From 4fa236b842ec6d0f19cfec5d69f845a8c4f226e2 Mon Sep 17 00:00:00 2001 From: fbalicchia Date: Wed, 29 Oct 2025 09:08:24 +0100 Subject: [PATCH 001/121] manage aws profile Signed-off-by: fbalicchia --- crates/goose/src/providers/bedrock.rs | 43 ++++++++++++++++++--------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/crates/goose/src/providers/bedrock.rs b/crates/goose/src/providers/bedrock.rs index ff5300484316..e69934bd53cc 100644 --- a/crates/goose/src/providers/bedrock.rs +++ b/crates/goose/src/providers/bedrock.rs @@ -42,8 +42,6 @@ pub struct BedrockProvider { model: ModelConfig, #[serde(skip)] retry_config: RetryConfig, - #[serde(skip)] - name: String, } impl BedrockProvider { @@ -51,7 +49,7 @@ impl BedrockProvider { let config = crate::config::Config::global(); // Attempt to load config and secrets to get AWS_ prefixed keys - // to re-export them into the environment for aws_config::load_from_env() + // to re-export them into the environment for aws_config to use as fallback let set_aws_env_vars = |res: Result, _>| { if let Ok(map) = res { map.into_iter() @@ -64,14 +62,33 @@ impl BedrockProvider { set_aws_env_vars(config.load_values()); set_aws_env_vars(config.load_secrets()); - let sdk_config = aws_config::load_from_env().await; + // Use load_defaults() which supports AWS SSO, profiles, and environment variables + let mut loader = aws_config::defaults(aws_config::BehaviorVersion::latest()); + + // Check for AWS_PROFILE configuration + if let Ok(profile_name) = config.get_param::("AWS_PROFILE") { + if !profile_name.is_empty() { + loader = loader.profile_name(&profile_name); + } + } + + // Check for AWS_REGION configuration + if let Ok(region) = config.get_param::("AWS_REGION") { + if !region.is_empty() { + loader = loader.region(aws_config::Region::new(region)); + } + } - // validate credentials or return error back up + let sdk_config = loader.load().await; + + // Validate credentials or return error back up sdk_config .credentials_provider() - .unwrap() + .ok_or_else(|| anyhow::anyhow!("No AWS credentials provider configured"))? .provide_credentials() - .await?; + .await + .map_err(|e| anyhow::anyhow!("Failed to load AWS credentials: {}. Make sure to run 'aws sso login --profile ' if using SSO", e))?; + let client = Client::new(&sdk_config); let retry_config = Self::load_retry_config(config); @@ -80,7 +97,6 @@ impl BedrockProvider { client, model, retry_config, - name: Self::metadata().name, }) } @@ -179,18 +195,17 @@ impl Provider for BedrockProvider { ProviderMetadata::new( "aws_bedrock", "Amazon Bedrock", - "Run models through Amazon Bedrock. You may have to set 'AWS_' environment variables to configure authentication.", + "Run models through Amazon Bedrock. Supports AWS SSO profiles - run 'aws sso login --profile ' before using. Configure with AWS_PROFILE and AWS_REGION, or use environment variables/credentials.", BEDROCK_DEFAULT_MODEL, BEDROCK_KNOWN_MODELS.to_vec(), BEDROCK_DOC_LINK, - vec![ConfigKey::new("AWS_PROFILE", true, false, Some("default"))], + vec![ + ConfigKey::new("AWS_PROFILE", true, false, Some("default")), + ConfigKey::new("AWS_REGION", true, false, Some("us-east-1")), + ], ) } - fn get_name(&self) -> &str { - &self.name - } - fn retry_config(&self) -> RetryConfig { self.retry_config.clone() } From 875f96298ff7f04f3c1677da8a155187583090f5 Mon Sep 17 00:00:00 2001 From: Arya Pratap Singh Date: Wed, 29 Oct 2025 17:31:48 +0530 Subject: [PATCH 002/121] fix: corrected my name in data (#5414) Signed-off-by: Arya Pratap Singh Signed-off-by: fbalicchia --- documentation/src/pages/community/data/september-2025.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/pages/community/data/september-2025.json b/documentation/src/pages/community/data/september-2025.json index 29c90baa65c2..c4c99a5abd35 100644 --- a/documentation/src/pages/community/data/september-2025.json +++ b/documentation/src/pages/community/data/september-2025.json @@ -10,7 +10,7 @@ "handle": "sings-to-bees-on-wednesdays" }, { - "name": "Aryan Sharma", + "name": "Arya Pratap Singh", "handle": "ARYPROGRAMMER" }, { From e8276dc7333d406a3e87a0268b80ecb929f50806 Mon Sep 17 00:00:00 2001 From: M A Sai Adithyaa Date: Wed, 29 Oct 2025 19:25:39 +0530 Subject: [PATCH 003/121] feat(prompt): add audio summarizer prompt with ElevenLabs integration (#5437) Signed-off-by: saiadithyaa Signed-off-by: fbalicchia --- .../data/prompts/audio-summarizer.json | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 documentation/src/pages/prompt-library/data/prompts/audio-summarizer.json diff --git a/documentation/src/pages/prompt-library/data/prompts/audio-summarizer.json b/documentation/src/pages/prompt-library/data/prompts/audio-summarizer.json new file mode 100644 index 000000000000..dbb93c38d1b1 --- /dev/null +++ b/documentation/src/pages/prompt-library/data/prompts/audio-summarizer.json @@ -0,0 +1,23 @@ +{ + "id": "audio-summarizer", + "title": "Generate Audio Summary from Webpage", + "description": "Summarizes a webpage URL into bullet points and generates an MP3 audio file of the summary using ElevenLabs.", + "category": "productivity", + "job": "productivity", + "example_prompt": "Hey goose , summarize the article at https://en.wikipedia.org/wiki/Coronavirus into short bulletpoints. Then, take that summary and generate an audio file using the ElevenLabs MCP with the 'Rachel' voice.", + "example_result": "Based on the available content, here is a summarized version of the article about Coronavirus in bullet points:\n- Coronaviruses are a group of related viruses that cause diseases in mammals and birds.\n- In humans, coronaviruses can lead to respiratory tract infections, which can range from mild, like some cases of the common cold, to severe, such as SARS, MERS, and COVID-19.\n- The name \"coronavirus\" is derived from the Latin word \"corona,\" meaning \"crown\" or \"halo,\" which refers to the characteristic appearance of the virus particles.\n- Coronaviruses have a genome composed of a single strand of RNA and have characteristic surface spike proteins.\n- They are classified within the family Coronaviridae and the subfamily Orthocoronavirinae.\n- These viruses are further grouped into four genera: Alphacoronavirus, Betacoronavirus, Gammacoronavirus, and Deltacoronavirus.\n- Transmission between humans typically occurs through respiratory droplets, especially from coughs and sneezes.\n- Major outbreaks in recent history include the Severe Acute Respiratory Syndrome (SARS) in 2003, Middle East Respiratory Syndrome (MERS) in 2012, and COVID-19 starting in late 2019.\n\nNow, let's use the above summary to generate an audio file using the ElevenLabs MCP and the 'Rachel' voice. The audio file has been successfully generated using the 'Rachel' voice. You can find the file saved on your desktop under the name tts_Coron_20251029_145539.mp3.", + "extensions": [ + { + "name": "ElevenLabs MCP", + "description": "Generates high-quality, human-sounding text-to-speech audio and AI voices.", + "is_builtin": true, + "environmentVariables": [ + { + "name": "ELEVENLABS_API_KEY", + "value": "", + "required": true + } + ] + } + ] +} From db931e1c5fb050aa43d15a3551da297b433ff26b Mon Sep 17 00:00:00 2001 From: Dakshata Mishra <22-783@apsdhaulakuan.onmicrosoft.com> Date: Wed, 29 Oct 2025 19:37:49 +0530 Subject: [PATCH 004/121] Goose context7 video (#5426) Signed-off-by: Dakshata Mishra Signed-off-by: Dakshata <22-783@apsdhaulakuan.onmicrosoft.com> Signed-off-by: fbalicchia --- .../src/pages/community/data/community-content.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index e3de107ba447..12200b369f44 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -138,6 +138,18 @@ "submittedDate": "2025-10-26", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Goose with Context7 MCP", + "author": { + "name": "Dakshata Mishra", + "handle": "the-matrixneo" + }, + "type": "video", + "url": "https://www.youtube.com/shorts/EmLcx5gKHsE", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] } \ No newline at end of file From 649117c04f49cd15b8bacfa0d6b168c77f6f50dd Mon Sep 17 00:00:00 2001 From: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:30:31 -0400 Subject: [PATCH 005/121] Reduce LLMism comments (#5440) Signed-off-by: fbalicchia --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index a4d3d3d361af..6f10190d2d7d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -82,6 +82,7 @@ Never: Edit ui/desktop/openapi.json manually Never: Edit Cargo.toml use cargo add Never: Skip cargo fmt Never: Merge without ./scripts/clippy-lint.sh +Never: Comment self-evident operations (`// Initialize`, `// Return result`), getters/setters, constructors, or standard Rust idioms ## Entry Points - CLI: crates/goose-cli/src/main.rs From d2256abc92e1abaaa3793ca23dcce6ce2c58a197 Mon Sep 17 00:00:00 2001 From: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:59:20 -0400 Subject: [PATCH 006/121] Remove subagent instructions from system prompt (#5441) Signed-off-by: fbalicchia --- ...oose__agents__prompt_manager__tests__basic.snap | 12 ------------ ...ents__prompt_manager__tests__one_extension.snap | 12 ------------ ...ents__prompt_manager__tests__typical_setup.snap | 12 ------------ crates/goose/src/prompts/system.md | 14 -------------- 4 files changed, 50 deletions(-) diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap index 4acf9b188401..c88109a7b2e3 100644 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__basic.snap @@ -30,18 +30,6 @@ No extensions are defined. You should let the user know that they should add ext -# sub agents - -Execute self contained tasks where step-by-step visibility is not important through subagents. - -- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, - verification, exploration -- Parallel subagents for multiple operations, single subagents for independent work -- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) -- Provide all needed context — subagents cannot see your context -- Use extension filters to limit resource access -- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - # Response Guidelines - Use Markdown formatting for all responses. diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap index bb5479e3e553..18656ece918c 100644 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__one_extension.snap @@ -54,18 +54,6 @@ how to use this extension - list_resources -# sub agents - -Execute self contained tasks where step-by-step visibility is not important through subagents. - -- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, - verification, exploration -- Parallel subagents for multiple operations, single subagents for independent work -- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) -- Provide all needed context — subagents cannot see your context -- Use extension filters to limit resource access -- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - # Response Guidelines - Use Markdown formatting for all responses. diff --git a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__typical_setup.snap b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__typical_setup.snap index c28476fe5c38..1c7af49c5634 100644 --- a/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__typical_setup.snap +++ b/crates/goose/src/agents/snapshots/goose__agents__prompt_manager__tests__typical_setup.snap @@ -68,18 +68,6 @@ Explain that minimizing extensions helps with the recall of the correct tools to - list_resources -# sub agents - -Execute self contained tasks where step-by-step visibility is not important through subagents. - -- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, - verification, exploration -- Parallel subagents for multiple operations, single subagents for independent work -- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) -- Provide all needed context — subagents cannot see your context -- Use extension filters to limit resource access -- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - # Response Guidelines - Use Markdown formatting for all responses. diff --git a/crates/goose/src/prompts/system.md b/crates/goose/src/prompts/system.md index 1501f28623b7..55a9e6f59562 100644 --- a/crates/goose/src/prompts/system.md +++ b/crates/goose/src/prompts/system.md @@ -59,20 +59,6 @@ Explain that minimizing extensions helps with the recall of the correct tools to {% endif %} {{tool_selection_strategy}} -{% if enable_subagents %} - -# sub agents - -Execute self contained tasks where step-by-step visibility is not important through subagents. - -- Delegate via `dynamic_task__create_task` for: result-only operations, parallelizable work, multi-part requests, - verification, exploration -- Parallel subagents for multiple operations, single subagents for independent work -- Explore solutions in parallel — launch parallel subagents with different approaches (if non-interfering) -- Provide all needed context — subagents cannot see your context -- Use extension filters to limit resource access -- Use return_last_only when only a summary or simple answer is required — inform subagent of this choice. - {% endif %} # Response Guidelines From 28af1fecec499c6f13d3e807420f8a697972c4e2 Mon Sep 17 00:00:00 2001 From: Mohammad Shahzeb Alam Date: Wed, 29 Oct 2025 20:33:47 +0530 Subject: [PATCH 007/121] Docs quick tip slot4 (#4948) Signed-off-by: Mohammad Shahzeb Alam Co-authored-by: taniandjerry <126204004+taniandjerry@users.noreply.github.com> Signed-off-by: fbalicchia --- documentation/docs/guides/tips.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/documentation/docs/guides/tips.md b/documentation/docs/guides/tips.md index 5b4c06bc46f3..22622f05291e 100644 --- a/documentation/docs/guides/tips.md +++ b/documentation/docs/guides/tips.md @@ -47,8 +47,11 @@ You don’t need to get it right the first time. Iterating on prompts and tools ### Keep Goose updated Regularly [update](/docs/guides/updating-goose) Goose to benefit from the latest features, bug fixes, and performance improvements. -### Keep Recipes Idempotent -Write "[recipes](/docs/guides/recipes/session-recipes)" so they can run multiple times without causing unintended side effects. This ensures safer re-runs and easier debugging in automated workflows. +### Pair Two Models to Save Money +Use [lead/worker model](/docs/tutorials/lead-worker/) to have goose use a "lead" model for early planning before handing the task to a lower-cost "worker" model for execution. -### Add Clear Logging -Include informative log messages in your recipes for each major step. It makes debugging and troubleshooting much faster when something fails. +### Make Recipes Safe to Re-run +Write [recipes](/docs/guides/recipes/session-recipes) that check your current state before acting, so they can be run multiple times without causing any errors or duplication. + +### Add Logging to Recipes +Inlcude informative log messages in your recipes for each major step to make debugging and troubleshooting easier should something fail. From 33af5dde5414bc115462d9fb4e26b41a304254f4 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Wed, 29 Oct 2025 11:16:06 -0400 Subject: [PATCH 008/121] Agent extension api (#5281) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose-server/src/openapi.rs | 4 + crates/goose-server/src/routes/agent.rs | 97 +++++ crates/goose-server/src/routes/errors.rs | 15 + crates/goose-server/src/routes/extension.rs | 139 ------- crates/goose-server/src/routes/mod.rs | 3 +- crates/goose-server/src/state.rs | 1 - ui/desktop/openapi.json | 108 +++++ ui/desktop/src/api/sdk.gen.ts | 24 +- ui/desktop/src/api/types.gen.ts | 72 ++++ ui/desktop/src/components/ConfigContext.tsx | 5 - .../settings/extensions/agent-api.test.ts | 376 ------------------ .../settings/extensions/agent-api.ts | 234 +++-------- .../extensions/extension-manager.test.ts | 188 +-------- .../settings/extensions/extension-manager.ts | 34 +- .../subcomponents/ExtensionList.tsx | 8 +- .../settings/extensions/utils.test.ts | 50 --- .../components/settings/extensions/utils.ts | 35 -- ui/desktop/src/hooks/useWhisper.ts | 2 +- ui/desktop/src/sharedSessions.ts | 2 +- .../{jsonUtils.ts => conversionUtils.ts} | 10 + ui/desktop/src/utils/costDatabase.ts | 2 +- ui/desktop/src/utils/githubUpdater.ts | 2 +- 22 files changed, 427 insertions(+), 984 deletions(-) delete mode 100644 crates/goose-server/src/routes/extension.rs delete mode 100644 ui/desktop/src/components/settings/extensions/agent-api.test.ts rename ui/desktop/src/utils/{jsonUtils.ts => conversionUtils.ts} (51%) diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index f84a92a64247..85f20ec71a96 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -348,6 +348,8 @@ derive_utoipa!(Icon as IconSchema); super::routes::agent::resume_agent, super::routes::agent::get_tools, super::routes::agent::update_from_session, + super::routes::agent::agent_add_extension, + super::routes::agent::agent_remove_extension, super::routes::agent::update_agent_provider, super::routes::agent::update_router_tool_selector, super::routes::reply::confirm_permission, @@ -486,6 +488,8 @@ derive_utoipa!(Icon as IconSchema); super::routes::agent::StartAgentRequest, super::routes::agent::ResumeAgentRequest, super::routes::agent::UpdateFromSessionRequest, + super::routes::agent::AddExtensionRequest, + super::routes::agent::RemoveExtensionRequest, super::routes::setup::SetupResponse, )) )] diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index fb850895e97b..b16cea136058 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -11,6 +11,7 @@ use axum::{ }; use goose::config::PermissionManager; +use goose::agents::ExtensionConfig; use goose::config::Config; use goose::model::ModelConfig; use goose::prompt_template::render_global_file; @@ -70,6 +71,18 @@ pub struct ResumeAgentRequest { load_model_and_extensions: bool, } +#[derive(Deserialize, utoipa::ToSchema)] +pub struct AddExtensionRequest { + session_id: String, + config: ExtensionConfig, +} + +#[derive(Deserialize, utoipa::ToSchema)] +pub struct RemoveExtensionRequest { + name: String, + session_id: String, +} + #[utoipa::path( post, path = "/agent/start", @@ -451,6 +464,88 @@ async fn update_router_tool_selector( )) } +#[utoipa::path( + post, + path = "/agent/add_extension", + request_body = AddExtensionRequest, + responses( + (status = 200, description = "Extension added", body = String), + (status = 401, description = "Unauthorized - invalid secret key"), + (status = 424, description = "Agent not initialized"), + (status = 500, description = "Internal server error") + ) +)] +async fn agent_add_extension( + State(state): State>, + Json(request): Json, +) -> Result { + // If this is a Stdio extension that uses npx, check for Node.js installation + #[cfg(target_os = "windows")] + if let ExtensionConfig::Stdio { cmd, .. } = &request.config { + if cmd.ends_with("npx.cmd") || cmd.ends_with("npx") { + let node_exists = std::path::Path::new(r"C:\Program Files\nodejs\node.exe").exists() + || std::path::Path::new(r"C:\Program Files (x86)\nodejs\node.exe").exists(); + + if !node_exists { + let cmd_path = std::path::Path::new(&cmd); + let script_dir = cmd_path.parent().ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; + let install_script = script_dir.join("install-node.cmd"); + + if install_script.exists() { + eprintln!("Installing Node.js..."); + let output = std::process::Command::new(&install_script) + .arg("https://nodejs.org/dist/v23.10.0/node-v23.10.0-x64.msi") + .output() + .map_err(|e| { + eprintln!("Failed to run Node.js installer: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + if !output.status.success() { + return Err(ErrorResponse::internal(format!( + "Failed to install Node.js: {}", + String::from_utf8_lossy(&output.stderr) + ))); + } + eprintln!("Node.js installation completed"); + } else { + return Err(ErrorResponse::internal(format!( + "Node.js not detected and no installer script not found at: {}", + install_script.display() + ))); + } + } + } + } + + let agent = state.get_agent(request.session_id).await?; + agent + .add_extension(request.config) + .await + .map_err(|e| ErrorResponse::internal(format!("Failed to add extension: {}", e)))?; + Ok(StatusCode::OK) +} + +#[utoipa::path( + post, + path = "/agent/remove_extension", + request_body = RemoveExtensionRequest, + responses( + (status = 200, description = "Extension removed", body = String), + (status = 401, description = "Unauthorized - invalid secret key"), + (status = 424, description = "Agent not initialized"), + (status = 500, description = "Internal server error") + ) +)] +async fn agent_remove_extension( + State(state): State>, + Json(request): Json, +) -> Result { + let agent = state.get_agent(request.session_id).await?; + agent.remove_extension(&request.name).await?; + Ok(StatusCode::OK) +} + pub fn routes(state: Arc) -> Router { Router::new() .route("/agent/start", post(start_agent)) @@ -462,5 +557,7 @@ pub fn routes(state: Arc) -> Router { post(update_router_tool_selector), ) .route("/agent/update_from_session", post(update_from_session)) + .route("/agent/add_extension", post(agent_add_extension)) + .route("/agent/remove_extension", post(agent_remove_extension)) .with_state(state) } diff --git a/crates/goose-server/src/routes/errors.rs b/crates/goose-server/src/routes/errors.rs index 894f13e426e9..c265482d055e 100644 --- a/crates/goose-server/src/routes/errors.rs +++ b/crates/goose-server/src/routes/errors.rs @@ -13,6 +13,15 @@ pub struct ErrorResponse { pub status: StatusCode, } +impl ErrorResponse { + pub(crate) fn internal(message: impl Into) -> Self { + Self { + message: message.into(), + status: StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + impl IntoResponse for ErrorResponse { fn into_response(self) -> Response { let body = Json(serde_json::json!({ @@ -22,3 +31,9 @@ impl IntoResponse for ErrorResponse { (self.status, body).into_response() } } + +impl From for ErrorResponse { + fn from(err: anyhow::Error) -> Self { + Self::internal(err.to_string()) + } +} diff --git a/crates/goose-server/src/routes/extension.rs b/crates/goose-server/src/routes/extension.rs deleted file mode 100644 index 5fec1a3599e7..000000000000 --- a/crates/goose-server/src/routes/extension.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::sync::Arc; - -use crate::state::AppState; -use axum::{extract::State, routing::post, Json, Router}; -use goose::agents::ExtensionConfig; -use http::StatusCode; -use serde::{Deserialize, Serialize}; -use tracing; - -#[derive(Serialize)] -struct ExtensionResponse { - error: bool, - message: Option, -} - -#[derive(Deserialize)] -struct AddExtensionRequest { - session_id: String, - #[serde(flatten)] - config: ExtensionConfig, -} - -async fn add_extension( - State(state): State>, - Json(request): Json, -) -> Result, StatusCode> { - // Log the request for debugging - tracing::info!( - "Received extension request for session: {}", - request.session_id - ); - - // If this is a Stdio extension that uses npx, check for Node.js installation - #[cfg(target_os = "windows")] - if let ExtensionConfig::Stdio { cmd, .. } = &request.config { - if cmd.ends_with("npx.cmd") || cmd.ends_with("npx") { - // Check if Node.js is installed in standard locations - let node_exists = std::path::Path::new(r"C:\Program Files\nodejs\node.exe").exists() - || std::path::Path::new(r"C:\Program Files (x86)\nodejs\node.exe").exists(); - - if !node_exists { - // Get the directory containing npx.cmd - let cmd_path = std::path::Path::new(&cmd); - let script_dir = cmd_path.parent().ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; - - // Run the Node.js installer script - let install_script = script_dir.join("install-node.cmd"); - - if install_script.exists() { - eprintln!("Installing Node.js..."); - let output = std::process::Command::new(&install_script) - .arg("https://nodejs.org/dist/v23.10.0/node-v23.10.0-x64.msi") - .output() - .map_err(|e| { - eprintln!("Failed to run Node.js installer: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - if !output.status.success() { - eprintln!( - "Failed to install Node.js: {}", - String::from_utf8_lossy(&output.stderr) - ); - return Ok(Json(ExtensionResponse { - error: true, - message: Some(format!( - "Failed to install Node.js: {}", - String::from_utf8_lossy(&output.stderr) - )), - })); - } - eprintln!("Node.js installation completed"); - } else { - eprintln!( - "Node.js installer script not found at: {}", - install_script.display() - ); - return Ok(Json(ExtensionResponse { - error: true, - message: Some("Node.js installer script not found".to_string()), - })); - } - } - } - } - - let agent = state.get_agent_for_route(request.session_id).await?; - let response = agent.add_extension(request.config).await; - - // Respond with the result. - match response { - Ok(_) => Ok(Json(ExtensionResponse { - error: false, - message: None, - })), - Err(e) => { - eprintln!("Failed to add extension configuration: {:?}", e); - Ok(Json(ExtensionResponse { - error: true, - message: Some(format!( - "Failed to add extension configuration, error: {:?}", - e - )), - })) - } - } -} - -#[derive(Deserialize)] -struct RemoveExtensionRequest { - name: String, - session_id: String, -} - -/// Handler for removing an extension by name -async fn remove_extension( - State(state): State>, - Json(request): Json, -) -> Result, StatusCode> { - let agent = state.get_agent_for_route(request.session_id).await?; - - match agent.remove_extension(&request.name).await { - Ok(_) => Ok(Json(ExtensionResponse { - error: false, - message: None, - })), - Err(e) => Ok(Json(ExtensionResponse { - error: true, - message: Some(format!("Failed to remove extension: {:?}", e)), - })), - } -} - -pub fn routes(state: Arc) -> Router { - Router::new() - .route("/extensions/add", post(add_extension)) - .route("/extensions/remove", post(remove_extension)) - .with_state(state) -} diff --git a/crates/goose-server/src/routes/mod.rs b/crates/goose-server/src/routes/mod.rs index 7deafd6b7b2d..9ca3799e5d89 100644 --- a/crates/goose-server/src/routes/mod.rs +++ b/crates/goose-server/src/routes/mod.rs @@ -2,7 +2,6 @@ pub mod agent; pub mod audio; pub mod config_management; pub mod errors; -pub mod extension; pub mod recipe; pub mod recipe_utils; pub mod reply; @@ -11,6 +10,7 @@ pub mod session; pub mod setup; pub mod status; pub mod utils; + use std::sync::Arc; use axum::Router; @@ -22,7 +22,6 @@ pub fn configure(state: Arc) -> Router { .merge(reply::routes(state.clone())) .merge(agent::routes(state.clone())) .merge(audio::routes(state.clone())) - .merge(extension::routes(state.clone())) .merge(config_management::routes(state.clone())) .merge(recipe::routes(state.clone())) .merge(session::routes(state.clone())) diff --git a/crates/goose-server/src/state.rs b/crates/goose-server/src/state.rs index b8b916bf9102..274da82939b3 100644 --- a/crates/goose-server/src/state.rs +++ b/crates/goose-server/src/state.rs @@ -49,7 +49,6 @@ impl AppState { self.agent_manager.get_or_create_agent(session_id).await } - /// Get agent for route handlers - always uses Interactive mode and converts any error to 500 pub async fn get_agent_for_route( &self, session_id: String, diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 83f3a073db9f..8fcd96b9553d 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -13,6 +13,84 @@ "version": "1.11.0" }, "paths": { + "/agent/add_extension": { + "post": { + "tags": [ + "super::routes::agent" + ], + "operationId": "agent_add_extension", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddExtensionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Extension added", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid secret key" + }, + "424": { + "description": "Agent not initialized" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/agent/remove_extension": { + "post": { + "tags": [ + "super::routes::agent" + ], + "operationId": "agent_remove_extension", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveExtensionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Extension removed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid secret key" + }, + "424": { + "description": "Agent not initialized" + }, + "500": { + "description": "Internal server error" + } + } + } + }, "/agent/resume": { "post": { "tags": [ @@ -1989,6 +2067,21 @@ }, "components": { "schemas": { + "AddExtensionRequest": { + "type": "object", + "required": [ + "session_id", + "config" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/ExtensionConfig" + }, + "session_id": { + "type": "string" + } + } + }, "Annotations": { "type": "object", "properties": { @@ -3812,6 +3905,21 @@ } } }, + "RemoveExtensionRequest": { + "type": "object", + "required": [ + "name", + "session_id" + ], + "properties": { + "name": { + "type": "string" + }, + "session_id": { + "type": "string" + } + } + }, "ResourceContents": { "anyOf": [ { diff --git a/ui/desktop/src/api/sdk.gen.ts b/ui/desktop/src/api/sdk.gen.ts index ebcf9ab38b77..7f65f47dc5a7 100644 --- a/ui/desktop/src/api/sdk.gen.ts +++ b/ui/desktop/src/api/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, ConfirmPermissionData, ConfirmPermissionErrors, ConfirmPermissionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetToolsData, GetToolsErrors, GetToolsResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StatusData, StatusResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateRouterToolSelectorData, UpdateRouterToolSelectorErrors, UpdateRouterToolSelectorResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen'; +import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, ConfirmPermissionData, ConfirmPermissionErrors, ConfirmPermissionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetToolsData, GetToolsErrors, GetToolsResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StatusData, StatusResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateRouterToolSelectorData, UpdateRouterToolSelectorErrors, UpdateRouterToolSelectorResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen'; export type Options = Options2 & { /** @@ -18,6 +18,28 @@ export type Options; }; +export const agentAddExtension = (options: Options) => { + return (options.client ?? client).post({ + url: '/agent/add_extension', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } + }); +}; + +export const agentRemoveExtension = (options: Options) => { + return (options.client ?? client).post({ + url: '/agent/remove_extension', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } + }); +}; + export const resumeAgent = (options: Options) => { return (options.client ?? client).post({ url: '/agent/resume', diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 6c4eb54cee6c..d2d9948f4225 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -4,6 +4,11 @@ export type ClientOptions = { baseUrl: `${string}://${string}` | (string & {}); }; +export type AddExtensionRequest = { + config: ExtensionConfig; + session_id: string; +}; + export type Annotations = { audience?: Array; lastModified?: string; @@ -578,6 +583,11 @@ export type RedactedThinkingContent = { data: string; }; +export type RemoveExtensionRequest = { + name: string; + session_id: string; +}; + export type ResourceContents = { _meta?: { [key: string]: unknown; @@ -896,6 +906,68 @@ export type UpsertPermissionsQuery = { tool_permissions: Array; }; +export type AgentAddExtensionData = { + body: AddExtensionRequest; + path?: never; + query?: never; + url: '/agent/add_extension'; +}; + +export type AgentAddExtensionErrors = { + /** + * Unauthorized - invalid secret key + */ + 401: unknown; + /** + * Agent not initialized + */ + 424: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type AgentAddExtensionResponses = { + /** + * Extension added + */ + 200: string; +}; + +export type AgentAddExtensionResponse = AgentAddExtensionResponses[keyof AgentAddExtensionResponses]; + +export type AgentRemoveExtensionData = { + body: RemoveExtensionRequest; + path?: never; + query?: never; + url: '/agent/remove_extension'; +}; + +export type AgentRemoveExtensionErrors = { + /** + * Unauthorized - invalid secret key + */ + 401: unknown; + /** + * Agent not initialized + */ + 424: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type AgentRemoveExtensionResponses = { + /** + * Extension removed + */ + 200: string; +}; + +export type AgentRemoveExtensionResponse = AgentRemoveExtensionResponses[keyof AgentRemoveExtensionResponses]; + export type ResumeAgentData = { body: ResumeAgentRequest; path?: never; diff --git a/ui/desktop/src/components/ConfigContext.tsx b/ui/desktop/src/components/ConfigContext.tsx index 8bda007082de..ab0618a58e6f 100644 --- a/ui/desktop/src/components/ConfigContext.tsx +++ b/ui/desktop/src/components/ConfigContext.tsx @@ -19,7 +19,6 @@ import type { ExtensionQuery, ExtensionConfig, } from '../api'; -import { removeShims } from './settings/extensions/utils'; export type { ExtensionConfig } from '../api/types.gen'; @@ -122,10 +121,6 @@ export const ConfigProvider: React.FC = ({ children }) => { const addExtension = useCallback( async (name: string, config: ExtensionConfig, enabled: boolean) => { - // remove shims if present - if (config.type === 'stdio') { - config.cmd = removeShims(config.cmd); - } const query: ExtensionQuery = { name, config, enabled }; await apiAddExtension({ body: query, diff --git a/ui/desktop/src/components/settings/extensions/agent-api.test.ts b/ui/desktop/src/components/settings/extensions/agent-api.test.ts deleted file mode 100644 index b5e943b0cc82..000000000000 --- a/ui/desktop/src/components/settings/extensions/agent-api.test.ts +++ /dev/null @@ -1,376 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { extensionApiCall, addToAgent, removeFromAgent, sanitizeName } from './agent-api'; -import * as config from '../../../config'; -import * as toasts from '../../../toasts'; -import { ExtensionConfig } from '../../../api/types.gen'; - -// Mock dependencies -vi.mock('../../../config'); -vi.mock('../../../toasts'); -vi.mock('./utils'); - -const mockGetApiUrl = vi.mocked(config.getApiUrl); -const mockToastService = vi.mocked(toasts.toastService); - -// Mock window.electron -const mockElectron = { - getSecretKey: vi.fn(), -}; - -Object.defineProperty(window, 'electron', { - value: mockElectron, - writable: true, -}); - -// Mock fetch -const mockFetch = vi.fn(); -(globalThis as typeof globalThis & { fetch: typeof mockFetch }).fetch = mockFetch; - -describe('Agent API', () => { - beforeEach(() => { - vi.clearAllMocks(); - mockGetApiUrl.mockImplementation((path: string) => `http://localhost:8080${path}`); - mockElectron.getSecretKey.mockResolvedValue('secret-key'); - mockToastService.configure = vi.fn(); - mockToastService.loading = vi.fn().mockReturnValue('toast-id'); - mockToastService.success = vi.fn(); - mockToastService.error = vi.fn(); - mockToastService.dismiss = vi.fn(); - }); - - describe('sanitizeName', () => { - it('should sanitize extension names correctly', () => { - expect(sanitizeName('Test Extension')).toBe('testextension'); - expect(sanitizeName('My-Extension_Name')).toBe('myextensionname'); - expect(sanitizeName('UPPERCASE')).toBe('uppercase'); - }); - }); - - describe('extensionApiCall', () => { - const mockExtensionConfig: ExtensionConfig = { - type: 'stdio', - description: 'description', - name: 'test-extension', - cmd: 'python', - args: ['script.py'], - }; - - it('should make successful API call for adding extension', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - const response = await extensionApiCall( - '/extensions/add', - mockExtensionConfig, - {}, - 'test-session' - ); - - expect(mockFetch).toHaveBeenCalledWith('http://localhost:8080/extensions/add', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': 'secret-key', - }, - body: JSON.stringify({ ...mockExtensionConfig, session_id: 'test-session' }), - }); - - expect(mockToastService.loading).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Activating test-extension extension...', - }); - - expect(mockToastService.success).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Successfully activated extension', - }); - - expect(response).toBe(mockResponse); - }); - - it('should make successful API call for removing extension', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - const response = await extensionApiCall( - '/extensions/remove', - 'test-extension', - {}, - 'test-session' - ); - - expect(mockFetch).toHaveBeenCalledWith('http://localhost:8080/extensions/remove', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': 'secret-key', - }, - body: JSON.stringify({ name: 'test-extension', session_id: 'test-session' }), - }); - - expect(mockToastService.loading).not.toHaveBeenCalled(); // No loading toast for removal - expect(mockToastService.success).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Successfully deactivated extension', - }); - - expect(response).toBe(mockResponse); - }); - - it('should handle HTTP error responses', async () => { - const mockResponse = { - ok: false, - status: 500, - statusText: 'Internal Server Error', - }; - mockFetch.mockResolvedValue(mockResponse); - - await expect( - extensionApiCall('/extensions/add', mockExtensionConfig, {}, 'test-session') - ).rejects.toThrow('Server returned 500: Internal Server Error'); - - expect(mockToastService.error).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Failed to add test-extension extension: Server returned 500: Internal Server Error', - traceback: 'Server returned 500: Internal Server Error', - }); - }); - - it('should handle 428 error specially', async () => { - const mockResponse = { - ok: false, - status: 428, - statusText: 'Precondition Required', - }; - mockFetch.mockResolvedValue(mockResponse); - - await expect( - extensionApiCall('/extensions/add', mockExtensionConfig, {}, 'test-session') - ).rejects.toThrow('Agent is not initialized. Please initialize the agent first.'); - - expect(mockToastService.error).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Failed to add extension. Goose Agent was still starting up. Please try again.', - traceback: 'Server returned 428: Precondition Required', - }); - }); - - it('should handle API error responses', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": true, "message": "Extension not found"}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - await expect( - extensionApiCall('/extensions/remove', 'test-extension', {}, 'test-session') - ).rejects.toThrow('Error deactivating extension: Extension not found'); - - expect(mockToastService.error).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Error deactivating extension: Extension not found', - traceback: 'Error deactivating extension: Extension not found', - }); - }); - - it('should handle JSON parse errors', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('invalid json'), - }; - mockFetch.mockResolvedValue(mockResponse); - - const response = await extensionApiCall( - '/extensions/add', - mockExtensionConfig, - {}, - 'test-session' - ); - - expect(mockToastService.success).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Successfully activated extension', - }); - - expect(response).toBe(mockResponse); - }); - - it('should handle network errors', async () => { - const networkError = new Error('Network error'); - mockFetch.mockRejectedValue(networkError); - - await expect( - extensionApiCall('/extensions/add', mockExtensionConfig, {}, 'test-session') - ).rejects.toThrow('Network error'); - - expect(mockToastService.error).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Network error', - traceback: 'Network error', - }); - }); - - it('should configure toast service with options', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - await extensionApiCall( - '/extensions/add', - mockExtensionConfig, - { silent: true }, - 'test-session' - ); - - expect(mockToastService.configure).toHaveBeenCalledWith({ silent: true }); - }); - }); - - describe('addToAgent', () => { - const mockExtensionConfig: ExtensionConfig = { - type: 'stdio', - name: 'Test Extension', - description: 'Test description', - cmd: 'python', - args: ['script.py'], - }; - - it('should add stdio extension to agent with shim replacement', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - // Mock replaceWithShims - const { replaceWithShims } = await import('./utils'); - vi.mocked(replaceWithShims).mockResolvedValue('/path/to/python'); - - await addToAgent(mockExtensionConfig, {}, 'test-session'); - - expect(mockFetch).toHaveBeenCalledWith('http://localhost:8080/extensions/add', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': 'secret-key', - }, - body: JSON.stringify({ - ...mockExtensionConfig, - name: 'testextension', - cmd: '/path/to/python', - session_id: 'test-session', - }), - }); - }); - - it('should handle 428 error with enhanced message', async () => { - const mockResponse = { - ok: false, - status: 428, - statusText: 'Precondition Required', - }; - mockFetch.mockResolvedValue(mockResponse); - - await expect(addToAgent(mockExtensionConfig, {}, 'test-session')).rejects.toThrow( - 'Agent is not initialized. Please initialize the agent first.' - ); - }); - - it('should add non-stdio extension without shim replacement', async () => { - const sseConfig: ExtensionConfig = { - type: 'sse', - name: 'SSE Extension', - description: 'Test description', - uri: 'http://localhost:8080/events', - }; - - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - await addToAgent(sseConfig, {}, 'test-session'); - - expect(mockFetch).toHaveBeenCalledWith('http://localhost:8080/extensions/add', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': 'secret-key', - }, - body: JSON.stringify({ - ...sseConfig, - name: 'sseextension', - session_id: 'test-session', - }), - }); - }); - - it('should not mutate the original extension config', async () => { - const originalConfig: ExtensionConfig = { - type: 'stdio', - name: 'Extension Manager', - description: 'Test description', - cmd: 'python', - args: ['script.py'], - }; - - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - const { replaceWithShims } = await import('./utils'); - vi.mocked(replaceWithShims).mockResolvedValue('/path/to/shim'); - - await addToAgent(originalConfig, {}, 'test-session'); - - // Verify the original config was not mutated - expect(originalConfig.name).toBe('Extension Manager'); - expect(originalConfig.cmd).toBe('python'); - }); - }); - - describe('removeFromAgent', () => { - it('should remove extension from agent', async () => { - const mockResponse = { - ok: true, - text: vi.fn().mockResolvedValue('{"error": false}'), - }; - mockFetch.mockResolvedValue(mockResponse); - - await removeFromAgent('Test Extension', {}, 'test-session'); - - expect(mockFetch).toHaveBeenCalledWith('http://localhost:8080/extensions/remove', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': 'secret-key', - }, - body: JSON.stringify({ name: 'testextension', session_id: 'test-session' }), - }); - }); - - it('should handle removal errors', async () => { - const mockResponse = { - ok: false, - status: 404, - statusText: 'Not Found', - }; - mockFetch.mockResolvedValue(mockResponse); - - await expect(removeFromAgent('Test Extension', {}, 'test-session')).rejects.toThrow(); - - expect(mockToastService.error).toHaveBeenCalled(); - }); - }); -}); diff --git a/ui/desktop/src/components/settings/extensions/agent-api.ts b/ui/desktop/src/components/settings/extensions/agent-api.ts index 7143779b78d0..01b6463c5a20 100644 --- a/ui/desktop/src/components/settings/extensions/agent-api.ts +++ b/ui/desktop/src/components/settings/extensions/agent-api.ts @@ -1,200 +1,82 @@ -import { ExtensionConfig } from '../../../api/types.gen'; -import { getApiUrl } from '../../../config'; -import { toastService, ToastServiceOptions } from '../../../toasts'; -import { replaceWithShims } from './utils'; +import { toastService } from '../../../toasts'; +import { agentAddExtension, ExtensionConfig, agentRemoveExtension } from '../../../api'; +import { errorMessage } from '../../../utils/conversionUtils'; -interface ApiResponse { - error?: boolean; - message?: string; -} - -/** - * Makes an API call to the extension endpoints - */ -export async function extensionApiCall( - endpoint: string, - payload: ExtensionConfig | string, - options: ToastServiceOptions & { isDelete?: boolean } = {}, - sessionId: string -): Promise { - // Configure toast notifications - toastService.configure(options); - - // Determine if we're activating, deactivating, or removing an extension - const isActivating = endpoint == '/extensions/add'; - const isRemoving = options.isDelete === true; - - const action = { - type: isActivating ? 'activating' : isRemoving ? 'removing' : 'deactivating', - verb: isActivating ? 'Activating' : isRemoving ? 'Removing' : 'Deactivating', - pastTense: isActivating ? 'activated' : isRemoving ? 'removed' : 'deactivated', - presentTense: isActivating ? 'activate' : isRemoving ? 'remove' : 'deactivate', - }; - - // for adding the payload is an extensionConfig, for removing payload is just the name - const extensionName = isActivating ? (payload as ExtensionConfig).name : (payload as string); - let toastId; - - // Step 1: Show loading toast (only for activation of stdio) - if (isActivating && typeof payload === 'object' && payload.type === 'stdio') { - toastId = toastService.loading({ - title: extensionName, - msg: `${action.verb} ${extensionName} extension...`, - }); - } +export async function addToAgent( + extensionConfig: ExtensionConfig, + sessionId: string, + showToast: boolean +) { + const extensionName = extensionConfig.name; + let toastId = showToast + ? toastService.loading({ + title: extensionName, + msg: `adding ${extensionName} extension...`, + }) + : 0; try { - // Build the request body - let requestBody: ExtensionConfig | { name: string; session_id: string }; - if (typeof payload === 'object') { - // For adding extensions (ExtensionConfig) - requestBody = { ...payload, session_id: sessionId }; - } else { - // For removing extensions (just the name string) - requestBody = { name: payload, session_id: sessionId }; - } - - // Step 2: Make the API call - const response = await fetch(getApiUrl(endpoint), { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Secret-Key': await window.electron.getSecretKey(), - }, - body: JSON.stringify(requestBody), + await agentAddExtension({ + body: { session_id: sessionId, config: extensionConfig }, + throwOnError: true, }); - - // Step 3: Handle non-successful responses - if (!response.ok) { - return handleErrorResponse(response, extensionName, action, toastId); - } - - // Step 4: Parse response data - const data = await parseResponseData(response); - - // Step 5: Check for errors in the response data - if (data.error) { - const errorMessage = `Error ${action.type} extension: ${data.message || 'Unknown error'}`; + if (showToast) { toastService.dismiss(toastId); - // Rely on the global error catch to show the copyable error toast here - throw new Error(errorMessage); + toastService.success({ + title: extensionName, + msg: `Successfully added extension`, + }); } - - // Step 6: Success - dismiss loading toast and return - toastService.dismiss(toastId); - toastService.success({ - title: extensionName, - msg: `Successfully ${action.pastTense} extension`, - }); - return response; } catch (error) { - // Final catch-all error handler - toastService.dismiss(toastId); - const errorMessage = error instanceof Error ? error.message : String(error); - const msg = - errorMessage.length < 70 ? errorMessage : `Failed to ${action.presentTense} extension`; + if (showToast) { + toastService.dismiss(toastId); + } + const errMsg = errorMessage(error); + const msg = errMsg.length < 70 ? errMsg : `Failed to add extension`; toastService.error({ title: extensionName, msg: msg, - traceback: errorMessage, + traceback: errMsg, }); - console.error(`Error in extensionApiCall for ${extensionName}:`, error); throw error; } } -// Helper functions to separate concerns - -// Handles HTTP error responses -function handleErrorResponse( - response: Response, +export async function removeFromAgent( extensionName: string, - action: { type: string; verb: string }, - toastId: string | number | undefined -): never { - const errorMsg = `Server returned ${response.status}: ${response.statusText}`; - console.error(errorMsg); - - // Special case: Agent not initialized (status 428) - if (response.status === 428 && action.type === 'activating') { - toastService.dismiss(toastId); - toastService.error({ - title: extensionName, - msg: 'Failed to add extension. Goose Agent was still starting up. Please try again.', - traceback: errorMsg, - }); - throw new Error('Agent is not initialized. Please initialize the agent first.'); - } - - // General error case - const msg = `Failed to ${action.type === 'activating' ? 'add' : action.type === 'removing' ? 'remove' : 'deactivate'} ${extensionName} extension: ${errorMsg}`; - toastService.dismiss(toastId); - toastService.error({ - title: extensionName, - msg: msg, - traceback: errorMsg, - }); - throw new Error(msg); -} - -// Safely parses JSON response -async function parseResponseData(response: Response): Promise { - try { - const text = await response.text(); - return text ? JSON.parse(text) : { error: false }; - } catch (parseError) { - console.warn('Could not parse response as JSON, assuming success', parseError); - return { error: false }; - } -} - -/** - * Add an extension to the agent - */ -export async function addToAgent( - extension: ExtensionConfig, - options: ToastServiceOptions = {}, - sessionId: string -): Promise { - // Create a copy to avoid mutating the original extension object - const extensionCopy: ExtensionConfig = { ...extension }; + sessionId: string, + showToast: boolean +) { + let toastId = showToast + ? toastService.loading({ + title: extensionName, + msg: `Removing ${extensionName} extension...`, + }) + : 0; try { - if (extensionCopy.type === 'stdio') { - extensionCopy.cmd = await replaceWithShims(extensionCopy.cmd); + await agentRemoveExtension({ + body: { session_id: sessionId, name: extensionName }, + throwOnError: true, + }); + if (showToast) { + toastService.dismiss(toastId); + toastService.success({ + title: extensionName, + msg: `Successfully removed extension`, + }); } - - extensionCopy.name = sanitizeName(extensionCopy.name); - - return await extensionApiCall('/extensions/add', extensionCopy, options, sessionId); } catch (error) { - // Check if this is a 428 error and make the message more descriptive - if (error instanceof Error && error.message && error.message.includes('428')) { - const enhancedError = new Error( - 'Failed to add extension. Goose Agent was still starting up. Please try again.' - ); - console.error( - `Failed to add extension ${extensionCopy.name} to agent: ${enhancedError.message}` - ); - throw enhancedError; + if (showToast) { + toastService.dismiss(toastId); } - throw error; - } -} - -/** - * Remove an extension from the agent - */ -export async function removeFromAgent( - name: string, - options: ToastServiceOptions & { isDelete?: boolean } = {}, - sessionId: string -): Promise { - try { - return await extensionApiCall('/extensions/remove', sanitizeName(name), options, sessionId); - } catch (error) { - const action = options.isDelete ? 'remove' : 'deactivate'; - console.error(`Failed to ${action} extension ${name} from agent:`, error); + const errorMessage = error instanceof Error ? error.message : String(error); + const msg = errorMessage.length < 70 ? errorMessage : `Failed to remove extension`; + toastService.error({ + title: extensionName, + msg: msg, + traceback: errorMessage, + }); throw error; } } diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts index 7406d41485d2..db379e379b24 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts @@ -1,11 +1,5 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { - activateExtension, - addToAgentOnStartup, - updateExtension, - toggleExtension, - deleteExtension, -} from './extension-manager'; +import { addToAgentOnStartup, updateExtension, toggleExtension } from './extension-manager'; import * as agentApi from './agent-api'; import * as toasts from '../../../toasts'; @@ -38,70 +32,9 @@ describe('Extension Manager', () => { mockRemoveFromConfig.mockResolvedValue(undefined); }); - describe('activateExtension', () => { - it('should successfully activate extension', async () => { - mockAddToAgent.mockResolvedValue({} as Response); - - await activateExtension({ - addToConfig: mockAddToConfig, - sessionId: 'test-session', - extensionConfig: mockExtensionConfig, - }); - - expect(mockAddToAgent).toHaveBeenCalledWith( - mockExtensionConfig, - { silent: false }, - 'test-session' - ); - expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, true); - }); - - it('should add to config as disabled if agent fails', async () => { - const agentError = new Error('Agent failed'); - mockAddToAgent.mockRejectedValue(agentError); - - await expect( - activateExtension({ - addToConfig: mockAddToConfig, - sessionId: 'test-session', - extensionConfig: mockExtensionConfig, - }) - ).rejects.toThrow('Agent failed'); - - expect(mockAddToAgent).toHaveBeenCalledWith( - mockExtensionConfig, - { silent: false }, - 'test-session' - ); - expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, false); - }); - - it('should remove from agent if config fails', async () => { - const configError = new Error('Config failed'); - mockAddToAgent.mockResolvedValue({} as Response); - mockAddToConfig.mockRejectedValue(configError); - - await expect( - activateExtension({ - addToConfig: mockAddToConfig, - sessionId: 'test-session', - extensionConfig: mockExtensionConfig, - }) - ).rejects.toThrow('Config failed'); - - expect(mockAddToAgent).toHaveBeenCalledWith( - mockExtensionConfig, - { silent: false }, - 'test-session' - ); - expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, true); - expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', {}, 'test-session'); - }); - }); - describe('addToAgentOnStartup', () => { it('should successfully add extension on startup', async () => { - mockAddToAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); await addToAgentOnStartup({ addToConfig: mockAddToConfig, @@ -109,29 +42,20 @@ describe('Extension Manager', () => { extensionConfig: mockExtensionConfig, }); - expect(mockAddToAgent).toHaveBeenCalledWith( - mockExtensionConfig, - { silent: true }, - 'test-session' - ); + expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); expect(mockAddToConfig).not.toHaveBeenCalled(); }); it('should successfully add extension on startup with custom toast options', async () => { - mockAddToAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); await addToAgentOnStartup({ addToConfig: mockAddToConfig, sessionId: 'test-session', extensionConfig: mockExtensionConfig, - toastOptions: { silent: false }, }); - expect(mockAddToAgent).toHaveBeenCalledWith( - mockExtensionConfig, - { silent: false }, - 'test-session' - ); + expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); expect(mockAddToConfig).not.toHaveBeenCalled(); }); @@ -140,7 +64,7 @@ describe('Extension Manager', () => { mockAddToAgent .mockRejectedValueOnce(error428) .mockRejectedValueOnce(error428) - .mockResolvedValue({} as Response); + .mockResolvedValue(undefined); await addToAgentOnStartup({ addToConfig: mockAddToConfig, @@ -174,7 +98,7 @@ describe('Extension Manager', () => { describe('updateExtension', () => { it('should update extension without name change', async () => { - mockAddToAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); mockAddToConfig.mockResolvedValue(undefined); mockToastService.success = vi.fn(); @@ -187,11 +111,6 @@ describe('Extension Manager', () => { originalName: 'test-extension', }); - expect(mockAddToAgent).toHaveBeenCalledWith( - { ...mockExtensionConfig, name: 'test-extension' }, - { silent: true }, - 'test-session' - ); expect(mockAddToConfig).toHaveBeenCalledWith( 'test-extension', { ...mockExtensionConfig, name: 'test-extension' }, @@ -204,8 +123,8 @@ describe('Extension Manager', () => { }); it('should handle name change by removing old and adding new', async () => { - mockAddToAgent.mockResolvedValue({} as Response); - mockRemoveFromAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); + mockRemoveFromAgent.mockResolvedValue(undefined); mockRemoveFromConfig.mockResolvedValue(undefined); mockAddToConfig.mockResolvedValue(undefined); mockToastService.success = vi.fn(); @@ -219,16 +138,11 @@ describe('Extension Manager', () => { originalName: 'old-extension', }); - expect(mockRemoveFromAgent).toHaveBeenCalledWith( - 'old-extension', - { silent: true }, - 'test-session' - ); expect(mockRemoveFromConfig).toHaveBeenCalledWith('old-extension'); expect(mockAddToAgent).toHaveBeenCalledWith( { ...mockExtensionConfig, name: 'new-extension' }, - { silent: true }, - 'test-session' + 'test-session', + false ); expect(mockAddToConfig).toHaveBeenCalledWith( 'new-extension', @@ -265,7 +179,7 @@ describe('Extension Manager', () => { describe('toggleExtension', () => { it('should toggle extension on successfully', async () => { - mockAddToAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); mockAddToConfig.mockResolvedValue(undefined); await toggleExtension({ @@ -275,12 +189,12 @@ describe('Extension Manager', () => { sessionId: 'test-session', }); - expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, {}, 'test-session'); + expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, true); }); it('should toggle extension off successfully', async () => { - mockRemoveFromAgent.mockResolvedValue({} as Response); + mockRemoveFromAgent.mockResolvedValue(undefined); mockAddToConfig.mockResolvedValue(undefined); await toggleExtension({ @@ -290,7 +204,7 @@ describe('Extension Manager', () => { sessionId: 'test-session', }); - expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', {}, 'test-session'); + expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', 'test-session', true); expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, false); }); @@ -308,14 +222,14 @@ describe('Extension Manager', () => { }) ).rejects.toThrow('Agent failed'); - expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, {}, 'test-session'); + expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); // addToConfig is called during the rollback (toggleOff) expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, false); }); it('should remove from agent if config update fails when toggling on', async () => { const configError = new Error('Config failed'); - mockAddToAgent.mockResolvedValue({} as Response); + mockAddToAgent.mockResolvedValue(undefined); mockAddToConfig.mockRejectedValue(configError); await expect( @@ -327,9 +241,9 @@ describe('Extension Manager', () => { }) ).rejects.toThrow('Config failed'); - expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, {}, 'test-session'); + expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, true); - expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', {}, 'test-session'); + expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', 'test-session', true); }); it('should update config even if agent removal fails when toggling off', async () => { @@ -346,71 +260,7 @@ describe('Extension Manager', () => { }) ).rejects.toThrow('Agent removal failed'); - expect(mockRemoveFromAgent).toHaveBeenCalledWith('test-extension', {}, 'test-session'); expect(mockAddToConfig).toHaveBeenCalledWith('test-extension', mockExtensionConfig, false); }); }); - - describe('deleteExtension', () => { - it('should delete extension successfully', async () => { - mockRemoveFromAgent.mockResolvedValue({} as Response); - mockRemoveFromConfig.mockResolvedValue(undefined); - - await deleteExtension({ - name: 'test-extension', - removeFromConfig: mockRemoveFromConfig, - sessionId: 'test-session', - }); - - expect(mockRemoveFromAgent).toHaveBeenCalledWith( - 'test-extension', - { isDelete: true }, - 'test-session' - ); - expect(mockRemoveFromConfig).toHaveBeenCalledWith('test-extension'); - }); - - it('should remove from config even if agent removal fails', async () => { - const agentError = new Error('Agent removal failed'); - mockRemoveFromAgent.mockRejectedValue(agentError); - mockRemoveFromConfig.mockResolvedValue(undefined); - - await expect( - deleteExtension({ - name: 'test-extension', - removeFromConfig: mockRemoveFromConfig, - sessionId: 'test-session', - }) - ).rejects.toThrow('Agent removal failed'); - - expect(mockRemoveFromAgent).toHaveBeenCalledWith( - 'test-extension', - { isDelete: true }, - 'test-session' - ); - expect(mockRemoveFromConfig).toHaveBeenCalledWith('test-extension'); - }); - - it('should throw config error if both agent and config fail', async () => { - const agentError = new Error('Agent removal failed'); - const configError = new Error('Config removal failed'); - mockRemoveFromAgent.mockRejectedValue(agentError); - mockRemoveFromConfig.mockRejectedValue(configError); - - await expect( - deleteExtension({ - name: 'test-extension', - removeFromConfig: mockRemoveFromConfig, - sessionId: 'test-session', - }) - ).rejects.toThrow('Config removal failed'); - - expect(mockRemoveFromAgent).toHaveBeenCalledWith( - 'test-extension', - { isDelete: true }, - 'test-session' - ); - expect(mockRemoveFromConfig).toHaveBeenCalledWith('test-extension'); - }); - }); }); diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.ts b/ui/desktop/src/components/settings/extensions/extension-manager.ts index a27693eadf5e..c8f212a1101e 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.ts @@ -60,23 +60,20 @@ export async function activateExtension({ }: ActivateExtensionProps): Promise { try { // AddToAgent - await addToAgent(extensionConfig, { silent: false }, sessionId); + await addToAgent(extensionConfig, sessionId, true); } catch (error) { console.error('Failed to add extension to agent:', error); - // add to config with enabled = false await addToConfig(extensionConfig.name, extensionConfig, false); - // Rethrow the error to inform the caller throw error; } - // Then add to config try { await addToConfig(extensionConfig.name, extensionConfig, true); } catch (error) { console.error('Failed to add extension to config:', error); // remove from Agent try { - await removeFromAgent(extensionConfig.name, {}, sessionId); + await removeFromAgent(extensionConfig.name, sessionId, true); } catch (removeError) { console.error('Failed to remove extension from agent after config failure:', removeError); } @@ -94,15 +91,16 @@ interface AddToAgentOnStartupProps { /** * Adds an extension to the agent during application startup with retry logic + * + * TODO(Douwe): Delete this after basecamp lands */ export async function addToAgentOnStartup({ addToConfig, extensionConfig, - toastOptions = { silent: true }, sessionId, }: AddToAgentOnStartupProps): Promise { try { - await retryWithBackoff(() => addToAgent(extensionConfig, toastOptions, sessionId), { + await retryWithBackoff(() => addToAgent(extensionConfig, sessionId, true), { retries: 3, delayMs: 1000, shouldRetry: (error: ExtensionError) => @@ -165,7 +163,7 @@ export async function updateExtension({ // First remove the old extension from agent (using original name) try { - await removeFromAgent(originalName!, { silent: true }, sessionId); // Suppress removal toast since we'll show update toast + await removeFromAgent(originalName!, sessionId, false); } catch (error) { console.error('Failed to remove old extension from agent during rename:', error); // Continue with the process even if agent removal fails @@ -188,8 +186,7 @@ export async function updateExtension({ // Add new extension with sanitized name if (enabled) { try { - // AddToAgent with silent option to avoid duplicate toasts - await addToAgent(sanitizedExtensionConfig, { silent: true }, sessionId); + await addToAgent(sanitizedExtensionConfig, sessionId, false); } catch (error) { console.error('[updateExtension]: Failed to add renamed extension to agent:', error); throw error; @@ -218,8 +215,7 @@ export async function updateExtension({ if (enabled) { try { - // AddToAgent with silent option to avoid duplicate toasts - await addToAgent(sanitizedExtensionConfig, { silent: true }, sessionId); + await addToAgent(sanitizedExtensionConfig, sessionId, false); } catch (error) { console.error('[updateExtension]: Failed to add extension to agent during update:', error); // Failed to add to agent -- show that error to user and do not update the config file @@ -278,13 +274,7 @@ export async function toggleExtension({ if (toggle == 'toggleOn') { try { // add to agent with toast options - await addToAgent( - extensionConfig, - { - ...toastOptions, - }, - sessionId - ); + await addToAgent(extensionConfig, sessionId, !toastOptions?.silent); } catch (error) { console.error('Error adding extension to agent. Will try to toggle back off.'); try { @@ -308,7 +298,7 @@ export async function toggleExtension({ console.error('Failed to update config after enabling extension:', error); // remove from agent try { - await removeFromAgent(extensionConfig.name, toastOptions, sessionId); + await removeFromAgent(extensionConfig.name, sessionId, !toastOptions?.silent); } catch (removeError) { console.error('Failed to remove extension from agent after config failure:', removeError); } @@ -318,7 +308,7 @@ export async function toggleExtension({ // enabled to disabled let agentRemoveError = null; try { - await removeFromAgent(extensionConfig.name, toastOptions, sessionId); + await removeFromAgent(extensionConfig.name, sessionId, !toastOptions?.silent); } catch (error) { // note there was an error, but attempt to remove from config anyway console.error('Error removing extension from agent', extensionConfig.name, error); @@ -353,7 +343,7 @@ export async function deleteExtension({ name, removeFromConfig, sessionId }: Del // remove from agent let agentRemoveError = null; try { - await removeFromAgent(name, { isDelete: true }, sessionId); + await removeFromAgent(name, sessionId, true); } catch (error) { console.error('Failed to remove extension from agent during deletion:', error); agentRemoveError = error; diff --git a/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionList.tsx b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionList.tsx index 1c1b37526702..a39137076e2f 100644 --- a/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionList.tsx +++ b/ui/desktop/src/components/settings/extensions/subcomponents/ExtensionList.tsx @@ -1,8 +1,8 @@ -import { FixedExtensionEntry } from '../../../ConfigContext'; -import { ExtensionConfig } from '../../../../api/types.gen'; import ExtensionItem from './ExtensionItem'; import builtInExtensionsData from '../../../../built-in-extensions.json'; -import { combineCmdAndArgs, removeShims } from '../utils'; +import { combineCmdAndArgs } from '../utils'; +import { ExtensionConfig } from '../../../../api'; +import { FixedExtensionEntry } from '../../../ConfigContext'; interface ExtensionListProps { extensions: FixedExtensionEntry[]; @@ -132,7 +132,7 @@ export function getSubtitle(config: ExtensionConfig) { default: return { description: config.description || null, - command: 'cmd' in config ? combineCmdAndArgs(removeShims(config.cmd), config.args) : null, + command: 'cmd' in config ? combineCmdAndArgs(config.cmd, config.args) : null, }; } } diff --git a/ui/desktop/src/components/settings/extensions/utils.test.ts b/ui/desktop/src/components/settings/extensions/utils.test.ts index dce8ea94ce5d..98c90963d427 100644 --- a/ui/desktop/src/components/settings/extensions/utils.test.ts +++ b/ui/desktop/src/components/settings/extensions/utils.test.ts @@ -6,8 +6,6 @@ import { createExtensionConfig, splitCmdAndArgs, combineCmdAndArgs, - replaceWithShims, - removeShims, extractCommand, extractExtensionName, DEFAULT_EXTENSION_TIMEOUT, @@ -342,54 +340,6 @@ describe('Extension Utils', () => { }); }); - describe('replaceWithShims', () => { - beforeEach(() => { - mockElectron.getBinaryPath.mockImplementation((binary: string) => { - const paths: Record = { - goosed: '/path/to/goosed', - jbang: '/path/to/jbang', - npx: '/path/to/npx', - uvx: '/path/to/uvx', - }; - return Promise.resolve(paths[binary] || binary); - }); - }); - - it('should replace known commands with shim paths', async () => { - expect(await replaceWithShims('goosed')).toBe('/path/to/goosed'); - expect(await replaceWithShims('jbang')).toBe('/path/to/jbang'); - expect(await replaceWithShims('npx')).toBe('/path/to/npx'); - expect(await replaceWithShims('uvx')).toBe('/path/to/uvx'); - }); - - it('should leave unknown commands unchanged', async () => { - expect(await replaceWithShims('python')).toBe('python'); - expect(await replaceWithShims('node')).toBe('node'); - }); - }); - - describe('removeShims', () => { - it('should remove shim paths and return command name', () => { - expect(removeShims('/path/to/goosed')).toBe('goosed'); - expect(removeShims('/usr/local/bin/jbang')).toBe('jbang'); - expect(removeShims('/Applications/Docker.app/Contents/Resources/bin/docker')).toBe('docker'); - expect(removeShims('/path/to/npx.cmd')).toBe('npx.cmd'); - }); - - it('should handle paths with trailing slashes', () => { - // The removeShims function only works if the path ends with the shim pattern - // Trailing slashes prevent the pattern from matching - expect(removeShims('/path/to/goosed/')).toBe('/path/to/goosed/'); - expect(removeShims('/path/to/uvx//')).toBe('/path/to/uvx//'); - }); - - it('should leave non-shim commands unchanged', () => { - expect(removeShims('python')).toBe('python'); - expect(removeShims('node')).toBe('node'); - expect(removeShims('/usr/bin/python3')).toBe('/usr/bin/python3'); - }); - }); - describe('extractCommand', () => { it('should extract command from extension link', () => { const link = 'goose://extension/add?name=Test&cmd=python&arg=script.py&arg=--flag'; diff --git a/ui/desktop/src/components/settings/extensions/utils.ts b/ui/desktop/src/components/settings/extensions/utils.ts index 137853034774..b561ea1437ec 100644 --- a/ui/desktop/src/components/settings/extensions/utils.ts +++ b/ui/desktop/src/components/settings/extensions/utils.ts @@ -190,41 +190,6 @@ export function combineCmdAndArgs(cmd: string, args: string[]): string { return [cmd, ...args].join(' '); } -export async function replaceWithShims(cmd: string) { - const binaryPathMap: Record = { - goosed: await window.electron.getBinaryPath('goosed'), - jbang: await window.electron.getBinaryPath('jbang'), - npx: await window.electron.getBinaryPath('npx'), - uvx: await window.electron.getBinaryPath('uvx'), - }; - - if (binaryPathMap[cmd]) { - console.log('--------> Replacing command with shim ------>', cmd, binaryPathMap[cmd]); - cmd = binaryPathMap[cmd]; - } - - return cmd; -} - -export function removeShims(cmd: string) { - // Only remove shims if the path matches our known shim patterns - const shimPatterns = [/cu$/, /goosed$/, /docker$/, /jbang$/, /npx$/, /uvx$/, /npx.cmd$/]; - - // Check if the command matches any shim pattern - const isShim = shimPatterns.some((pattern) => pattern.test(cmd)); - - if (isShim) { - const segments = cmd.split('/'); - // Filter out any empty segments (which can happen with trailing slashes) - const nonEmptySegments = segments.filter((segment) => segment.length > 0); - // Return the last segment or empty string if there are no segments - return nonEmptySegments.length > 0 ? nonEmptySegments[nonEmptySegments.length - 1] : ''; - } - - // If it's not a shim, return the original command - return cmd; -} - export function extractCommand(link: string): string { const url = new URL(link); const cmd = url.searchParams.get('cmd') || 'Unknown Command'; diff --git a/ui/desktop/src/hooks/useWhisper.ts b/ui/desktop/src/hooks/useWhisper.ts index fe0ddb62d8c2..385f674e9423 100644 --- a/ui/desktop/src/hooks/useWhisper.ts +++ b/ui/desktop/src/hooks/useWhisper.ts @@ -2,7 +2,7 @@ import { useState, useRef, useCallback, useEffect } from 'react'; import { useConfig } from '../components/ConfigContext'; import { getApiUrl } from '../config'; import { useDictationSettings } from './useDictationSettings'; -import { safeJsonParse } from '../utils/jsonUtils'; +import { safeJsonParse } from '../utils/conversionUtils'; interface UseWhisperOptions { onTranscription?: (text: string) => void; diff --git a/ui/desktop/src/sharedSessions.ts b/ui/desktop/src/sharedSessions.ts index 4e6b7184ca1e..849f5549f86e 100644 --- a/ui/desktop/src/sharedSessions.ts +++ b/ui/desktop/src/sharedSessions.ts @@ -1,4 +1,4 @@ -import { safeJsonParse } from './utils/jsonUtils'; +import { safeJsonParse } from './utils/conversionUtils'; import { Message } from './api'; export interface SharedSessionDetails { diff --git a/ui/desktop/src/utils/jsonUtils.ts b/ui/desktop/src/utils/conversionUtils.ts similarity index 51% rename from ui/desktop/src/utils/jsonUtils.ts rename to ui/desktop/src/utils/conversionUtils.ts index 1f8f3ec01ee0..51b9cb30accf 100644 --- a/ui/desktop/src/utils/jsonUtils.ts +++ b/ui/desktop/src/utils/conversionUtils.ts @@ -11,3 +11,13 @@ export async function safeJsonParse( throw error; } } + +export function errorMessage(err: Error | unknown, default_value?: string) { + if (err instanceof Error) { + return err.message; + } else if (typeof err === 'object' && err !== null && 'message' in err) { + return String(err.message); + } else { + return default_value || String(err); + } +} diff --git a/ui/desktop/src/utils/costDatabase.ts b/ui/desktop/src/utils/costDatabase.ts index 04dc868700ab..a2e8e5cbd213 100644 --- a/ui/desktop/src/utils/costDatabase.ts +++ b/ui/desktop/src/utils/costDatabase.ts @@ -1,6 +1,6 @@ // Import the proper type from ConfigContext import { getApiUrl } from '../config'; -import { safeJsonParse } from './jsonUtils'; +import { safeJsonParse } from './conversionUtils'; export interface ModelCostInfo { input_token_cost: number; // Cost per token for input (in USD) diff --git a/ui/desktop/src/utils/githubUpdater.ts b/ui/desktop/src/utils/githubUpdater.ts index 4516a2aee442..1b0140b9475a 100644 --- a/ui/desktop/src/utils/githubUpdater.ts +++ b/ui/desktop/src/utils/githubUpdater.ts @@ -4,7 +4,7 @@ import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; import log from './logger'; -import { safeJsonParse } from './jsonUtils'; +import { safeJsonParse } from './conversionUtils'; interface GitHubRelease { tag_name: string; From 34e3a241c10b4d25e1a9d7df7a9fbb6e8be76b05 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 29 Oct 2025 11:34:13 -0400 Subject: [PATCH 009/121] Configurable search paths (#5356) Signed-off-by: fbalicchia --- Cargo.lock | 6 +++-- crates/goose/Cargo.toml | 2 ++ crates/goose/src/agents/extension_manager.rs | 7 ++++++ crates/goose/src/config/base.rs | 12 ++++++++++ crates/goose/src/config/mod.rs | 1 + crates/goose/src/config/search_path.rs | 25 ++++++++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 crates/goose/src/config/search_path.rs diff --git a/Cargo.lock b/Cargo.lock index 18578f0b1640..ee07bf9bb281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2648,6 +2648,7 @@ dependencies = [ "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", + "paste", "rand 0.8.5", "regex", "reqwest 0.12.12", @@ -2659,6 +2660,7 @@ dependencies = [ "serde_yaml", "serial_test", "sha2", + "shellexpand", "sqlx", "sys-info", "temp-env", @@ -6129,9 +6131,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shellexpand" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" dependencies = [ "dirs", ] diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index e70471c8909f..f1fad2320ac8 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -105,6 +105,8 @@ sys-info = "0.9" oauth2 = "5.0.0" schemars = { version = "1.0.4", default-features = false, features = ["derive"] } insta = "1.43.2" +paste = "1.0.0" +shellexpand = "3.1.1" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/crates/goose/src/agents/extension_manager.rs b/crates/goose/src/agents/extension_manager.rs index 7e81552f6c2c..7eaa2ea8bde2 100644 --- a/crates/goose/src/agents/extension_manager.rs +++ b/crates/goose/src/agents/extension_manager.rs @@ -32,6 +32,7 @@ use super::tool_execution::ToolCallResult; use crate::agents::extension::{Envs, ProcessExit}; use crate::agents::extension_malware_check; use crate::agents::mcp_client::{McpClient, McpClientTrait}; +use crate::config::search_path::search_path_var; use crate::config::{get_all_extensions, Config}; use crate::oauth::oauth_flow; use crate::prompt_template; @@ -182,6 +183,12 @@ async fn child_process_client( command.process_group(0); #[cfg(windows)] command.creation_flags(CREATE_NO_WINDOW_FLAG); + + command.env( + "PATH", + search_path_var().map_err(|e| ExtensionError::ConfigError(format!("{}", e)))?, + ); + let (transport, mut stderr) = TokioChildProcess::builder(command) .stderr(Stdio::piped()) .spawn()?; diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index 3cde60d3b423..3974a4b9a6cc 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -136,6 +136,16 @@ impl Default for Config { } } +macro_rules! declare_param { + ($param_name:ident, $param_type:ty) => { + paste::paste! { + pub fn [](&self) -> Result<$param_type, ConfigError> { + self.get_param(stringify!($param_name)) + } + } + }; +} + impl Config { /// Get the global configuration instance. /// @@ -730,6 +740,8 @@ impl Config { }; Ok(()) } + + declare_param!(GOOSE_SEARCH_PATHS, Vec); } /// Load init-config.yaml from workspace root if it exists. diff --git a/crates/goose/src/config/mod.rs b/crates/goose/src/config/mod.rs index 3ab6f3497ffa..c37a49e66b89 100644 --- a/crates/goose/src/config/mod.rs +++ b/crates/goose/src/config/mod.rs @@ -4,6 +4,7 @@ mod experiments; pub mod extensions; pub mod paths; pub mod permission; +pub mod search_path; pub mod signup_openrouter; pub mod signup_tetrate; diff --git a/crates/goose/src/config/search_path.rs b/crates/goose/src/config/search_path.rs new file mode 100644 index 000000000000..d500a4bb5167 --- /dev/null +++ b/crates/goose/src/config/search_path.rs @@ -0,0 +1,25 @@ +use std::{env, ffi::OsString, path::PathBuf}; + +use crate::config::{Config, ConfigError}; + +pub fn search_path_var() -> Result { + let paths = Config::global() + .get_goose_search_paths() + .or_else(|err| match err { + ConfigError::NotFound(_) => Ok(vec![]), + err => Err(err), + })? + .into_iter() + .map(|s| PathBuf::from(shellexpand::tilde(&s).as_ref())); + + env::join_paths( + paths.chain( + env::var_os("PATH") + .as_ref() + .map(env::split_paths) + .into_iter() + .flatten(), + ), + ) + .map_err(|e| ConfigError::DeserializeError(format!("{}", e))) +} From 0f6aa2e600d79f039886aa89b0850f723fe1a9e3 Mon Sep 17 00:00:00 2001 From: Anudhyan Datta <127120520+Anudhyan@users.noreply.github.com> Date: Wed, 29 Oct 2025 21:04:52 +0530 Subject: [PATCH 010/121] docs: Anudhyan's PR for Hacktoberfest issue #4722 (#5442) Signed-off-by: Anudhyan <127120520+Anudhyan@users.noreply.github.com> Signed-off-by: Anudhyan Datta " Signed-off-by: Anudhyan Datta Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 12200b369f44..1f9fcf91375b 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -150,6 +150,18 @@ "submittedDate": "2025-10-29", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Stop Chasing Stale Docs: Creating Automated Documentation Workflows with goose", + "author": { + "name": "Anudhyan Datta", + "handle": "Anudhyan" + }, + "type": "blog", + "url": "https://anudhyan.hashnode.dev/stop-chasing-stale-docs-creating-automated-documentation-workflows-with-goose", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] -} \ No newline at end of file +} From 36b33e961acdb90559dc7db1361d83e713639f05 Mon Sep 17 00:00:00 2001 From: Shreyansh Singh Gautam <149963387+Shreyanshsingh23@users.noreply.github.com> Date: Wed, 29 Oct 2025 21:19:34 +0530 Subject: [PATCH 011/121] Blog post goose recipes (#5438) Signed-off-by: Shreyansh Singh Gautam Co-authored-by: taniandjerry <126204004+taniandjerry@users.noreply.github.com> Thank you so much for contributing this Hacktoberfest, Sheryansh! Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 1f9fcf91375b..9772a5071b9f 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -122,9 +122,7 @@ "url": "https://dev.to/lymah/configuring-goose-for-team-environments-and-shared-workflows-5ehn", "thumbnail": "https://i.imgur.com/pltI1bv.jpeg", "submittedDate": "2025-10-26", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -139,6 +137,19 @@ "tags": ["hacktoberfest"], "hacktoberfest": true }, + { + "title": "Creating and Sharing Effective goose Recipes", + "author": { + "name": "Shreyansh Singh Gautam", + "handle": "Shreyanshsingh23" + }, + "type": "blog", + "url": "https://medium.com/@shreyanshrewa/creating-and-sharing-effective-goose-recipes-abf9767d5128", + "thumbnail": "https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=400&h=225&fit=crop&crop=entropy&auto=format", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true + }, { "title": "Goose with Context7 MCP", "author": { From 518edb4950d189875a938b0fcd9e499779aa7dfb Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Wed, 29 Oct 2025 12:14:26 -0400 Subject: [PATCH 012/121] fix(extensions/desktop): only show env vars for stdio mcps (#5430) Signed-off-by: fbalicchia --- .../extensions/modal/ExtensionModal.tsx | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx b/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx index 44b26345f843..947a6d02f288 100644 --- a/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx +++ b/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx @@ -353,7 +353,6 @@ export default function ExtensionModal({ submitAttempted={submitAttempted} /> - {/* Divider */}
{/* Command */} @@ -374,42 +373,43 @@ export default function ExtensionModal({ /> - {/* Divider */} -
+ {formData.type === 'stdio' && ( + <> +
+ +
+ +
+ + )} - {/* Environment Variables */} -
- -
+ {formData.type === 'streamable_http' && ( + <> + {/* Divider */} +
+ +
+ +
+ + )} )} - {/* Request Headers - Only for streamable_http */} - {formData.type === 'streamable_http' && ( - <> - {/* Divider */} -
- -
- -
- - )} - {showDeleteConfirmation ? ( <> From b52d54e0443eb04e0e92411760426c8d4dc32567 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Wed, 29 Oct 2025 12:50:55 -0400 Subject: [PATCH 013/121] fix: don't use user specific paths in mcp integration tests (#5445) Signed-off-by: fbalicchia --- crates/goose/tests/mcp_integration_test.rs | 15 +++++++++++---- ...--quiet-pgoose-server--bingoosed--mcpdeveloper | 14 +++++++------- ...e-server--bingoosed--mcpdeveloper.results.json | 8 ++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/crates/goose/tests/mcp_integration_test.rs b/crates/goose/tests/mcp_integration_test.rs index e3c47a56524f..9182735a5863 100644 --- a/crates/goose/tests/mcp_integration_test.rs +++ b/crates/goose/tests/mcp_integration_test.rs @@ -108,22 +108,22 @@ enum TestMode { vec![ CallToolRequestParam { name: "text_editor".into(), arguments: Some(object!({ "command": "view", - "path": "~/goose/crates/goose/tests/tmp/goose.txt" + "path": "/tmp/goose_test/goose.txt" }))}, CallToolRequestParam { name: "text_editor".into(), arguments: Some(object!({ "command": "str_replace", - "path": "~/goose/crates/goose/tests/tmp/goose.txt", + "path": "/tmp/goose_test/goose.txt", "old_str": "# goose", "new_str": "# goose (modified by test)" }))}, // Test shell command to verify file was modified CallToolRequestParam { name: "shell".into(), arguments: Some(object!({ - "command": "cat ~/goose/crates/goose/tests/tmp/goose.txt" + "command": "cat /tmp/goose_test/goose.txt" })) }, // Test text_editor tool to restore original content CallToolRequestParam { name: "text_editor".into(), arguments: Some(object!({ "command": "str_replace", - "path": "~/goose/crates/goose/tests/tmp/goose.txt", + "path": "/tmp/goose_test/goose.txt", "old_str": "# goose (modified by test)", "new_str": "# goose" }))}, @@ -138,6 +138,13 @@ async fn test_replayed_session( required_envs: Vec<&str>, ) { std::env::set_var("GOOSE_MCP_CLIENT_VERSION", "0.0.0"); + + // Setup test file for developer extension tests + let test_file_path = "/tmp/goose_test/goose.txt"; + if let Some(parent) = std::path::Path::new(test_file_path).parent() { + fs::create_dir_all(parent).ok(); + } + fs::write(test_file_path, "# goose\n").ok(); let replay_file_name = command .iter() .map(|s| s.replace("/", "_")) diff --git a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper index 1b6f4f54ec91..b8b5c12a217b 100644 --- a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper +++ b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper @@ -10,19 +10,19 @@ STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"} STDERR: 2025-09-27T04:13:30.418172Z  INFO rmcp::handler::server: client initialized STDERR: at /Users/angiej/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.6.2/src/handler/server.rs:218 STDERR: -STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"text_editor","arguments":{"command":"view","path":"~/goose/crates/goose/tests/tmp/goose.txt"}}} +STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"text_editor","arguments":{"command":"view","path":"/tmp/goose_test/goose.txt"}}} STDERR: 2025-09-27T04:13:30.418412Z  INFO rmcp::service: Service initialized as server, peer_info: Some(InitializeRequestParam { protocol_version: ProtocolVersion("2025-03-26"), capabilities: ClientCapabilities { experimental: None, roots: None, sampling: None, elicitation: None }, client_info: Implementation { name: "goose", version: "1.9.0" } }) STDERR: at /Users/angiej/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.6.2/src/service.rs:561 STDERR: in rmcp::service::serve_inner STDERR: -STDOUT: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"resource","resource":{"uri":"file:///Users/angiej/goose/crates/goose/tests/tmp/goose.txt","mimeType":"text","text":"# goose\n"},"annotations":{"audience":["assistant"]}},{"type":"text","text":"### /Users/angiej/goose/crates/goose/tests/tmp/goose.txt\n```\n1: # goose\n```\n","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} -STDIN: {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"_meta":{"progressToken":1},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose (modified by test)","old_str":"# goose","path":"~/goose/crates/goose/tests/tmp/goose.txt"}}} -STDOUT: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"The file /Users/angiej/goose/crates/goose/tests/tmp/goose.txt has been edited, and the section now reads:\n```\n# goose (modified by test)\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose (modified by test)\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} -STDIN: {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"_meta":{"progressToken":2},"name":"shell","arguments":{"command":"cat ~/goose/crates/goose/tests/tmp/goose.txt"}}} +STDOUT: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"resource","resource":{"uri":"file:///tmp/goose_test/goose.txt","mimeType":"text","text":"# goose\n"},"annotations":{"audience":["assistant"]}},{"type":"text","text":"### /tmp/goose_test/goose.txt\n```\n1: # goose\n```\n","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} +STDIN: {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"_meta":{"progressToken":1},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose (modified by test)","old_str":"# goose","path":"/tmp/goose_test/goose.txt"}}} +STDOUT: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose (modified by test)\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose (modified by test)\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} +STDIN: {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"_meta":{"progressToken":2},"name":"shell","arguments":{"command":"cat /tmp/goose_test/goose.txt"}}} STDOUT: {"jsonrpc":"2.0","method":"notifications/message","params":{"level":"info","logger":"shell_tool","data":{"type":"shell_output","stream":"stdout","output":"# goose (modified by test)"}}} STDOUT: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"# goose (modified by test)\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"# goose (modified by test)\n","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} -STDIN: {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"_meta":{"progressToken":3},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose","old_str":"# goose (modified by test)","path":"~/goose/crates/goose/tests/tmp/goose.txt"}}} -STDOUT: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"The file /Users/angiej/goose/crates/goose/tests/tmp/goose.txt has been edited, and the section now reads:\n```\n# goose\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} +STDIN: {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"_meta":{"progressToken":3},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose","old_str":"# goose (modified by test)","path":"/tmp/goose_test/goose.txt"}}} +STDOUT: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} STDIN: {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"_meta":{"progressToken":4},"name":"list_windows","arguments":{}}} STDOUT: {"jsonrpc":"2.0","id":5,"result":{"content":[{"type":"text","text":"Available windows:\nMenubar","annotations":{"audience":["assistant"]}},{"type":"text","text":"Available windows:\nMenubar","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} STDERR: 2025-09-27T04:13:30.505916Z  INFO rmcp::service: input stream terminated diff --git a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json index c01cbec5f023..1f53d3c2629e 100644 --- a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json +++ b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json @@ -3,7 +3,7 @@ { "type": "resource", "resource": { - "uri": "file:///Users/angiej/goose/crates/goose/tests/tmp/goose.txt", + "uri": "file:///tmp/goose_test/goose.txt", "mimeType": "text", "text": "# goose\n" }, @@ -15,7 +15,7 @@ }, { "type": "text", - "text": "### /Users/angiej/goose/crates/goose/tests/tmp/goose.txt\n```\n1: # goose\n```\n", + "text": "### /tmp/goose_test/goose.txt\n```\n1: # goose\n```\n", "annotations": { "audience": [ "user" @@ -27,7 +27,7 @@ [ { "type": "text", - "text": "The file /Users/angiej/goose/crates/goose/tests/tmp/goose.txt has been edited, and the section now reads:\n```\n# goose (modified by test)\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n", + "text": "The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose (modified by test)\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n", "annotations": { "audience": [ "assistant" @@ -69,7 +69,7 @@ [ { "type": "text", - "text": "The file /Users/angiej/goose/crates/goose/tests/tmp/goose.txt has been edited, and the section now reads:\n```\n# goose\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n", + "text": "The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n", "annotations": { "audience": [ "assistant" From b27f3b6568b9e81ab9c31ebb01548fd95aa21cfb Mon Sep 17 00:00:00 2001 From: Lymah Date: Wed, 29 Oct 2025 18:12:26 +0100 Subject: [PATCH 014/121] Doc (Blog): Building Effective Prompts and Workflows for Code Review with goose (#5446) Signed-off-by: Lymah123 Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 9772a5071b9f..92db590fbe32 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -173,6 +173,19 @@ "submittedDate": "2025-10-29", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Building Effective Prompts and Workflows for Code Review with goose", + "author": { + "name": "Halimah", + "handle": "lymah123" + }, + "type": "blog", + "url": "https://dev.to/lymah/building-effective-prompts-and-workflows-for-code-review-with-goose-51m1", + "thumbnail": "https://i.imgur.com/2cRXct5.png", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] -} +} \ No newline at end of file From fc990e0b54240b15109d0b0b3816f8ec83b0347f Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:36:42 -0700 Subject: [PATCH 015/121] docs: otlp observability (#5436) Signed-off-by: fbalicchia --- documentation/docs/guides/config-file.md | 24 ++++--- .../docs/guides/environment-variables.md | 67 +++++++++++++------ documentation/docs/troubleshooting.md | 23 +++++-- 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/documentation/docs/guides/config-file.md b/documentation/docs/guides/config-file.md index fb8f953a320d..73ebb688ae42 100644 --- a/documentation/docs/guides/config-file.md +++ b/documentation/docs/guides/config-file.md @@ -6,7 +6,7 @@ sidebar_label: Configuration File # Configuration File -Goose uses a YAML configuration file to manage settings and extensions. This file is located at: +goose uses a YAML configuration file to manage settings and extensions. This file is located at: * macOS/Linux: `~/.config/goose/config.yaml` * Windows: `%APPDATA%\Block\goose\config\config.yaml` @@ -35,7 +35,9 @@ The following settings can be configured at the root level of your config.yaml f | `GOOSE_CLI_SHOW_COST` | Show estimated cost for token use in the CLI | true/false | false | No | | `GOOSE_ALLOWLIST` | URL for allowed extensions | Valid URL | None | No | | `GOOSE_RECIPE_GITHUB_REPO` | GitHub repository for recipes | Format: "org/repo" | None | No | -| `GOOSE_AUTO_COMPACT_THRESHOLD` | Set the percentage threshold at which Goose [automatically summarizes your session](/docs/guides/sessions/smart-context-management#automatic-compaction). | Float between 0.0 and 1.0 (disabled at 0.0)| 0.8 | No | +| `GOOSE_AUTO_COMPACT_THRESHOLD` | Set the percentage threshold at which goose [automatically summarizes your session](/docs/guides/sessions/smart-context-management#automatic-compaction). | Float between 0.0 and 1.0 (disabled at 0.0)| 0.8 | No | +| `otel_exporter_otlp_endpoint` | OTLP endpoint URL for [observability](/docs/guides/environment-variables#opentelemetry-protocol-otlp) | URL (e.g., `http://localhost:4318`) | None | No | +| `otel_exporter_otlp_timeout` | Export timeout in milliseconds for [observability](/docs/guides/environment-variables#opentelemetry-protocol-otlp) | Integer (ms) | 10000 | No | | `security_prompt_enabled` | Enable [prompt injection detection](/docs/guides/security/prompt-injection-detection) to identify potentially harmful commands | true/false | false | No | | `security_prompt_threshold` | Sensitivity threshold for [prompt injection detection](/docs/guides/security/prompt-injection-detection) (higher = stricter) | Float between 0.01 and 1.0 | 0.7 | No | @@ -75,6 +77,10 @@ GOOSE_CLI_MIN_PRIORITY: 0.2 # Recipe Configuration GOOSE_RECIPE_GITHUB_REPO: "block/goose-recipes" +# Observability (OpenTelemetry) +otel_exporter_otlp_endpoint: "http://localhost:4318" +otel_exporter_otlp_timeout: 20000 + # Security Configuration security_prompt_enabled: true @@ -102,10 +108,10 @@ Extensions are configured under the `extensions` key. Each extension can have th ```yaml extensions: extension_name: - bundled: true/false # Whether it's included with Goose - display_name: "Name" # Human-readable name (optional) - enabled: true/false # Whether the extension is active - name: "extension_name" # Internal name + bundled: true/false # Whether it's included with goose + display_name: "Name" # Human-readable name (optional) + enabled: true/false # Whether the extension is active + name: "extension_name" # Internal name timeout: 300 # Operation timeout in seconds type: "builtin"/"stdio" # Extension type @@ -113,8 +119,8 @@ extensions: cmd: "command" # Command to execute args: ["arg1", "arg2"] # Command arguments description: "text" # Extension description - env_keys: [] # Required environment variables - envs: {} # Environment values + env_keys: [] # Required environment variables + envs: {} # Environment values ``` ## Configuration Priority @@ -133,7 +139,7 @@ Settings are applied in the following order of precedence: ## Updating Configuration -Changes to the config file require restarting Goose to take effect. You can verify your current configuration using: +Changes to the config file require restarting goose to take effect. You can verify your current configuration using: ```bash goose info -v diff --git a/documentation/docs/guides/environment-variables.md b/documentation/docs/guides/environment-variables.md index 2ae552a1ba19..7f6dc0f2888f 100644 --- a/documentation/docs/guides/environment-variables.md +++ b/documentation/docs/guides/environment-variables.md @@ -4,7 +4,7 @@ title: Environment Variables sidebar_label: Environment Variables --- -Goose supports various environment variables that allow you to customize its behavior. This guide provides a comprehensive list of available environment variables grouped by their functionality. +goose supports various environment variables that allow you to customize its behavior. This guide provides a comprehensive list of available environment variables grouped by their functionality. ## Model Configuration @@ -12,7 +12,7 @@ These variables control the [language models](/docs/getting-started/providers) a ### Basic Provider Configuration -These are the minimum required variables to get started with Goose. +These are the minimum required variables to get started with goose. | Variable | Purpose | Values | Default | |----------|---------|---------|---------| @@ -70,7 +70,7 @@ A _turn_ is one complete prompt-response interaction. Here's how it works with t - Fallback to the lead model if the worker model struggles for 2 consecutive turns - Use the lead model for 2 turns and then switch back to the worker model -The lead model and worker model names are displayed at the start of the Goose CLI session. If you don't export a `GOOSE_MODEL` for your session, the worker model defaults to the `GOOSE_MODEL` in your [configuration file](/docs/guides/config-file). +The lead model and worker model names are displayed at the start of the goose CLI session. If you don't export a `GOOSE_MODEL` for your session, the worker model defaults to the `GOOSE_MODEL` in your [configuration file](/docs/guides/config-file). **Examples** @@ -88,7 +88,7 @@ export GOOSE_LEAD_FALLBACK_TURNS=2 ### Planning Mode Configuration -These variables control Goose's [planning functionality](/docs/guides/multi-model/creating-plans). +These variables control goose's [planning functionality](/docs/guides/multi-model/creating-plans). | Variable | Purpose | Values | Default | |----------|---------|---------|---------| @@ -146,17 +146,17 @@ export DATABRICKS_MAX_RETRY_INTERVAL_MS=60000 # cap the maximum retry del ## Session Management -These variables control how Goose manages conversation sessions and context. +These variables control how goose manages conversation sessions and context. | Variable | Purpose | Values | Default | |----------|---------|---------|---------| -| `GOOSE_CONTEXT_STRATEGY` | Controls how Goose handles context limit exceeded situations | "summarize", "truncate", "clear", "prompt" | "prompt" (interactive), "summarize" (headless) | +| `GOOSE_CONTEXT_STRATEGY` | Controls how goose handles context limit exceeded situations | "summarize", "truncate", "clear", "prompt" | "prompt" (interactive), "summarize" (headless) | | `GOOSE_MAX_TURNS` | [Maximum number of turns](/docs/guides/sessions/smart-context-management#maximum-turns) allowed without user input | Integer (e.g., 10, 50, 100) | 1000 | | `CONTEXT_FILE_NAMES` | Specifies custom filenames for [hint/context files](/docs/guides/using-goosehints#custom-context-files) | JSON array of strings (e.g., `["CLAUDE.md", ".goosehints"]`) | `[".goosehints"]` | | `GOOSE_CLI_THEME` | [Theme](/docs/guides/goose-cli-commands#themes) for CLI response markdown | "light", "dark", "ansi" | "dark" | | `GOOSE_RANDOM_THINKING_MESSAGES` | Controls whether to show amusing random messages during processing | "true", "false" | "true" | | `GOOSE_CLI_SHOW_COST` | Toggles display of model cost estimates in CLI output | "true", "1" (case insensitive) to enable | false | -| `GOOSE_AUTO_COMPACT_THRESHOLD` | Set the percentage threshold at which Goose [automatically summarizes your session](/docs/guides/sessions/smart-context-management#automatic-compaction). | Float between 0.0 and 1.0 (disabled at 0.0) | 0.8 | +| `GOOSE_AUTO_COMPACT_THRESHOLD` | Set the percentage threshold at which goose [automatically summarizes your session](/docs/guides/sessions/smart-context-management#automatic-compaction). | Float between 0.0 and 1.0 (disabled at 0.0) | 0.8 | **Examples** @@ -194,7 +194,7 @@ export GOOSE_AUTO_COMPACT_THRESHOLD=0.6 ### Model Context Limit Overrides -These variables allow you to override the default context window size (token limit) for your models. This is particularly useful when using [LiteLLM proxies](https://docs.litellm.ai/docs/providers/litellm_proxy) or custom models that don't match Goose's predefined model patterns. +These variables allow you to override the default context window size (token limit) for your models. This is particularly useful when using [LiteLLM proxies](https://docs.litellm.ai/docs/providers/litellm_proxy) or custom models that don't match goose's predefined model patterns. | Variable | Purpose | Values | Default | |----------|---------|---------|---------| @@ -221,11 +221,11 @@ For more details and examples, see [Model Context Limit Overrides](/docs/guides/ ## Tool Configuration -These variables control how Goose handles [tool execution](/docs/guides/goose-permissions) and [tool management](/docs/guides/managing-tools/). +These variables control how goose handles [tool execution](/docs/guides/goose-permissions) and [tool management](/docs/guides/managing-tools/). | Variable | Purpose | Values | Default | |----------|---------|---------|---------| -| `GOOSE_MODE` | Controls how Goose handles tool execution | "auto", "approve", "chat", "smart_approve" | "smart_approve" | +| `GOOSE_MODE` | Controls how goose handles tool execution | "auto", "approve", "chat", "smart_approve" | "smart_approve" | | `GOOSE_ENABLE_ROUTER` | Enables [intelligent tool selection strategy](/docs/guides/managing-tools/tool-router) | "true", "false" | "false" | | `GOOSE_TOOLSHIM` | Enables/disables tool call interpretation | "1", "true" (case insensitive) to enable | false | | `GOOSE_TOOLSHIM_OLLAMA_MODEL` | Specifies the model for [tool call interpretation](/docs/experimental/ollama) | Model name (e.g. llama3.2, qwen2.5) | System default | @@ -294,7 +294,34 @@ When the keyring is disabled, secrets are stored here: * Windows: `%APPDATA%\Block\goose\config\secrets.yaml` ::: -## Langfuse Integration +## Observability + +Beyond Goose's built-in [logging system](/docs/guides/logs), you can export telemetry to external observability platforms for advanced monitoring, performance analysis, and production insights. + +### OpenTelemetry Protocol (OTLP) + +Configure goose to export traces and metrics to any OTLP-compatible observability platform. +OTLP is the standard protocol for sending telemetry collected by [OpenTelemetry](https://opentelemetry.io/docs/). When configured, goose exports telemetry asynchronously and flushes on exit. + +| Variable | Purpose | Values | Default | +|----------|---------|--------|---------| +| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP endpoint URL | URL (e.g., `http://localhost:4318`) | None | +| `OTEL_EXPORTER_OTLP_TIMEOUT` | Export timeout in milliseconds | Integer (ms) | `10000` | + +**When to use OTLP:** +- Diagnosing slow tool execution or LLM response times when goose +- Understanding intermittent failures across multiple sessions +- Monitoring goose performance in production or CI/CD environments +- Tracking usage patterns, costs, and resource consumption over time +- Setting up alerts for performance degradation or high error rates + +**Example:** +```bash +export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318" +export OTEL_EXPORTER_OTLP_TIMEOUT=10000 +``` + +### Langfuse Integration These variables configure the [Langfuse integration for observability](/docs/tutorials/langfuse). @@ -349,28 +376,28 @@ export ALPHA_FEATURES=true ALPHA_FEATURES=true goose session ``` -## Variables Controlled by Goose +## Variables Controlled by goose -These variables are automatically set by Goose during command execution. +These variables are automatically set by goose during command execution. | Variable | Purpose | Values | Default | |----------|---------|---------|---------| -| `GOOSE_TERMINAL` | Indicates that a command is being executed by Goose, enables customizing shell behavior | "1" when set | Unset | +| `GOOSE_TERMINAL` | Indicates that a command is being executed by goose, enables customizing shell behavior | "1" when set | Unset | ### Customizing Shell Behavior -Sometimes you want Goose to use different commands or have different shell behavior than your normal terminal usage. For example, you might want Goose to use a different tool, or prevent Goose from running long-running development servers that could hang the AI agent. This is most useful when using Goose CLI, where shell commands are executed directly in your terminal environment. +Sometimes you want goose to use different commands or have different shell behavior than your normal terminal usage. For example, you might want goose to use a different tool, or prevent goose from running long-running development servers that could hang the AI agent. This is most useful when using goose CLI, where shell commands are executed directly in your terminal environment. **How it works:** -1. When Goose runs commands, `GOOSE_TERMINAL` is automatically set to "1" -2. Your shell configuration can detect this and direct Goose to change its default behavior while keeping your normal terminal usage unchanged +1. When goose runs commands, `GOOSE_TERMINAL` is automatically set to "1" +2. Your shell configuration can detect this and direct goose to change its default behavior while keeping your normal terminal usage unchanged **Example:** ```bash # In your ~/.bashrc or ~/.zshrc -# Guide Goose toward better tool choices +# Guide goose toward better tool choices if [[ -n "$GOOSE_TERMINAL" ]]; then alias find="echo 'Use rg instead: rg --files | rg for filenames, or rg for content search'" fi @@ -380,6 +407,6 @@ fi - Environment variables take precedence over configuration files. - For security-sensitive variables (like API keys), consider using the system keyring instead of environment variables. -- Some variables may require restarting Goose to take effect. -- When using the planning mode, if planner-specific variables are not set, Goose will fall back to the main model configuration. +- Some variables may require restarting goose to take effect. +- When using the planning mode, if planner-specific variables are not set, goose will fall back to the main model configuration. diff --git a/documentation/docs/troubleshooting.md b/documentation/docs/troubleshooting.md index 78feb8f3dc48..104b0e2d17a4 100644 --- a/documentation/docs/troubleshooting.md +++ b/documentation/docs/troubleshooting.md @@ -11,7 +11,7 @@ goose can and will edit files as part of its workflow. To avoid losing personal --- -### Interrupting Goose +### Interrupting goose If goose is heading in the wrong direction or gets stuck, you can [interrupt it](/docs/guides/sessions/in-session-actions#interrupt-task) to correct its actions or provide additional information. --- @@ -32,15 +32,24 @@ For particularly large or complex tasks, consider breaking them into smaller ses ### Preventing Long-Running Commands -If you use goose CLI and work with web development projects, you may encounter commands that cause Goose to hang indefinitely. Commands like `npm run dev`, `python -m http.server`, or `webpack serve` start development servers that never exit on their own. +If you use goose CLI and work with web development projects, you may encounter commands that cause goose to hang indefinitely. Commands like `npm run dev`, `python -m http.server`, or `webpack serve` start development servers that never exit on their own. You can prevent these issues by customizing your shell to handle these commands differently when goose runs them. See [Customizing Shell Behavior](/docs/guides/environment-variables#customizing-shell-behavior) for details on using the `GOOSE_TERMINAL` environment variable. --- +### Debugging and Diagnostics + +To help with troubleshooting issues, you can: + +- View [session and system logs](/docs/guides/logs) for debugging individual sessions +- Configure [telemetry export](/docs/guides/environment-variables#observability) for performance analysis, trend monitoring, or production/CI debugging + +--- + ### Context Length Exceeded Error -This error occurs when the input provided to Goose exceeds the maximum token limit of the LLM being used. To resolve this, try breaking down your input into smaller parts. You can also use [`.goosehints`][goosehints] as a way to provide goose with detailed context and use [message queues](/docs/guides/sessions/in-session-actions#queue-messages) in goose Desktop. +This error occurs when the input provided to goose exceeds the maximum token limit of the LLM being used. To resolve this, try breaking down your input into smaller parts. You can also use [`.goosehints`][goosehints] as a way to provide goose with detailed context and use [message queues](/docs/guides/sessions/in-session-actions#queue-messages) in goose Desktop. --- @@ -136,7 +145,7 @@ goose tries to use the system keyring (which requires DBus and X11) to securely To resolve: -Use the `GOOSE_DISABLE_KEYRING` environment variable to tell Goose to store secrets in files instead. This example sets the variable only while executing the `goose configure` command: +Use the `GOOSE_DISABLE_KEYRING` environment variable to tell goose to store secrets in files instead. This example sets the variable only while executing the `goose configure` command: ```bash GOOSE_DISABLE_KEYRING=1 goose configure @@ -296,7 +305,7 @@ If you encounter the error `Node.js installer script not found` when trying to a - Error occurs specifically when activating Node.js extensions #### Solution: -This issue typically occurs when Node.js is installed in a non-standard location. Goose expects to find Node.js in `C:\Program Files\nodejs\`, but it may be installed elsewhere (e.g., `D:\Program Files\nodejs\`). +This issue typically occurs when Node.js is installed in a non-standard location. goose expects to find Node.js in `C:\Program Files\nodejs\`, but it may be installed elsewhere (e.g., `D:\Program Files\nodejs\`). 1. **Check your Node.js installation path:** ```powershell @@ -305,7 +314,7 @@ This issue typically occurs when Node.js is installed in a non-standard location 2. **If Node.js is not in `C:\Program Files\nodejs\`, create a symbolic link:** - Open PowerShell as Administrator - - Create a symbolic link to redirect Goose to your actual Node.js installation: + - Create a symbolic link to redirect goose to your actual Node.js installation: ```powershell mklink /D "C:\Program Files\nodejs" "D:\Program Files\nodejs" ``` @@ -451,7 +460,7 @@ goose Desktop uses **"shims"** (packaged versions of `npx` and `uvx`) that autom args: [mcp-server-example] ``` -3. **Why this works:** Goose only replaces known command names (`npx`, `uvx`, `jbang`, etc.) with its packaged shims. Custom names are passed through unchanged to your system's actual executables. +3. **Why this works:** goose only replaces known command names (`npx`, `uvx`, `jbang`, etc.) with its packaged shims. Custom names are passed through unchanged to your system's actual executables. 4. **Require more changes**: In a corporate proxy environment or airgapped environment where the above doesn't work, it is recommended that you customize and package up goose desktop with shims/config that will work given the network constraints you have (for example, TLS certificate limitations, proxies, inability to download required content etc). From fcf8f70a26aadcb3dfd3211abfaa7b196ebb78db Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Wed, 29 Oct 2025 11:15:07 -0700 Subject: [PATCH 016/121] fix: shows the correct config file update path with cli configure (#5195) Signed-off-by: Anthony D. Mays Signed-off-by: fbalicchia --- crates/goose-cli/src/commands/configure.rs | 51 +++++++++++++++++++--- crates/goose-cli/src/commands/info.rs | 4 +- crates/goose/src/config/permission.rs | 5 +++ 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/crates/goose-cli/src/commands/configure.rs b/crates/goose-cli/src/commands/configure.rs index d4d4f8f07729..bf0ef6a0e614 100644 --- a/crates/goose-cli/src/commands/configure.rs +++ b/crates/goose-cli/src/commands/configure.rs @@ -10,6 +10,7 @@ use goose::config::extensions::{ get_all_extension_names, get_all_extensions, get_enabled_extensions, get_extension_by_name, name_to_key, remove_extension, set_extension, set_extension_enabled, }; +use goose::config::paths::Paths; use goose::config::permission::PermissionLevel; use goose::config::signup_tetrate::TetrateAuth; use goose::config::{ @@ -195,15 +196,17 @@ pub async fn handle_configure() -> anyhow::Result<()> { } Ok(()) } else { + let config_dir = Paths::config_dir().display().to_string(); + println!(); println!( "{}", - style("This will update your existing config file").dim() + style("This will update your existing config files").dim() ); println!( "{} {}", - style(" if you prefer, you can edit it directly at").dim(), - config.path() + style(" if you prefer, you can edit them directly at").dim(), + config_dir ); println!(); @@ -486,7 +489,7 @@ pub async fn configure_provider_dialog() -> anyhow::Result { } else { config.set_param(&key.name, Value::String(env_value))?; } - let _ = cliclack::log::info(format!("Saved {} to config file", key.name)); + let _ = cliclack::log::info(format!("Saved {} to {}", key.name, config.path())); } } None => { @@ -648,7 +651,7 @@ pub async fn configure_provider_dialog() -> anyhow::Result { // Update config with new values only if the test succeeds config.set_param("GOOSE_PROVIDER", Value::String(provider_name.to_string()))?; config.set_param("GOOSE_MODEL", Value::String(model.clone()))?; - cliclack::outro("Configuration saved successfully")?; + print_config_file_saved()?; Ok(true) } Err(e) => { @@ -709,7 +712,11 @@ pub fn toggle_extensions_dialog() -> anyhow::Result<()> { ); } - cliclack::outro("Extension settings updated successfully")?; + let config = Config::global(); + cliclack::outro(format!( + "Extension settings saved successfully to {}", + config.path() + ))?; Ok(()) } @@ -1123,6 +1130,8 @@ pub fn configure_extensions_dialog() -> anyhow::Result<()> { _ => unreachable!(), }; + print_config_file_saved()?; + Ok(()) } @@ -1178,6 +1187,8 @@ pub fn remove_extension_dialog() -> anyhow::Result<()> { cliclack::outro(format!("Removed {} extension", style(name).green()))?; } + print_config_file_saved()?; + Ok(()) } @@ -1216,6 +1227,8 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> { ) .interact()?; + let mut should_print_config_path = true; + match setting_type { "goose_mode" => { configure_goose_mode_dialog()?; @@ -1225,6 +1238,8 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> { } "tool_permission" => { configure_tool_permissions_dialog().await.and(Ok(()))?; + // No need to print config file path since it's already handled. + should_print_config_path = false; } "tool_output" => { configure_tool_output_dialog()?; @@ -1241,6 +1256,10 @@ pub async fn configure_settings_dialog() -> anyhow::Result<()> { _ => unreachable!(), }; + if should_print_config_path { + print_config_file_saved()?; + } + Ok(()) } @@ -1547,6 +1566,11 @@ pub async fn configure_tool_permissions_dialog() -> anyhow::Result<()> { tool.name, permission_label ))?; + cliclack::outro(format!( + "Changes saved to {}", + permission_manager.get_config_path().display() + ))?; + Ok(()) } @@ -1893,5 +1917,18 @@ pub fn configure_custom_provider_dialog() -> anyhow::Result<()> { "add" => add_provider(), "remove" => remove_provider(), _ => unreachable!(), - } + }?; + + print_config_file_saved()?; + + Ok(()) +} + +fn print_config_file_saved() -> anyhow::Result<()> { + let config = Config::global(); + cliclack::outro(format!( + "Configuration saved successfully to {}", + config.path() + ))?; + Ok(()) } diff --git a/crates/goose-cli/src/commands/info.rs b/crates/goose-cli/src/commands/info.rs index baf972d76826..0f0debc1c28a 100644 --- a/crates/goose-cli/src/commands/info.rs +++ b/crates/goose-cli/src/commands/info.rs @@ -14,11 +14,11 @@ pub fn handle_info(verbose: bool) -> Result<()> { // Get paths using a stored reference to the global config let config = Config::global(); - let config_file = config.path(); + let config_dir = Paths::config_dir().display().to_string(); // Define the labels and their corresponding path values once. let paths = [ - ("Config file:", config_file.to_string()), + ("Config dir:", config_dir), ("Sessions dir:", sessions_dir.display().to_string()), ("Logs dir:", logs_dir.display().to_string()), ]; diff --git a/crates/goose/src/config/permission.rs b/crates/goose/src/config/permission.rs index 5c184a3e9765..b2f2b63b1997 100644 --- a/crates/goose/src/config/permission.rs +++ b/crates/goose/src/config/permission.rs @@ -91,6 +91,11 @@ impl PermissionManager { self.get_permission(SMART_APPROVE_PERMISSION, principal_name) } + /// Retrieves the config file path. + pub fn get_config_path(&self) -> &Path { + self.config_path.as_path() + } + /// Helper function to retrieve the permission level for a specific permission category and tool. fn get_permission(&self, name: &str, principal_name: &str) -> Option { // Check if the permission category exists in the map From 79fc8985ee3cb3bf9048ed98614ef8a04f773fc7 Mon Sep 17 00:00:00 2001 From: Mohammed Thaha Date: Thu, 30 Oct 2025 01:01:01 +0530 Subject: [PATCH 017/121] docs: add blog on Optimizing Goose Performance on Windows (#5449) Signed-off-by: Mohammed Thaha Signed-off-by: fbalicchia --- .../src/pages/community/data/community-content.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 92db590fbe32..0b6b67ac602a 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -186,6 +186,19 @@ "submittedDate": "2025-10-29", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Optimizing Goose performance on Windows", + "author": { + "name": "Mohammed Thaha", + "handle": "mohammed-thaha" + }, + "type": "blog", + "url": "https://dev.to/mohammed_thaha/boosting-goose-performance-on-windows-real-benchmarks-power-tweaks-and-results-54gf", + "thumbnail": "https://media2.dev.to/dynamic/image/width=400,height=225,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxdtne8rxn4l2nctajv1.png", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] } \ No newline at end of file From 79f799c507377ed2dccbc0a40149800103eea356 Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Wed, 29 Oct 2025 13:46:01 -0700 Subject: [PATCH 018/121] docs: clarifies config file locations and purposes (#5210) Signed-off-by: Anthony D. Mays Signed-off-by: fbalicchia --- BUILDING_DOCKER.md | 2 +- .../docs/getting-started/installation.md | 5 +++-- .../docs/getting-started/using-extensions.md | 2 +- documentation/docs/guides/acp-clients.md | 2 +- .../{config-file.md => config-files.md} | 19 +++++++++++++------ .../docs/guides/environment-variables.md | 2 +- .../docs/guides/goose-cli-commands.md | 2 +- .../docs/guides/managing-tools/tool-router.md | 2 +- .../docs/guides/multi-model/autopilot.md | 2 +- .../docs/guides/recipes/session-recipes.md | 2 +- .../security/prompt-injection-detection.md | 2 +- .../sessions/smart-context-management.md | 4 ++-- documentation/docs/guides/subagents.mdx | 2 +- documentation/docs/troubleshooting.md | 2 +- documentation/docusaurus.config.ts | 4 ++++ 15 files changed, 33 insertions(+), 21 deletions(-) rename documentation/docs/guides/{config-file.md => config-files.md} (87%) diff --git a/BUILDING_DOCKER.md b/BUILDING_DOCKER.md index ef3b62e0bed7..ed61e4b5e0a9 100644 --- a/BUILDING_DOCKER.md +++ b/BUILDING_DOCKER.md @@ -319,4 +319,4 @@ When contributing Docker-related changes: - [goose in Docker Tutorial](documentation/docs/tutorials/goose-in-docker.md) - Step-by-step tutorial - [Installation Guide](https://block.github.io/goose/docs/getting-started/installation) - All installation methods -- [Configuration Guide](https://block.github.io/goose/docs/guides/config-file) - Detailed configuration options +- [Configuration Guide](https://block.github.io/goose/docs/guides/config-files) - Detailed configuration options diff --git a/documentation/docs/getting-started/installation.md b/documentation/docs/getting-started/installation.md index c7bb426991e4..93392be7a137 100644 --- a/documentation/docs/getting-started/installation.md +++ b/documentation/docs/getting-started/installation.md @@ -376,10 +376,10 @@ You can change your LLM provider and/or model or update your API key at any time ## Shared Configuration Settings -The Goose CLI and Desktop UI share all core configurations, including LLM provider settings, model selection, and extension configurations. When you install or configure extensions in either interface, the settings are stored in a central location at `~/.config/goose/config.yaml`, making them available to both the Desktop application and CLI. This makes it convenient to switch between interfaces while maintaining consistent settings. +The Goose CLI and Desktop UI share all core configurations, including LLM provider settings, model selection, and extension configurations. When you install or configure extensions in either interface, the settings are stored in a central location, making them available to both the Desktop application and CLI. This makes it convenient to switch between interfaces while maintaining consistent settings. For more information, visit the [Config Files][config-files] guide. :::info -While core configurations are shared between interfaces, extensions have flexibility in how they store authentication credentials. Some extensions may use the shared config file while others implement their own storage methods. +While core configurations are shared between interfaces, extensions have flexibility in how they store authentication credentials. Some extensions may use the shared config files while others implement their own storage methods. ::: @@ -404,3 +404,4 @@ You can also configure Extensions to extend Goose's functionality, including add [providers]: /docs/getting-started/providers [handling-rate-limits]: /docs/guides/handling-llm-rate-limits-with-goose [mcp]: https://www.anthropic.com/news/model-context-protocol +[config-files]: /docs/guides/config-files.md diff --git a/documentation/docs/getting-started/using-extensions.md b/documentation/docs/getting-started/using-extensions.md index ced2fdd71340..763f6193f138 100644 --- a/documentation/docs/getting-started/using-extensions.md +++ b/documentation/docs/getting-started/using-extensions.md @@ -523,7 +523,7 @@ Goose relies on extension properties to determine how to handle an extension. Yo - 1. Navigate to the Goose [configuration file](/docs/guides/config-file). For example, navigate to `~/.config/goose/config.yaml` on macOS. + 1. Navigate to the Goose [configuration file](/docs/guides/config-files). For example, navigate to `~/.config/goose/config.yaml` on macOS. 2. Edit the extension properties as needed and save your changes. diff --git a/documentation/docs/guides/acp-clients.md b/documentation/docs/guides/acp-clients.md index 0f072d9ebfe1..815d0dc06886 100644 --- a/documentation/docs/guides/acp-clients.md +++ b/documentation/docs/guides/acp-clients.md @@ -77,7 +77,7 @@ You should now be able to interact with Goose directly in Zed. Your ACP sessions ### Advanced Configuration -By default, Goose will use the provider and model defined in your [configuration file](/docs/guides/config-file). You can override this for specific ACP configurations using the `GOOSE_PROVIDER` and `GOOSE_MODEL` environment variables. +By default, Goose will use the provider and model defined in your [configuration file](/docs/guides/config-files). You can override this for specific ACP configurations using the `GOOSE_PROVIDER` and `GOOSE_MODEL` environment variables. The following Zed settings example configures two Goose agent instances. This is useful for: - Comparing model performance on the same task diff --git a/documentation/docs/guides/config-file.md b/documentation/docs/guides/config-files.md similarity index 87% rename from documentation/docs/guides/config-file.md rename to documentation/docs/guides/config-files.md index 73ebb688ae42..8a4754730963 100644 --- a/documentation/docs/guides/config-file.md +++ b/documentation/docs/guides/config-files.md @@ -1,17 +1,24 @@ --- sidebar_position: 85 -title: Configuration File -sidebar_label: Configuration File +title: Configuration Files +sidebar_label: Configuration Files --- -# Configuration File +# Configuration Overview -goose uses a YAML configuration file to manage settings and extensions. This file is located at: +goose uses YAML [configuration files](#configuration-files) to manage settings and extensions. The primary config file is located at: * macOS/Linux: `~/.config/goose/config.yaml` * Windows: `%APPDATA%\Block\goose\config\config.yaml` -The configuration file allows you to set default behaviors, configure language models, and manage extensions. While many settings can also be set using [environment variables](/docs/guides/environment-variables), the config file provides a persistent way to maintain your preferences. +The configuration files allow you to set default behaviors, configure language models, set tool permissions, and manage extensions. While many settings can also be set using [environment variables](/docs/guides/environment-variables), the config files provide a persistent way to maintain your preferences. + +## Configuration Files + +- **config.yaml** - Provider, model, extensions, and general settings +- **permission.yaml** - Tool permission levels configured via `goose configure` +- **secrets.yaml** - API keys and secrets (only when keyring is disabled) +- **permissions/tool_permissions.json** - Runtime permission decisions (auto-managed) ## Global Settings @@ -139,7 +146,7 @@ Settings are applied in the following order of precedence: ## Updating Configuration -Changes to the config file require restarting goose to take effect. You can verify your current configuration using: +Changes to config files require restarting goose to take effect. You can verify your current configuration using: ```bash goose info -v diff --git a/documentation/docs/guides/environment-variables.md b/documentation/docs/guides/environment-variables.md index 7f6dc0f2888f..40c5b02d6f70 100644 --- a/documentation/docs/guides/environment-variables.md +++ b/documentation/docs/guides/environment-variables.md @@ -70,7 +70,7 @@ A _turn_ is one complete prompt-response interaction. Here's how it works with t - Fallback to the lead model if the worker model struggles for 2 consecutive turns - Use the lead model for 2 turns and then switch back to the worker model -The lead model and worker model names are displayed at the start of the goose CLI session. If you don't export a `GOOSE_MODEL` for your session, the worker model defaults to the `GOOSE_MODEL` in your [configuration file](/docs/guides/config-file). +The lead model and worker model names are displayed at the start of the goose CLI session. If you don't export a `GOOSE_MODEL` for your session, the worker model defaults to the `GOOSE_MODEL` in your [configuration file](/docs/guides/config-files). **Examples** diff --git a/documentation/docs/guides/goose-cli-commands.md b/documentation/docs/guides/goose-cli-commands.md index aa9ed0026164..e137fdc99b05 100644 --- a/documentation/docs/guides/goose-cli-commands.md +++ b/documentation/docs/guides/goose-cli-commands.md @@ -507,7 +507,7 @@ The `/t` command controls the syntax highlighting theme for markdown content in **Configuration:** - The default theme is `dark` -- The theme setting is saved to the [configuration file](/docs/guides/config-file) as `GOOSE_CLI_THEME` and persists between sessions +- The theme setting is saved to the [configuration file](/docs/guides/config-files) as `GOOSE_CLI_THEME` and persists between sessions - The saved configuration can be overridden for the session using the `GOOSE_CLI_THEME` [environment variable](/docs/guides/environment-variables#session-management) :::info diff --git a/documentation/docs/guides/managing-tools/tool-router.md b/documentation/docs/guides/managing-tools/tool-router.md index 12e737d37edc..65bc17308349 100644 --- a/documentation/docs/guides/managing-tools/tool-router.md +++ b/documentation/docs/guides/managing-tools/tool-router.md @@ -147,7 +147,7 @@ When enabled, Goose uses LLM intelligence to analyze your query and select only ## Environment Variable Configuration -You can also configure tool selection using environment variables or in your [configuration file](/docs/guides/config-file): +You can also configure tool selection using environment variables or in your [configuration file](/docs/guides/config-files): ```bash # Enable LLM-based tool selection diff --git a/documentation/docs/guides/multi-model/autopilot.md b/documentation/docs/guides/multi-model/autopilot.md index 888e4645a005..ef302b3272d8 100644 --- a/documentation/docs/guides/multi-model/autopilot.md +++ b/documentation/docs/guides/multi-model/autopilot.md @@ -33,7 +33,7 @@ You can use `goose session --debug` in goose CLI to see when AutoPilot switches ## Configuration -Add the `x-advanced-models` section to your [`config.yaml`](/docs/guides/config-file) file and map your model preferences to [predefined](#predefined-roles) or custom roles. +Add the `x-advanced-models` section to your [`config.yaml`](/docs/guides/config-files) file and map your model preferences to [predefined](#predefined-roles) or custom roles. The `provider`, `model` and `role` parameters are required. diff --git a/documentation/docs/guides/recipes/session-recipes.md b/documentation/docs/guides/recipes/session-recipes.md index 9f369cc10c31..1b48459a6735 100644 --- a/documentation/docs/guides/recipes/session-recipes.md +++ b/documentation/docs/guides/recipes/session-recipes.md @@ -265,7 +265,7 @@ You can turn your current goose session into a reusable recipe that includes the #### Configure Recipe Location - Recipes can be stored locally on your device or in a GitHub repository. Configure your recipe repository using either the `goose configure` command or [config file](/docs/guides/config-file#global-settings). + Recipes can be stored locally on your device or in a GitHub repository. Configure your recipe repository using either the `goose configure` command or [config file](/docs/guides/config-files#global-settings). :::tip Repository Structure - Each recipe should be in its own directory diff --git a/documentation/docs/guides/security/prompt-injection-detection.md b/documentation/docs/guides/security/prompt-injection-detection.md index 2afe6d91ff64..9d82f57887a5 100644 --- a/documentation/docs/guides/security/prompt-injection-detection.md +++ b/documentation/docs/guides/security/prompt-injection-detection.md @@ -64,7 +64,7 @@ When in doubt, deny. - Add these settings to your [`config.yaml`](/docs/guides/config-file): + Add these settings to your [`config.yaml`](/docs/guides/config-files): ```yaml security_prompt_enabled: true diff --git a/documentation/docs/guides/sessions/smart-context-management.md b/documentation/docs/guides/sessions/smart-context-management.md index ff67cf79694d..6b5f4baa65de 100644 --- a/documentation/docs/guides/sessions/smart-context-management.md +++ b/documentation/docs/guides/sessions/smart-context-management.md @@ -159,7 +159,7 @@ This feature gives you control over agent autonomy and prevents infinite loops a - Enabling human supervision or interaction during autonomous operations - Controlling loops while testing and debugging agent behavior -This setting is stored as the `GOOSE_MAX_TURNS` environment variable in your [config.yaml file](/docs/guides/config-file). You can configure it using the Desktop app or CLI. +This setting is stored as the `GOOSE_MAX_TURNS` environment variable in your [config.yaml file](/docs/guides/config-files). You can configure it using the Desktop app or CLI. @@ -375,7 +375,7 @@ Pricing data is regularly fetched from the OpenRouter API and cached locally. Th These costs are estimates only, and not connected to your actual provider bill. The cost shown is an approximation based on token counts and public pricing data. - Show estimated cost in the Goose CLI by setting the `GOOSE_CLI_SHOW_COST` [environment variable](/docs/guides/environment-variables.md#session-management) or including it in the [configuration file](/docs/guides/config-file.md). + Show estimated cost in the Goose CLI by setting the `GOOSE_CLI_SHOW_COST` [environment variable](/docs/guides/environment-variables.md#session-management) or including it in the [configuration file](/docs/guides/config-files.md). ``` # Set environment variable diff --git a/documentation/docs/guides/subagents.mdx b/documentation/docs/guides/subagents.mdx index c2dd4cc8809a..776a51236704 100644 --- a/documentation/docs/guides/subagents.mdx +++ b/documentation/docs/guides/subagents.mdx @@ -150,7 +150,7 @@ I'll use your code-reviewer recipe to create a specialized subagent for this ana External subagents let you bring in AI agents from other providers and platforms, enabling Goose to coordinate and integrate your workflow with the broader ecosystem. In the below example, we use Codex as a subagent by running it as an MCP server: -**[Goose Configuration File](/docs/guides/config-file)** (`.~/.config/goose/config.yaml `): +**[Goose Configuration File](/docs/guides/config-files)** (`.~/.config/goose/config.yaml `): ```yaml subagent: args: diff --git a/documentation/docs/troubleshooting.md b/documentation/docs/troubleshooting.md index 104b0e2d17a4..65452b810c7b 100644 --- a/documentation/docs/troubleshooting.md +++ b/documentation/docs/troubleshooting.md @@ -125,7 +125,7 @@ Failed to authenticate: Execution error: OAuth configuration not supported by th ``` To resolve: -1. Temporarily comment out or remove lead/worker model variables from your config file (`~/.config/goose/config.yaml`): +1. Temporarily comment out or remove lead/worker model variables from the main config file (`~/.config/goose/config.yaml`): ```yaml # GOOSE_LEAD_MODEL: your-model # GOOSE_WORKER_MODEL: your-model diff --git a/documentation/docusaurus.config.ts b/documentation/docusaurus.config.ts index 84384519ac0f..a550acf11aea 100644 --- a/documentation/docusaurus.config.ts +++ b/documentation/docusaurus.config.ts @@ -162,6 +162,10 @@ const config: Config = { from: '/docs/guides/creating-plans', to: '/docs/guides/multi-model/creating-plans' }, + { + from: '/docs/guides/config-file', + to: '/docs/guides/config-files', + }, // MCP tutorial redirects - moved from /docs/tutorials/ to /docs/mcp/ { from: '/docs/tutorials/agentql-mcp', From 0e9225e464f4011ea1203ae20d7b6449d801a691 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Wed, 29 Oct 2025 17:05:59 -0400 Subject: [PATCH 019/121] feat(mcp): support sampling in a scoped way (#5367) Signed-off-by: fbalicchia --- crates/goose/src/agents/agent.rs | 10 +- crates/goose/src/agents/extension_manager.rs | 34 ++++-- crates/goose/src/agents/mcp_client.rs | 107 ++++++++++++++++-- crates/goose/src/agents/types.rs | 4 + crates/goose/tests/mcp_integration_test.rs | 3 +- ...iet-pgoose-server--bingoosed--mcpdeveloper | 2 +- .../tests/mcp_replays/github-mcp-serverstdio | 2 +- ...x-y@modelcontextprotocol_server-everything | 2 +- .../tests/mcp_replays/uvxmcp-server-fetch | 2 +- 9 files changed, 136 insertions(+), 30 deletions(-) diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 8dc45289c39a..461843f4447f 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -28,7 +28,7 @@ use crate::agents::subagent_execution_tool::tasks_manager::TasksManager; use crate::agents::tool_route_manager::ToolRouteManager; use crate::agents::tool_router_index_manager::ToolRouterIndexManager; use crate::agents::types::SessionConfig; -use crate::agents::types::{FrontendTool, ToolResultReceiver}; +use crate::agents::types::{FrontendTool, SharedProvider, ToolResultReceiver}; use crate::config::{get_enabled_extensions, Config}; use crate::context_mgmt::DEFAULT_COMPACTION_THRESHOLD; use crate::conversation::{debug_conversation_fix, fix_conversation, Conversation}; @@ -86,7 +86,8 @@ pub struct ToolCategorizeResult { /// The main goose Agent pub struct Agent { - pub(super) provider: Mutex>>, + pub(super) provider: SharedProvider, + pub extension_manager: Arc, pub(super) sub_recipe_manager: Mutex, pub(super) tasks_manager: TasksManager, @@ -159,10 +160,11 @@ impl Agent { // Create channels with buffer size 32 (adjust if needed) let (confirm_tx, confirm_rx) = mpsc::channel(32); let (tool_tx, tool_rx) = mpsc::channel(32); + let provider = Arc::new(Mutex::new(None)); Self { - provider: Mutex::new(None), - extension_manager: Arc::new(ExtensionManager::new()), + provider: provider.clone(), + extension_manager: Arc::new(ExtensionManager::new(provider.clone())), sub_recipe_manager: Mutex::new(SubRecipeManager::new()), tasks_manager: TasksManager::new(), final_output_tool: Arc::new(Mutex::new(None)), diff --git a/crates/goose/src/agents/extension_manager.rs b/crates/goose/src/agents/extension_manager.rs index 7eaa2ea8bde2..fcea45250c88 100644 --- a/crates/goose/src/agents/extension_manager.rs +++ b/crates/goose/src/agents/extension_manager.rs @@ -12,6 +12,7 @@ use rmcp::transport::{ TokioChildProcess, }; use std::collections::HashMap; +use std::option::Option; use std::process::Stdio; use std::sync::Arc; use std::time::Duration; @@ -29,6 +30,7 @@ use super::extension::{ ToolInfo, PLATFORM_EXTENSIONS, }; use super::tool_execution::ToolCallResult; +use super::types::SharedProvider; use crate::agents::extension::{Envs, ProcessExit}; use crate::agents::extension_malware_check; use crate::agents::mcp_client::{McpClient, McpClientTrait}; @@ -91,6 +93,7 @@ impl Extension { pub struct ExtensionManager { extensions: Mutex>, context: Mutex, + provider: SharedProvider, } /// A flattened representation of a resource used by the agent to prepare inference @@ -171,13 +174,14 @@ pub fn get_parameter_names(tool: &Tool) -> Vec { impl Default for ExtensionManager { fn default() -> Self { - Self::new() + Self::new(Arc::new(Mutex::new(None))) } } async fn child_process_client( mut command: Command, timeout: &Option, + provider: SharedProvider, ) -> ExtensionResult { #[cfg(unix)] command.process_group(0); @@ -205,6 +209,7 @@ async fn child_process_client( let client_result = McpClient::connect( transport, Duration::from_secs(timeout.unwrap_or(crate::config::DEFAULT_EXTENSION_TIMEOUT)), + provider, ) .await; @@ -243,7 +248,7 @@ fn extract_auth_error( } impl ExtensionManager { - pub fn new() -> Self { + pub fn new(provider: SharedProvider) -> Self { Self { extensions: Mutex::new(HashMap::new()), context: Mutex::new(PlatformExtensionContext { @@ -251,9 +256,15 @@ impl ExtensionManager { extension_manager: None, tool_route_manager: None, }), + provider, } } + /// Create a new ExtensionManager with no provider (useful for tests) + pub fn new_without_provider() -> Self { + Self::new(Arc::new(Mutex::new(None))) + } + pub async fn set_context(&self, context: PlatformExtensionContext) { *self.context.lock().await = context; } @@ -348,6 +359,7 @@ impl ExtensionManager { Duration::from_secs( timeout.unwrap_or(crate::config::DEFAULT_EXTENSION_TIMEOUT), ), + self.provider.clone(), ) .await?, ) @@ -388,6 +400,7 @@ impl ExtensionManager { Duration::from_secs( timeout.unwrap_or(crate::config::DEFAULT_EXTENSION_TIMEOUT), ), + self.provider.clone(), ) .await; let client = if let Some(_auth_error) = extract_auth_error(&client_res) { @@ -407,6 +420,7 @@ impl ExtensionManager { Duration::from_secs( timeout.unwrap_or(crate::config::DEFAULT_EXTENSION_TIMEOUT), ), + self.provider.clone(), ) .await? } else { @@ -430,7 +444,7 @@ impl ExtensionManager { // Check for malicious packages before launching the process extension_malware_check::deny_if_malicious_cmd_args(cmd, args).await?; - let client = child_process_client(command, timeout).await?; + let client = child_process_client(command, timeout, self.provider.clone()).await?; Box::new(client) } ExtensionConfig::Builtin { @@ -459,7 +473,7 @@ impl ExtensionManager { let command = Command::new(cmd).configure(|command| { command.arg("mcp").arg(name); }); - let client = child_process_client(command, timeout).await?; + let client = child_process_client(command, timeout, self.provider.clone()).await?; Box::new(client) } ExtensionConfig::Platform { name, .. } => { @@ -495,7 +509,7 @@ impl ExtensionManager { command.arg("python").arg(file_path.to_str().unwrap()); }); - let client = child_process_client(command, timeout).await?; + let client = child_process_client(command, timeout, self.provider.clone()).await?; Box::new(client) } @@ -1252,7 +1266,7 @@ mod tests { #[tokio::test] async fn test_get_client_for_tool() { - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); // Add some mock clients using the helper method extension_manager @@ -1312,7 +1326,7 @@ mod tests { async fn test_dispatch_tool_call() { // test that dispatch_tool_call parses out the sanitized name correctly, and extracts // tool_names - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); // Add some mock clients using the helper method extension_manager @@ -1429,7 +1443,7 @@ mod tests { #[tokio::test] async fn test_tool_availability_filtering() { - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); // Only "available_tool" should be available to the LLM let available_tools = vec!["available_tool".to_string()]; @@ -1457,7 +1471,7 @@ mod tests { #[tokio::test] async fn test_tool_availability_defaults_to_available() { - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); extension_manager .add_mock_extension_with_tools( @@ -1482,7 +1496,7 @@ mod tests { #[tokio::test] async fn test_dispatch_unavailable_tool_returns_error() { - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); let available_tools = vec!["available_tool".to_string()]; diff --git a/crates/goose/src/agents/mcp_client.rs b/crates/goose/src/agents/mcp_client.rs index a166b8f7bec2..88c017a2e402 100644 --- a/crates/goose/src/agents/mcp_client.rs +++ b/crates/goose/src/agents/mcp_client.rs @@ -1,21 +1,24 @@ -use rmcp::model::JsonObject; +use crate::agents::types::SharedProvider; +use rmcp::model::{Content, ErrorCode, JsonObject}; /// MCP client implementation for Goose use rmcp::{ model::{ CallToolRequest, CallToolRequestParam, CallToolResult, CancelledNotification, CancelledNotificationMethod, CancelledNotificationParam, ClientCapabilities, ClientInfo, - ClientRequest, GetPromptRequest, GetPromptRequestParam, GetPromptResult, Implementation, - InitializeResult, ListPromptsRequest, ListPromptsResult, ListResourcesRequest, - ListResourcesResult, ListToolsRequest, ListToolsResult, LoggingMessageNotification, + ClientRequest, CreateMessageRequestParam, CreateMessageResult, GetPromptRequest, + GetPromptRequestParam, GetPromptResult, Implementation, InitializeResult, + ListPromptsRequest, ListPromptsResult, ListResourcesRequest, ListResourcesResult, + ListToolsRequest, ListToolsResult, LoggingMessageNotification, LoggingMessageNotificationMethod, PaginatedRequestParam, ProgressNotification, ProgressNotificationMethod, ProtocolVersion, ReadResourceRequest, ReadResourceRequestParam, - ReadResourceResult, RequestId, ServerNotification, ServerResult, + ReadResourceResult, RequestId, Role, SamplingMessage, ServerNotification, ServerResult, }, service::{ - ClientInitializeError, PeerRequestOptions, RequestHandle, RunningService, ServiceRole, + ClientInitializeError, PeerRequestOptions, RequestContext, RequestHandle, RunningService, + ServiceRole, }, transport::IntoTransport, - ClientHandler, Peer, RoleClient, ServiceError, ServiceExt, + ClientHandler, ErrorData, Peer, RoleClient, ServiceError, ServiceExt, }; use serde_json::Value; use std::{sync::Arc, time::Duration}; @@ -76,12 +79,17 @@ pub trait McpClientTrait: Send + Sync { pub struct GooseClient { notification_handlers: Arc>>>, + provider: SharedProvider, } impl GooseClient { - pub fn new(handlers: Arc>>>) -> Self { + pub fn new( + handlers: Arc>>>, + provider: SharedProvider, + ) -> Self { GooseClient { notification_handlers: handlers, + provider, } } } @@ -127,10 +135,88 @@ impl ClientHandler for GooseClient { }); } + async fn create_message( + &self, + params: CreateMessageRequestParam, + _context: RequestContext, + ) -> Result { + let provider = self + .provider + .lock() + .await + .as_ref() + .ok_or(ErrorData::new( + ErrorCode::INTERNAL_ERROR, + "Could not use provider", + None, + ))? + .clone(); + + let provider_ready_messages: Vec = params + .messages + .iter() + .map(|msg| { + let base = match msg.role { + Role::User => crate::conversation::message::Message::user(), + Role::Assistant => crate::conversation::message::Message::assistant(), + }; + + match msg.content.as_text() { + Some(text) => base.with_text(&text.text), + None => base.with_content(msg.content.clone().into()), + } + }) + .collect(); + + let system_prompt = params + .system_prompt + .as_deref() + .unwrap_or("You are a general-purpose AI agent called goose"); + + let (response, usage) = provider + .complete(system_prompt, &provider_ready_messages, &[]) + .await + .map_err(|e| { + ErrorData::new( + ErrorCode::INTERNAL_ERROR, + "Unexpected error while completing the prompt", + Some(Value::from(e.to_string())), + ) + })?; + + Ok(CreateMessageResult { + model: usage.model, + stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.to_string()), + message: SamplingMessage { + role: Role::Assistant, + // TODO(alexhancock): MCP sampling currently only supports one content on each SamplingMessage + // https://modelcontextprotocol.io/specification/draft/client/sampling#messages + // This doesn't mesh well with goose's approach which has Vec + // There is a proposal to MCP which is agreed to go in the next version to have SamplingMessages support multiple content parts + // https://github.com/modelcontextprotocol/modelcontextprotocol/pull/198 + // Until that is formalized, we can take the first message content from the provider and use it + content: if let Some(content) = response.content.first() { + match content { + crate::conversation::message::MessageContent::Text(text) => { + Content::text(&text.text) + } + crate::conversation::message::MessageContent::Image(img) => { + Content::image(&img.data, &img.mime_type) + } + // TODO(alexhancock) - Content::Audio? goose's messages don't currently have it + _ => Content::text(""), + } + } else { + Content::text("") + }, + }, + }) + } + fn get_info(&self) -> ClientInfo { ClientInfo { protocol_version: ProtocolVersion::V_2025_03_26, - capabilities: ClientCapabilities::builder().build(), + capabilities: ClientCapabilities::builder().enable_sampling().build(), client_info: Implementation { name: "goose".to_string(), version: std::env::var("GOOSE_MCP_CLIENT_VERSION") @@ -155,6 +241,7 @@ impl McpClient { pub async fn connect( transport: T, timeout: std::time::Duration, + provider: SharedProvider, ) -> Result where T: IntoTransport, @@ -163,7 +250,7 @@ impl McpClient { let notification_subscribers = Arc::new(Mutex::new(Vec::>::new())); - let client = GooseClient::new(notification_subscribers.clone()); + let client = GooseClient::new(notification_subscribers.clone(), provider); let client: rmcp::service::RunningService = client.serve(transport).await?; let server_info = client.peer_info().cloned(); diff --git a/crates/goose/src/agents/types.rs b/crates/goose/src/agents/types.rs index 0518c65789b3..027560179b2a 100644 --- a/crates/goose/src/agents/types.rs +++ b/crates/goose/src/agents/types.rs @@ -1,4 +1,5 @@ use crate::mcp_utils::ToolResult; +use crate::providers::base::Provider; use rmcp::model::{Content, Tool}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -9,6 +10,9 @@ use utoipa::ToSchema; /// Type alias for the tool result channel receiver pub type ToolResultReceiver = Arc>)>>>; +// We use double Arc here to allow easy provider swaps while sharing concurrent access +pub type SharedProvider = Arc>>>; + /// Default timeout for retry operations (5 minutes) pub const DEFAULT_RETRY_TIMEOUT_SECONDS: u64 = 300; diff --git a/crates/goose/tests/mcp_integration_test.rs b/crates/goose/tests/mcp_integration_test.rs index 9182735a5863..6704119e638b 100644 --- a/crates/goose/tests/mcp_integration_test.rs +++ b/crates/goose/tests/mcp_integration_test.rs @@ -205,8 +205,7 @@ async fn test_replayed_session( bundled: Some(false), available_tools: vec![], }; - - let extension_manager = ExtensionManager::new(); + let extension_manager = ExtensionManager::new_without_provider(); #[allow(clippy::redundant_closure_call)] let result = (async || -> Result<(), Box> { diff --git a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper index b8b5c12a217b..c5b490b065f4 100644 --- a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper +++ b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper @@ -1,4 +1,4 @@ -STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"goose","version":"0.0.0"}}} +STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} STDERR: 2025-09-27T04:13:30.409389Z  INFO goose_mcp::mcp_server_runner: Starting MCP server STDERR: at crates/goose-mcp/src/mcp_server_runner.rs:18 STDERR: diff --git a/crates/goose/tests/mcp_replays/github-mcp-serverstdio b/crates/goose/tests/mcp_replays/github-mcp-serverstdio index e7f70639287c..f38a2473b14a 100644 --- a/crates/goose/tests/mcp_replays/github-mcp-serverstdio +++ b/crates/goose/tests/mcp_replays/github-mcp-serverstdio @@ -1,4 +1,4 @@ -STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"goose","version":"0.0.0"}}} +STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} STDERR: GitHub MCP Server running on stdio STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"logging":{},"prompts":{},"resources":{"subscribe":true,"listChanged":true},"tools":{"listChanged":true}},"serverInfo":{"name":"github-mcp-server","version":"version"}}} STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"} diff --git a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything index 4fbb74482a5d..8ac4f0843488 100644 --- a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything +++ b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything @@ -1,4 +1,4 @@ -STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"goose","version":"0.0.0"}}} +STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} STDERR: 2025-09-26 23:13:04 - Starting npx setup script. STDERR: 2025-09-26 23:13:04 - Creating directory ~/.config/goose/mcp-hermit/bin if it does not exist. STDERR: 2025-09-26 23:13:04 - Changing to directory ~/.config/goose/mcp-hermit. diff --git a/crates/goose/tests/mcp_replays/uvxmcp-server-fetch b/crates/goose/tests/mcp_replays/uvxmcp-server-fetch index 7362e657a902..a473f29fa8eb 100644 --- a/crates/goose/tests/mcp_replays/uvxmcp-server-fetch +++ b/crates/goose/tests/mcp_replays/uvxmcp-server-fetch @@ -1,4 +1,4 @@ -STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"goose","version":"0.0.0"}}} +STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} STDERR: 2025-09-26 23:13:04 - Starting uvx setup script. STDERR: 2025-09-26 23:13:04 - Creating directory ~/.config/goose/mcp-hermit/bin if it does not exist. STDERR: 2025-09-26 23:13:04 - Changing to directory ~/.config/goose/mcp-hermit. From 3f306d68dcb855f0f7b956c4a717eb20ee55c8d3 Mon Sep 17 00:00:00 2001 From: Dakshata Mishra <22-783@apsdhaulakuan.onmicrosoft.com> Date: Thu, 30 Oct 2025 02:37:49 +0530 Subject: [PATCH 020/121] Add CSV File Merger recipe (#5455) Signed-off-by: Dakshata <22-783@apsdhaulakuan.onmicrosoft.com> Signed-off-by: fbalicchia --- .../recipes/data/recipes/csv-file-merger.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 documentation/src/pages/recipes/data/recipes/csv-file-merger.yaml diff --git a/documentation/src/pages/recipes/data/recipes/csv-file-merger.yaml b/documentation/src/pages/recipes/data/recipes/csv-file-merger.yaml new file mode 100644 index 000000000000..2e46e1123324 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/csv-file-merger.yaml @@ -0,0 +1,65 @@ +version: 1.0.0 +title: CSV File Merger +author: + contact: the-matrixneo +description: "Combines multiple CSV files from a directory into a single master file." +instructions: | + 1. Provide the path to the directory containing your CSV files. + 2. Specify the desired name for the final merged output file. + 3. The recipe will scan the directory and merge all found CSV files. + 4. It will check for header consistency across the files. + 5. Your new, combined file will be saved in the same directory. + +activities: + - Validate the input directory path. + - Scan for and identify all CSV files within the directory. + - Check for header consistency across all files. + - Merge the data from all identified files. + - Generate the final, single CSV file. + +parameters: + - key: directory_path + input_type: string + requirement: required + description: "Path to the folder containing the CSV files you want to merge." + + - key: output_filename + input_type: string + requirement: required + description: "Name for the final merged CSV file." + default: "merged_output.csv" + + - key: header_check + input_type: string + requirement: optional + description: "How to handle differing headers ('strict' to fail, 'flexible' to merge common columns)." + default: "strict" + choices: + - "strict" + - "flexible" + +extensions: + - type: builtin + name: developer + display_name: Developer + timeout: 300 + bundled: true + description: "Orchestrates the merging logic and performs the in-memory data processing to combine the CSVs." + + - type: stdio + name: filesystem + cmd: npx + args: + - -y + - "@modelcontextprotocol/server-filesystem" + - "{{ directory_path }}" + timeout: 300 + description: "Handles all direct filesystem operations." +prompt: | + You are a CSV merging assistant. + 1. First, validate that the directory at {{ directory_path }} exists. If not, inform the user and stop. + 2. Scan the directory for all files ending with ".csv". If none are found, report it and stop. + 3. Based on the {{ header_check }} parameter, verify the headers. If 'strict' and headers mismatch, list the inconsistent files and stop. If 'flexible', proceed by merging only common columns. + 4. Read each CSV file and append its contents into a single dataset. + 5. Save the combined dataset to a new file named {{ output_filename }} in the original directory. + 6. Provide a summary of the operation. From a7d007f78c2c70b2554940f08915ef90f3db8395 Mon Sep 17 00:00:00 2001 From: Dakshata Mishra <22-783@apsdhaulakuan.onmicrosoft.com> Date: Thu, 30 Oct 2025 02:38:30 +0530 Subject: [PATCH 021/121] Add Goose with Neon MCP submission (#5454) Signed-off-by: Dakshata <22-783@apsdhaulakuan.onmicrosoft.com> Signed-off-by: fbalicchia --- .../community/data/community-content.json | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 0b6b67ac602a..0debddb03b41 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -15,11 +15,7 @@ "url": "https://block.github.io/goose/blog/2025/09/26/hacktoberfest-2025", "thumbnail": "https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-09-26", - "tags": [ - "hacktoberfest", - "open-source", - "contributing" - ], + "tags": ["hacktoberfest", "open-source", "contributing"], "hacktoberfest": true }, { @@ -32,9 +28,7 @@ "url": "https://dev.to/agasta/running-goose-in-containers-without-losing-your-mind-3m8", "thumbnail": "https://images.unsplash.com/photo-1759560397953-8221761119ec?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-10-04", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -46,9 +40,7 @@ "type": "video", "url": "https://www.youtube.com/shorts/Qidl20e-HOc", "submittedDate": "2025-10-13", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -60,11 +52,7 @@ "type": "blog", "url": "https://anudhyan.hashnode.dev/best-practices-for-using-goose-in-enterprise-environments", "submittedDate": "2025-10-15", - "tags": [ - "hacktoberfest", - "goose", - "enterprise" - ], + "tags": ["hacktoberfest", "goose", "enterprise"], "hacktoberfest": true }, { @@ -77,9 +65,7 @@ "url": "https://dev.to/lymah/getting-started-with-goose-on-windows-30bh", "thumbnail": "https://i.imgur.com/WEZXcBD.png", "submittedDate": "2025-10-14", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -92,9 +78,7 @@ "url": "https://dev.to/lymah/best-practices-for-prompt-engineering-with-goose-3m6h", "thumbnail": "https://i.imgur.com/Shsi56O.png", "submittedDate": "2025-10-16", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -107,9 +91,7 @@ "url": "https://dev.to/lymah/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl", "thumbnail": "https://i.imgur.com/uim8eHi.png", "submittedDate": "2025-10-21", - "tags": [ - "hacktoberfest" - ], + "tags": ["hacktoberfest"], "hacktoberfest": true }, { @@ -199,6 +181,18 @@ "submittedDate": "2025-10-29", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Goose with Neon MCP", + "author": { + "name": "Dakshata Mishra", + "handle": "the-matrixneo" + }, + "type": "video", + "url": "https://www.youtube.com/shorts/IxUPo2QDg_8", + "submittedDate": "2025-10-29", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] -} \ No newline at end of file +} From 54db894b5325cc00c230a85e61930620e3061c12 Mon Sep 17 00:00:00 2001 From: Better-Boy Date: Thu, 30 Oct 2025 02:49:37 +0530 Subject: [PATCH 022/121] technical debt tracker recipe (#5451) Signed-off-by: Better-Boy Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: fbalicchia --- .../subrecipes/complexity-analysis.yaml | 52 ++++++++ .../subrecipes/dependency-analysis.yaml | 69 +++++++++++ .../subrecipes/documentation-analysis.yaml | 69 +++++++++++ .../subrecipes/duplication-detection.yaml | 66 ++++++++++ .../subrecipes/test-coverage-analysis.yaml | 54 ++++++++ .../data/recipes/technical-debt-tracker.yaml | 115 ++++++++++++++++++ 6 files changed, 425 insertions(+) create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/complexity-analysis.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/dependency-analysis.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/documentation-analysis.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/duplication-detection.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/test-coverage-analysis.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/technical-debt-tracker.yaml diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/complexity-analysis.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/complexity-analysis.yaml new file mode 100644 index 000000000000..ba528c473785 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/complexity-analysis.yaml @@ -0,0 +1,52 @@ +version: 1.0.0 +title: "Code Complexity Analyzer" +description: "Analyzes cyclomatic complexity and identifies overly complex functions and classes" +instructions: | + You are analyzing code complexity to identify technical debt. + + Your tasks: + 1. Scan all source code files in {{ repository_path }} + 2. Calculate cyclomatic complexity for functions, methods, and classes + 3. Identify code that exceeds the complexity threshold of {{ complexity_threshold }} + 4. Look for: + - Long functions (>50 lines) + - Deep nesting levels (>4 levels) + - High parameter counts (>5 parameters) + - Large classes (>500 lines) + + 5. For each complex item found, provide: + - File path and line number + - Current complexity score + - Brief explanation of why it's complex + - Suggested refactoring approach + + Return results in a structured format with severity levels: + - Critical: Complexity > 2x threshold + - High: Complexity > 1.5x threshold + - Medium: Complexity > threshold + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository" + + - key: complexity_threshold + input_type: number + requirement: optional + default: 15 + description: "Cyclomatic complexity threshold" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +settings: + temperature: 0.2 + +prompt: | + Analyze code complexity in {{ repository_path }}. + Flag any function/method with cyclomatic complexity > {{ complexity_threshold }}. + Provide specific file paths, line numbers, and refactoring recommendations. \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/dependency-analysis.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/dependency-analysis.yaml new file mode 100644 index 000000000000..63dd8dc0c03f --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/dependency-analysis.yaml @@ -0,0 +1,69 @@ +version: 1.0.0 +title: "Dependency Health Analyzer" +description: "Analyzes dependencies for outdated versions, vulnerabilities, and maintenance issues" +instructions: | + You are analyzing project dependencies to identify security and maintenance risks. + + Your tasks: + 1. Locate dependency files: + - package.json / package-lock.json (Node.js) + - requirements.txt / Pipfile (Python) + - pom.xml / build.gradle (Java) + - Gemfile / Gemfile.lock (Ruby) + - go.mod (Go) + - Cargo.toml (Rust) + + 2. For each dependency, check: + - Current version vs latest stable version + - Last update date + - Known security vulnerabilities (CVEs) + - Maintenance status (archived, deprecated) + - License compatibility + + 3. Flag dependencies that are: + - Critical: Known security vulnerabilities + - High: Outdated by >{{ max_age_days }} days or deprecated + - Medium: Minor updates available + - Low: Patch updates available + + 4. Identify: + - Unused dependencies that can be removed + - Duplicate dependencies + - Heavy dependencies that could be replaced + - Missing security patches + + 5. Provide upgrade recommendations with potential breaking changes noted. + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository" + + - key: max_age_days + input_type: number + requirement: optional + default: 365 + description: "Flag dependencies older than this many days" + + - key: check_vulnerabilities + input_type: string + requirement: optional + default: "true" + description: "Whether to check for known vulnerabilities" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +settings: + temperature: 0.2 + +prompt: | + Analyze dependencies in {{ repository_path }}. + Check for vulnerabilities: {{ check_vulnerabilities }} + Flag dependencies older than {{ max_age_days }} days. + + Provide specific upgrade recommendations prioritized by security impact. \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/documentation-analysis.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/documentation-analysis.yaml new file mode 100644 index 000000000000..970779f19cdf --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/documentation-analysis.yaml @@ -0,0 +1,69 @@ +version: 1.0.0 +title: "Documentation Quality Analyzer" +description: "Identifies missing, outdated, or inadequate documentation" +instructions: | + You are analyzing documentation quality to identify gaps and issues. + + Your tasks: + 1. Check for essential documentation: + - README.md with setup/usage instructions + - CONTRIBUTING.md for contributor guidelines + - API documentation for public interfaces + - Architecture/design documents + - Inline code comments for complex logic + + 2. Analyze existing documentation for: + - Completeness - are all public APIs documented? + - Accuracy - does code match documentation? + - Clarity - is it easy to understand? + - Examples - are there usage examples? + - Maintenance - is it up to date? + + 3. Identify specific gaps: + - Undocumented public functions/classes + - Complex code without explanatory comments + - Missing setup/installation instructions + - Absence of examples or tutorials + - Outdated documentation (check git history) + + 4. Prioritize documentation tasks: + - Critical: Public APIs with no documentation + - High: Complex code without comments + - Medium: Missing examples/tutorials + - Low: Incomplete inline comments + + Provide specific file paths and function signatures that need documentation. + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository" + + - key: check_readme + input_type: string + requirement: optional + default: "true" + description: "Whether to check README quality" + + - key: check_api_docs + input_type: string + requirement: optional + default: "true" + description: "Whether to check API documentation" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +settings: + temperature: 0.3 + +prompt: | + Analyze documentation in {{ repository_path }}. + Check README quality: {{ check_readme }} + Check API docs: {{ check_api_docs }} + + Identify missing or inadequate documentation and provide specific recommendations. \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/duplication-detection.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/duplication-detection.yaml new file mode 100644 index 000000000000..9837ff927262 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/duplication-detection.yaml @@ -0,0 +1,66 @@ +version: 1.0.0 +title: "Code Duplication Detector" +description: "Identifies duplicated code blocks that should be refactored into reusable components" +instructions: | + You are analyzing code for duplication to identify refactoring opportunities. + + Your tasks: + 1. Scan all source code files in {{ repository_path }} + 2. Identify duplicated code blocks: + - Similar functions/methods (>{{ similarity_threshold }} similarity) + - Copy-pasted code sections (>{{ min_lines }} lines) + - Repeated patterns and logic + - Similar class structures + + 3. For each duplication found: + - Show both/all locations (file paths and line numbers) + - Calculate similarity percentage + - Estimate lines of duplicated code + - Assess refactoring complexity + + 4. Suggest refactoring strategies: + - Extract common functions/utilities + - Create base classes or mixins + - Use composition or inheritance + - Apply design patterns (Strategy, Template Method, etc.) + + 5. Prioritize by impact: + - Critical: >100 lines duplicated, appears 3+ times + - High: >50 lines duplicated, appears 2+ times + - Medium: >20 lines duplicated + - Low: Minor code similarities + + Focus on duplications that will provide the most maintenance benefit when refactored. + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository" + + - key: min_lines + input_type: number + requirement: optional + default: 10 + description: "Minimum lines for a code block to be considered duplicate" + + - key: similarity_threshold + input_type: number + requirement: optional + default: 0.85 + description: "Similarity threshold (0.0-1.0) for detecting duplicates" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +settings: + temperature: 0.2 + +prompt: | + Detect code duplication in {{ repository_path }}. + Find blocks >{{ min_lines }} lines with >{{ similarity_threshold }} similarity. + + Provide specific locations and refactoring recommendations for each duplication. \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/test-coverage-analysis.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/test-coverage-analysis.yaml new file mode 100644 index 000000000000..31bd6e8a66bf --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/test-coverage-analysis.yaml @@ -0,0 +1,54 @@ +version: 1.0.0 +title: "Test Coverage Analyzer" +description: "Identifies code with insufficient test coverage and missing test cases" +instructions: | + You are analyzing test coverage to identify untested code. + + Your tasks: + 1. Locate test files and test frameworks used (Jest, pytest, JUnit, etc.) + 2. Identify the test coverage reporting mechanism if available + 3. Analyze which parts of the codebase lack tests: + - Public APIs and exported functions + - Critical business logic + - Error handling paths + - Edge cases + + 4. For each file/module below {{ min_coverage }}% coverage: + - Calculate estimated current coverage + - Identify specific untested functions/methods + - Prioritize based on code criticality + - Suggest test cases that should be added + + 5. Check for: + - Missing unit tests + - Missing integration tests + - Missing error case tests + - Flaky or skipped tests + + Focus on high-value areas where tests would most improve reliability. + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository" + + - key: min_coverage + input_type: number + requirement: optional + default: 80 + description: "Minimum acceptable test coverage percentage" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +settings: + temperature: 0.2 + +prompt: | + Analyze test coverage in {{ repository_path }}. + Identify code with coverage below {{ min_coverage }}%. + Prioritize critical paths that lack tests and recommend specific test cases to add. \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/technical-debt-tracker.yaml b/documentation/src/pages/recipes/data/recipes/technical-debt-tracker.yaml new file mode 100644 index 000000000000..d6ab35e0c005 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/technical-debt-tracker.yaml @@ -0,0 +1,115 @@ +version: 1.0.0 +title: "Technical Debt Tracker" +description: "Comprehensive analysis of technical debt in a code repository including complexity, test coverage, documentation, dependencies, and code duplication" +author: + contact: Better-Boy + +instructions: | + You are a senior software engineer conducting a comprehensive technical debt analysis. + + Your workflow: + 1. First, examine the repository structure at {{ repository_path }} to understand the project + 2. Identify the primary programming language(s) and frameworks used + 3. Run each sub-recipe to gather specific technical debt metrics: + - complexity_analyzer: Identify complex code that needs refactoring + - test_coverage_analyzer: Find untested or poorly tested code + - documentation_analyzer: Identify missing or outdated documentation + - dependency_analyzer: Check for outdated or vulnerable dependencies + - duplication_detector: Find duplicated code that should be refactored + + 4. After all analyses complete, create a consolidated report that: + - Prioritizes issues by severity (Critical, High, Medium, Low) + - Groups related issues together + - Provides actionable recommendations with estimated effort + - Creates a technical debt reduction roadmap + + 5. Save the report as {{ output_file }} in markdown format + + Be thorough but focused on issues that will have the most impact on code quality and maintainability. + +parameters: + - key: repository_path + input_type: string + requirement: required + description: "Path to the code repository to analyze" + + - key: output_file + input_type: string + requirement: optional + default: "technical-debt-report.md" + description: "Output file name for the technical debt report" + + - key: complexity_threshold + input_type: number + requirement: optional + default: 15 + description: "Cyclomatic complexity threshold (functions above this are flagged)" + + - key: min_test_coverage + input_type: number + requirement: optional + default: 80 + description: "Minimum acceptable test coverage percentage" + + - key: max_dependency_age_days + input_type: number + requirement: optional + default: 365 + description: "Flag dependencies older than this many days" + +sub_recipes: + - name: "complexity_analyzer" + path: "./subrecipes/complexity-analysis.yaml" + values: + complexity_threshold: "{{ complexity_threshold }}" + + - name: "test_coverage_analyzer" + path: "./subrecipes/test-coverage-analysis.yaml" + values: + min_coverage: "{{ min_test_coverage }}" + + - name: "documentation_analyzer" + path: "./subrecipes/documentation-analysis.yaml" + values: + check_readme: "true" + check_api_docs: "true" + + - name: "dependency_analyzer" + path: "./subrecipes/dependency-analysis.yaml" + values: + max_age_days: "{{ max_dependency_age_days }}" + check_vulnerabilities: "true" + + - name: "duplication_detector" + path: "./subrecipes/duplication-detection.yaml" + values: + min_lines: "10" + similarity_threshold: "0.85" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + description: "File system and code analysis tools" + +prompt: | + Analyze the code repository at {{ repository_path }} for technical debt. + + Run a comprehensive analysis covering: + - Code complexity and maintainability + - Test coverage gaps + - Documentation quality + - Dependency health and security + - Code duplication + + Create a prioritized technical debt report and save it to {{ output_file }}. + +activities: + - "Scan repository structure" + - "Analyze code complexity" + - "Check test coverage" + - "Review documentation" + - "Audit dependencies" + - "Detect code duplication" + - "Generate prioritized report" \ No newline at end of file From bf0028a593aba9612af538f316d1825447bcb405 Mon Sep 17 00:00:00 2001 From: Better-Boy Date: Thu, 30 Oct 2025 02:54:22 +0530 Subject: [PATCH 023/121] openapi to locust load test generator recipe (#5447) Signed-off-by: Better-Boy Signed-off-by: fbalicchia --- .../data/recipes/openapi-to-locust.yaml | 93 ++++++++++ .../recipes/subrecipes/analyze-openapi.yaml | 71 ++++++++ .../subrecipes/generate-locustfile.yaml | 111 ++++++++++++ .../subrecipes/generate-support-files.yaml | 168 ++++++++++++++++++ .../subrecipes/generate-task-sets.yaml | 100 +++++++++++ 5 files changed, 543 insertions(+) create mode 100644 documentation/src/pages/recipes/data/recipes/openapi-to-locust.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/analyze-openapi.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/generate-locustfile.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/generate-support-files.yaml create mode 100644 documentation/src/pages/recipes/data/recipes/subrecipes/generate-task-sets.yaml diff --git a/documentation/src/pages/recipes/data/recipes/openapi-to-locust.yaml b/documentation/src/pages/recipes/data/recipes/openapi-to-locust.yaml new file mode 100644 index 000000000000..49e9beb46170 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/openapi-to-locust.yaml @@ -0,0 +1,93 @@ +version: "1.0.0" +title: "OpenAPI to Locust Load Test Generator" +description: "Generate comprehensive Locust load tests from OpenAPI/Swagger specifications" +author: + contact: Better-Boy + +instructions: | + You are an expert in API testing and load testing with Locust. + Your task is to generate production-ready Locust load test files from OpenAPI specifications. + + Follow this workflow: + 1. First, analyze the OpenAPI spec to understand the API structure + 2. Generate Locust task sets for different endpoint groups + 3. Create the main locustfile with proper configuration + 4. Generate supporting files (requirements.txt, README, config) + + Ensure the generated tests are: + - Well-structured with proper task weighting + - Include realistic user behavior patterns + - Have proper error handling and assertions + - Use parameterized data where appropriate + - Follow Locust best practices + +parameters: + - key: openapi_spec_path + input_type: string + requirement: required + description: "Path to the OpenAPI specification file (JSON or YAML)" + + - key: base_url + input_type: string + requirement: optional + default: "http://localhost:8000" + description: "Base URL for the API to test" + + - key: output_dir + input_type: string + requirement: optional + default: "./load_tests" + description: "Directory where generated test files will be saved" + + - key: test_complexity + input_type: string + requirement: optional + default: "standard" + description: "Test complexity level: basic, standard, or advanced" + + - key: include_auth + input_type: string + requirement: optional + default: "true" + description: "Whether to include authentication handling in tests" + +sub_recipes: + - name: analyze_openapi + path: "./subrecipes/analyze-openapi.yaml" + values: + analysis_depth: "comprehensive" + + - name: generate_task_sets + path: "./subrecipes/generate-task-sets.yaml" + + - name: generate_locustfile + path: "./subrecipes/generate-locustfile.yaml" + + - name: generate_support_files + path: "./subrecipes/generate-support-files.yaml" + +extensions: + - type: builtin + name: developer + timeout: 600 + bundled: true + +prompt: | + Generate complete Locust load tests from the OpenAPI specification at {{ openapi_spec_path }}. + + Configuration: + - Base URL: {{ base_url }} + - Output directory: {{ output_dir }} + - Test complexity: {{ test_complexity }} + - Include authentication: {{ include_auth }} + + Use the sub-recipe tools in this order: + 1. analyze_openapi - Parse and analyze the OpenAPI spec + 2. generate_task_sets - Create Locust TaskSets for endpoint groups + 3. generate_locustfile - Generate the main locustfile.py + 4. generate_support_files - Create requirements.txt, README.md, and config files + + After all subrecipes complete, verify all files were created successfully and provide: + - Summary of generated files + - Instructions for running the tests + - Example commands for different load scenarios \ No newline at end of file diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/analyze-openapi.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/analyze-openapi.yaml new file mode 100644 index 000000000000..3fd108935aed --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/analyze-openapi.yaml @@ -0,0 +1,71 @@ +version: "1.0.0" +title: "OpenAPI Spec Analyzer" +description: "Parse and analyze OpenAPI specification to extract endpoints, schemas, and auth details" +instructions: | + You are an API specification expert. Parse the OpenAPI/Swagger specification file + and extract all relevant information for load test generation. + + Your analysis should include: + - List of all endpoints grouped by tags/categories + - HTTP methods, paths, and parameters for each endpoint + - Request/response schemas and content types + - Authentication and security schemes + - Rate limits and other constraints if defined + + Output Format: + Create a structured analysis with: + 1. API metadata (title, version, description) + 2. Base servers/URLs + 3. Authentication methods used + 4. Endpoint groups with their operations + 5. Common schemas and data models + 6. Recommended test scenarios based on endpoint relationships + +parameters: + - key: output_dir + input_type: string + requirement: required + description: "Output directory" + + - key: openapi_spec_path + input_type: string + requirement: required + description: "Path to the OpenAPI specification file" + + - key: analysis_depth + input_type: string + requirement: optional + default: "standard" + description: "Depth of analysis: basic, standard, or comprehensive" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +prompt: | + Analyze the OpenAPI specification at {{ openapi_spec_path }}. + Perform a {{ analysis_depth }} analysis. + + Steps: + 1. Read and parse the spec file (handle both JSON and YAML formats) + 2. Extract API metadata and server information + 3. Identify all authentication/security schemes + 4. Group endpoints by tags or logical categories + 5. For each endpoint, document: + - HTTP method and path + - Path/query/header parameters + - Request body schema (if applicable) + - Response schemas + - Security requirements + 6. Identify endpoint relationships (e.g., POST /users before GET /users/{id}) + 7. Suggest realistic test scenarios and user flows + + Save the analysis to {{ output_dir }}/analysis.json for use by other sub-recipes. + + Present a summary with: + - Total number of endpoints + - Endpoints grouped by category + - Authentication types used + - Recommended test flow sequences diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/generate-locustfile.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-locustfile.yaml new file mode 100644 index 000000000000..5cc3c4ed3756 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-locustfile.yaml @@ -0,0 +1,111 @@ +version: "1.0.0" +title: "Main Locustfile Generator" +description: "Generate the main locustfile.py that orchestrates all TaskSets" +instructions: | + You are a Locust expert. Create the main locustfile.py that ties together + all the TaskSets and provides the entry point for load testing. + + The main locustfile should: + - Import all TaskSet classes from the tasks directory + - Define HttpUser classes that use the TaskSets + - Configure wait times and user behavior + - Set up authentication and session handling + - Include environment configuration (host, users, spawn rate) + - Add event hooks for setup/teardown and custom stats + - Include command-line argument handling if needed + + Support multiple user types/personas if the API has different access levels + (e.g., AdminUser, RegularUser, GuestUser) + +parameters: + - key: output_dir + input_type: string + requirement: required + description: "Output directory" + + - key: base_url + input_type: string + requirement: required + description: "Base URL for the API" + + - key: include_auth + input_type: string + requirement: required + description: "Whether to include authentication" + + - key: test_complexity + input_type: string + requirement: required + description: "Test complexity level" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +prompt: | + Generate the main locustfile.py that orchestrates the load tests. + + Structure: + ```python + from locust import HttpUser, between, events + import os + from tasks.users_tasks import UsersTaskSet + from tasks.products_tasks import ProductsTaskSet + # ... import other TaskSets + + class APIUser(HttpUser): + wait_time = between(1, 3) + host = "{{ base_url }}" + + tasks = [UsersTaskSet, ProductsTaskSet] # Mix of all TaskSets + + def on_start(self): + """Called when a simulated user starts""" + {% if include_auth == "true" %} + # Perform login and store token + response = self.client.post("/auth/login", json={ + "username": "test_user", + "password": "test_pass" + }) + self.token = response.json().get("token") + self.client.headers.update({"Authorization": f"Bearer {self.token}"}) + {% endif %} + + def on_stop(self): + """Called when a simulated user stops""" + pass + + # Event hooks for custom behavior + @events.test_start.add_listener + def on_test_start(environment, **kwargs): + print("Load test starting...") + + @events.test_stop.add_listener + def on_test_stop(environment, **kwargs): + print("Load test complete!") + ``` + + {% if test_complexity == "advanced" %} + Include multiple user types with different behavior patterns: + - AdminUser: Has access to admin endpoints + - RegularUser: Normal user operations + - ReadOnlyUser: Only GET requests + + Use task distribution weights for realistic traffic patterns. + {% endif %} + + Add configuration for: + - Environment variables for credentials + - Custom headers + - Connection pooling settings + - Request/response hooks for logging + + Save to {{ output_dir }}/locustfile.py + + Also create a .env.example file with placeholder values for: + - API_BASE_URL + - AUTH_USERNAME + - AUTH_PASSWORD + - Any API keys or tokens needed diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/generate-support-files.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-support-files.yaml new file mode 100644 index 000000000000..939beb6a541d --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-support-files.yaml @@ -0,0 +1,168 @@ +version: "1.0.0" +title: "Support Files Generator" +description: "Generate requirements.txt, README.md, configuration files, and helper scripts" +instructions: | + You are a DevOps and documentation expert. Create all supporting files needed + to make the load tests easy to use and maintain. + + Generate the following files: + 1. requirements.txt - All Python dependencies + 2. README.md - Comprehensive documentation + 3. locust.conf - Configuration file for Locust + 4. docker-compose.yml - Optional Docker setup for distributed testing + 5. run_tests.sh - Shell script with example commands + 6. data/ - Sample data files for parameterized tests + 7. .gitignore - Ignore patterns for test artifacts + +parameters: + - key: output_dir + input_type: string + requirement: required + description: "Output directory" + + - key: base_url + input_type: string + requirement: required + description: "Base URL for API" + +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true + +prompt: | + Generate all support files for the Locust load tests. + + 1. Create {{ output_dir }}/requirements.txt: + ``` + locust>=2.15.0 + pyyaml>=6.0 + requests>=2.31.0 + python-dotenv>=1.0.0 + faker>=20.0.0 # For generating realistic test data + ``` + + 2. Create {{ output_dir }}/README.md with: + - Project overview and purpose + - API being tested (from analysis) + - Prerequisites and installation steps + - Configuration instructions + - How to run tests: + * Single machine mode + * Distributed mode (master/workers) + * Headless mode + * Web UI mode + - Example commands for different scenarios: + * Quick smoke test: `locust --headless -u 10 -r 2 -t 1m` + * Stress test: `locust --headless -u 100 -r 10 -t 10m` + * Web UI: `locust --web-port 8089` + - Interpreting results and metrics + - Troubleshooting common issues + - Project structure explanation + + 3. Create {{ output_dir }}/locust.conf: + ```conf + # Locust configuration file + host = {{ base_url }} + users = 100 + spawn-rate = 10 + run-time = 5m + headless = false + web-host = 127.0.0.1 + web-port = 8089 + loglevel = INFO + logfile = locust.log + html = reports/report.html + csv = reports/results + ``` + + 4. Create {{ output_dir }}/run_tests.sh: + ```bash + #!/bin/bash + # Example test execution script + + echo "Starting Locust load tests..." + + # Smoke test (10 users, 1 minute) + if [ "$1" == "smoke" ]; then + locust --headless -u 10 -r 2 -t 1m --html=reports/smoke_test.html + + # Load test (100 users, 10 minutes) + elif [ "$1" == "load" ]; then + locust --headless -u 100 -r 10 -t 10m --html=reports/load_test.html + + # Stress test (500 users, 30 minutes) + elif [ "$1" == "stress" ]; then + locust --headless -u 500 -r 50 -t 30m --html=reports/stress_test.html + + # Web UI mode (default) + else + echo "Starting Locust web UI on http://localhost:8089" + locust + fi + ``` + + 5. Create {{ output_dir }}/.gitignore: + ``` + # Python + __pycache__/ + *.py[cod] + *$py.class + .Python + venv/ + env/ + + # Locust + *.log + reports/ + .env + + # IDE + .vscode/ + .idea/ + ``` + + 6. Create {{ output_dir }}/data/sample_users.json with realistic test data: + ```json + [ + {"username": "user1", "email": "user1@example.com"}, + {"username": "user2", "email": "user2@example.com"} + ] + ``` + + 7. Create {{ output_dir }}/docker-compose.yml for distributed testing: + ```yaml + version: '3' + services: + master: + image: locustio/locust + ports: + - "8089:8089" + volumes: + - ./:/mnt/locust + command: -f /mnt/locust/locustfile.py --master + + worker: + image: locustio/locust + volumes: + - ./:/mnt/locust + command: -f /mnt/locust/locustfile.py --worker --master-host master + deploy: + replicas: 4 + ``` + + 8. Create {{ output_dir }}/pytest.ini for optional integration with pytest: + ```ini + [pytest] + testpaths = tests + python_files = test_*.py + python_functions = test_* + addopts = -v --tb=short + ``` + + Create a reports/ directory structure with a README explaining output files. + + Make all shell scripts executable (chmod +x). + + Provide a summary of all generated files and their purposes. diff --git a/documentation/src/pages/recipes/data/recipes/subrecipes/generate-task-sets.yaml b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-task-sets.yaml new file mode 100644 index 000000000000..4cf99de2a79a --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/subrecipes/generate-task-sets.yaml @@ -0,0 +1,100 @@ +version: "1.0.0" +title: "Locust TaskSet Generator" +description: "Generate Locust TaskSet classes for different API endpoint groups" +instructions: | + You are a Locust performance testing expert. Generate TaskSet classes that + simulate realistic user behavior for different parts of the API. + + For each endpoint group, create a TaskSet that: + - Uses appropriate task weights based on expected traffic patterns + - Includes proper request construction with headers, params, and body + - Handles authentication tokens/sessions + - Validates responses with assertions + - Uses realistic wait times between requests + - Extracts data from responses for subsequent requests (e.g., IDs) + - Includes error handling and logging + + Follow Locust best practices: + - Use @task decorator with weights + - Use self.client for making requests + - Store shared data in self attributes + - Use context managers for setup/teardown if needed + - Add descriptive names for better reporting + +parameters: + - key: output_dir + input_type: string + requirement: required + description: "Directory for output files" + + - key: test_complexity + input_type: string + requirement: optional + default: "standard" + description: "Complexity level for tests" + + - key: include_auth + input_type: string + requirement: required + description: "Whether to include auth handling" + +extensions: + - type: builtin + name: developer + timeout: 600 + bundled: true + +prompt: | + Generate Locust TaskSet classes based on the API analysis. + + Use the analysis data to understand endpoint groups and relationships. + + For each endpoint group (e.g., Users, Products, Orders): + 1. Create a separate TaskSet class + 2. Implement tasks for each endpoint in that group + 3. Set realistic task weights (common operations get higher weights) + 4. Handle data dependencies between requests + + Example structure for each TaskSet: + ```python + from locust import TaskSet, task, between + import json + import random + + class UsersTaskSet(TaskSet): + wait_time = between(1, 3) + + def on_start(self): + # Setup code, e.g., login + pass + + @task(3) # Higher weight for common operations + def list_users(self): + with self.client.get("/users", catch_response=True) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Got status code {response.status_code}") + + @task(2) + def get_user_details(self): + # Use data from previous requests + pass + + @task(1) + def create_user(self): + # POST with realistic payload + pass + ``` + + Save each TaskSet to a separate file in {{ output_dir }}/tasks/ + Files should be named: users_tasks.py, products_tasks.py, etc. + + Configuration: + - Test complexity: {{ test_complexity }} + - Include authentication: {{ include_auth }} + + If test_complexity is "advanced", include: + - Data-driven tests with parameterized inputs + - Complex user flows with multiple dependent requests + - Performance-focused optimizations From 8cdd0001dd14e7be195bb76d58cba175b57e89af Mon Sep 17 00:00:00 2001 From: dorien-koelemeijer <62866702+dorien-koelemeijer@users.noreply.github.com> Date: Thu, 30 Oct 2025 08:06:41 +1000 Subject: [PATCH 024/121] Add OTLP logs layer (#5386) Signed-off-by: fbalicchia --- Cargo.lock | 13 ++++++++ crates/goose-cli/src/logging.rs | 9 +++++- crates/goose-server/src/logging.rs | 7 ++++- crates/goose/Cargo.toml | 1 + crates/goose/src/tracing/otlp_layer.rs | 43 ++++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee07bf9bb281..e4a2188851f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2646,6 +2646,7 @@ dependencies = [ "oauth2", "once_cell", "opentelemetry", + "opentelemetry-appender-tracing", "opentelemetry-otlp", "opentelemetry_sdk", "paste", @@ -4561,6 +4562,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5feffc321035ad94088a7e5333abb4d84a8726e54a802e736ce9dd7237e85b" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "opentelemetry-http" version = "0.27.0" diff --git a/crates/goose-cli/src/logging.rs b/crates/goose-cli/src/logging.rs index 9d3887246047..f65fe5a4df6a 100644 --- a/crates/goose-cli/src/logging.rs +++ b/crates/goose-cli/src/logging.rs @@ -102,7 +102,9 @@ fn setup_logging_internal( } if !force { - if let Ok((otlp_tracing_layer, otlp_metrics_layer)) = otlp_layer::init_otlp() { + if let Ok((otlp_tracing_layer, otlp_metrics_layer, otlp_logs_layer)) = + otlp_layer::init_otlp() + { layers.push( otlp_tracing_layer .with_filter(otlp_layer::create_otlp_tracing_filter()) @@ -113,6 +115,11 @@ fn setup_logging_internal( .with_filter(otlp_layer::create_otlp_metrics_filter()) .boxed(), ); + layers.push( + otlp_logs_layer + .with_filter(otlp_layer::create_otlp_logs_filter()) + .boxed(), + ); } } diff --git a/crates/goose-server/src/logging.rs b/crates/goose-server/src/logging.rs index c4ffd92870e5..7179e3cf7da3 100644 --- a/crates/goose-server/src/logging.rs +++ b/crates/goose-server/src/logging.rs @@ -74,7 +74,7 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> { console_layer.with_filter(LevelFilter::INFO).boxed(), ]; - if let Ok((otlp_tracing_layer, otlp_metrics_layer)) = otlp_layer::init_otlp() { + if let Ok((otlp_tracing_layer, otlp_metrics_layer, otlp_logs_layer)) = otlp_layer::init_otlp() { layers.push( otlp_tracing_layer .with_filter(otlp_layer::create_otlp_tracing_filter()) @@ -85,6 +85,11 @@ pub fn setup_logging(name: Option<&str>) -> Result<()> { .with_filter(otlp_layer::create_otlp_metrics_filter()) .boxed(), ); + layers.push( + otlp_logs_layer + .with_filter(otlp_layer::create_otlp_logs_filter()) + .boxed(), + ); } if let Some(langfuse) = langfuse_layer::create_langfuse_observer() { diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index f1fad2320ac8..f015819b7622 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -67,6 +67,7 @@ tracing = "0.1" tracing-subscriber = "0.3" tracing-opentelemetry = "0.28" opentelemetry = "0.27" +opentelemetry-appender-tracing = "0.27" opentelemetry_sdk = { version = "0.27", features = ["rt-tokio", "metrics"] } opentelemetry-otlp = { version = "0.27", features = ["grpc-tonic", "http-proto", "reqwest-client"] } tonic = "0.12" diff --git a/crates/goose/src/tracing/otlp_layer.rs b/crates/goose/src/tracing/otlp_layer.rs index 09d88956b648..958e188f31a1 100644 --- a/crates/goose/src/tracing/otlp_layer.rs +++ b/crates/goose/src/tracing/otlp_layer.rs @@ -1,6 +1,8 @@ use opentelemetry::trace::TracerProvider; use opentelemetry::{global, KeyValue}; +use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; use opentelemetry_otlp::WithExportConfig; +use opentelemetry_sdk::logs::{Logger, LoggerProvider}; use opentelemetry_sdk::trace::{self, RandomIdGenerator, Sampler}; use opentelemetry_sdk::{runtime, Resource}; use std::time::Duration; @@ -11,7 +13,8 @@ use tracing_subscriber::filter::FilterFn; pub type OtlpTracingLayer = OpenTelemetryLayer; pub type OtlpMetricsLayer = MetricsLayer; -pub type OtlpLayers = (OtlpTracingLayer, OtlpMetricsLayer); +pub type OtlpLogsLayer = OpenTelemetryTracingBridge; +pub type OtlpLayers = (OtlpTracingLayer, OtlpMetricsLayer, OtlpLogsLayer); pub type OtlpResult = Result>; #[derive(Debug, Clone)] @@ -163,10 +166,34 @@ pub fn create_otlp_metrics_layer() -> OtlpResult { Ok(tracing_opentelemetry::MetricsLayer::new(meter_provider)) } +pub fn create_otlp_logs_layer() -> OtlpResult> { + let config = OtlpConfig::from_config().ok_or("OTEL_EXPORTER_OTLP_ENDPOINT not configured")?; + + let resource = Resource::new(vec![ + KeyValue::new("service.name", "goose"), + KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), + KeyValue::new("service.namespace", "goose"), + ]); + + let exporter = opentelemetry_otlp::LogExporter::builder() + .with_http() + .with_endpoint(&config.endpoint) + .with_timeout(config.timeout) + .build()?; + + let logger_provider = LoggerProvider::builder() + .with_batch_exporter(exporter, runtime::Tokio) + .with_resource(resource) + .build(); + + Ok(OpenTelemetryTracingBridge::new(&logger_provider)) +} + pub fn init_otlp() -> OtlpResult { let tracing_layer = create_otlp_tracing_layer()?; let metrics_layer = create_otlp_metrics_layer()?; - Ok((tracing_layer, metrics_layer)) + let logs_layer = create_otlp_logs_layer()?; + Ok((tracing_layer, metrics_layer, logs_layer)) } pub fn init_otlp_tracing_only() -> OtlpResult { @@ -221,6 +248,18 @@ pub fn create_otlp_metrics_filter() -> FilterFn) -> bool> }) } +/// Creates a custom filter for OTLP metrics that captures: +/// - All events at WARN level and above +pub fn create_otlp_logs_filter() -> FilterFn) -> bool> { + FilterFn::new(|metadata: &Metadata<'_>| { + if metadata.level() <= &Level::WARN { + return true; + } + + false + }) +} + /// Shutdown OTLP providers gracefully pub fn shutdown_otlp() { // Shutdown the tracer provider and flush any pending spans From 61b88b1c38e3f69e4e11aa9e9b2d9743ce67421a Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:43:27 -0700 Subject: [PATCH 025/121] Don't disable extensions after they fail to activate in new chat session (#5464) Signed-off-by: fbalicchia --- .../extensions/extension-manager.test.ts | 10 ++-------- .../settings/extensions/extension-manager.ts | 16 +--------------- ui/desktop/src/utils/providerUtils.ts | 1 - 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts index db379e379b24..785cea3ffdf9 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts @@ -37,26 +37,22 @@ describe('Extension Manager', () => { mockAddToAgent.mockResolvedValue(undefined); await addToAgentOnStartup({ - addToConfig: mockAddToConfig, sessionId: 'test-session', extensionConfig: mockExtensionConfig, }); expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); - expect(mockAddToConfig).not.toHaveBeenCalled(); }); it('should successfully add extension on startup with custom toast options', async () => { mockAddToAgent.mockResolvedValue(undefined); await addToAgentOnStartup({ - addToConfig: mockAddToConfig, sessionId: 'test-session', extensionConfig: mockExtensionConfig, }); expect(mockAddToAgent).toHaveBeenCalledWith(mockExtensionConfig, 'test-session', true); - expect(mockAddToConfig).not.toHaveBeenCalled(); }); it('should retry on 428 errors', async () => { @@ -67,7 +63,6 @@ describe('Extension Manager', () => { .mockResolvedValue(undefined); await addToAgentOnStartup({ - addToConfig: mockAddToConfig, sessionId: 'test-session', extensionConfig: mockExtensionConfig, }); @@ -75,14 +70,13 @@ describe('Extension Manager', () => { expect(mockAddToAgent).toHaveBeenCalledTimes(3); }); - it('should disable extension after max retries', async () => { + it('should show error toast after max retries but keep extension enabled', async () => { const error428 = new Error('428 Precondition Required'); mockAddToAgent.mockRejectedValue(error428); mockToastService.configure = vi.fn(); mockToastService.error = vi.fn(); await addToAgentOnStartup({ - addToConfig: mockAddToConfig, sessionId: 'test-session', extensionConfig: mockExtensionConfig, }); @@ -90,7 +84,7 @@ describe('Extension Manager', () => { expect(mockAddToAgent).toHaveBeenCalledTimes(4); // Initial + 3 retries expect(mockToastService.error).toHaveBeenCalledWith({ title: 'test-extension', - msg: 'Extension failed to start and will be disabled.', + msg: 'Extension failed to start and will retry on a new session.', traceback: '428 Precondition Required', }); }); diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.ts b/ui/desktop/src/components/settings/extensions/extension-manager.ts index c8f212a1101e..6deb12960be0 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.ts @@ -83,7 +83,6 @@ export async function activateExtension({ } interface AddToAgentOnStartupProps { - addToConfig: (name: string, extensionConfig: ExtensionConfig, enabled: boolean) => Promise; extensionConfig: ExtensionConfig; toastOptions?: ToastServiceOptions; sessionId: string; @@ -95,7 +94,6 @@ interface AddToAgentOnStartupProps { * TODO(Douwe): Delete this after basecamp lands */ export async function addToAgentOnStartup({ - addToConfig, extensionConfig, sessionId, }: AddToAgentOnStartupProps): Promise { @@ -113,21 +111,9 @@ export async function addToAgentOnStartup({ toastService.configure({ silent: false }); toastService.error({ title: extensionConfig.name, - msg: 'Extension failed to start and will be disabled.', + msg: 'Extension failed to start and will retry on a new session.', traceback: finalError instanceof Error ? finalError.message : String(finalError), }); - - try { - await toggleExtension({ - toggle: 'toggleOff', - extensionConfig, - addToConfig, - toastOptions: { silent: true }, - sessionId, - }); - } catch (toggleErr) { - console.error('Failed to toggle off after error:', toggleErr); - } } } diff --git a/ui/desktop/src/utils/providerUtils.ts b/ui/desktop/src/utils/providerUtils.ts index 3dbd13434423..9c5f5f7c2d37 100644 --- a/ui/desktop/src/utils/providerUtils.ts +++ b/ui/desktop/src/utils/providerUtils.ts @@ -84,7 +84,6 @@ export const initializeSystem = async ( try { await addToAgentOnStartup({ - addToConfig: options.addExtension!, extensionConfig, toastOptions: { silent: false }, sessionId, From dbf68ed984a32dd3b86720e705fad54198ce771c Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:31:53 -0700 Subject: [PATCH 026/121] rpm install in /opt/Goose to avoid conflicts with chrome-sandbox (#5421) Signed-off-by: fbalicchia --- ui/desktop/forge.config.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts index 34c91dfb82a1..942e749f863b 100644 --- a/ui/desktop/forge.config.ts +++ b/ui/desktop/forge.config.ts @@ -72,7 +72,8 @@ module.exports = { categories: ['Development'], desktopTemplate: './forge.deb.desktop', options: { - icon: 'src/images/icon.png' + icon: 'src/images/icon.png', + prefix: '/opt' } }, }, @@ -86,7 +87,8 @@ module.exports = { categories: ['Development'], desktopTemplate: './forge.rpm.desktop', options: { - icon: 'src/images/icon.png' + icon: 'src/images/icon.png', + prefix: '/opt' } }, }, From d21e0705596278e18fa65a6e7defeefcceeb7a8c Mon Sep 17 00:00:00 2001 From: David Katz Date: Wed, 29 Oct 2025 23:23:25 -0400 Subject: [PATCH 027/121] Stream token usage on every agent message (#5342) Signed-off-by: fbalicchia --- crates/goose-server/src/openapi.rs | 5 ++- crates/goose-server/src/routes/reply.rs | 31 +++++++++++++- crates/goose/src/agents/agent.rs | 38 ++++++++++------- crates/goose/src/conversation/message.rs | 11 +++++ crates/goose/src/providers/base.rs | 23 ++++++++--- crates/goose/src/providers/formats/bedrock.rs | 10 ++--- crates/goose/src/providers/sagemaker_tgi.rs | 10 ++--- crates/goose/src/providers/venice.rs | 10 ++--- openapi.json | 0 ui/desktop/openapi.json | 41 +++++++++++++++++++ ui/desktop/src/api/types.gen.ts | 10 +++++ ui/desktop/src/components/BaseChat.tsx | 11 +++-- ui/desktop/src/components/BaseChat2.tsx | 11 +++-- ui/desktop/src/components/ChatInput.tsx | 24 +++++------ ui/desktop/src/components/hub.tsx | 6 +-- ui/desktop/src/hooks/useChatEngine.ts | 2 + ui/desktop/src/hooks/useChatStream.ts | 15 +++++++ ui/desktop/src/hooks/useMessageStream.ts | 19 +++++++-- 18 files changed, 214 insertions(+), 63 deletions(-) delete mode 100644 openapi.json diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index 85f20ec71a96..37fc4a77bc86 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -19,8 +19,8 @@ use goose::config::declarative_providers::{ }; use goose::conversation::message::{ FrontendToolRequest, Message, MessageContent, MessageMetadata, RedactedThinkingContent, - SystemNotificationContent, SystemNotificationType, ThinkingContent, ToolConfirmationRequest, - ToolRequest, ToolResponse, + SystemNotificationContent, SystemNotificationType, ThinkingContent, TokenState, + ToolConfirmationRequest, ToolRequest, ToolResponse, }; use crate::routes::reply::MessageEvent; @@ -404,6 +404,7 @@ derive_utoipa!(Icon as IconSchema); Message, MessageContent, MessageMetadata, + TokenState, ContentSchema, EmbeddedResourceSchema, ImageContentSchema, diff --git a/crates/goose-server/src/routes/reply.rs b/crates/goose-server/src/routes/reply.rs index 4c4a81925c57..0748399991be 100644 --- a/crates/goose-server/src/routes/reply.rs +++ b/crates/goose-server/src/routes/reply.rs @@ -8,7 +8,7 @@ use axum::{ }; use bytes::Bytes; use futures::{stream::StreamExt, Stream}; -use goose::conversation::message::{Message, MessageContent}; +use goose::conversation::message::{Message, MessageContent, TokenState}; use goose::conversation::Conversation; use goose::permission::{Permission, PermissionConfirmation}; use goose::session::SessionManager; @@ -126,6 +126,7 @@ impl IntoResponse for SseResponse { pub enum MessageEvent { Message { message: Message, + token_state: TokenState, }, Error { error: String, @@ -159,6 +160,7 @@ async fn stream_event( e ) }); + if tx.send(format!("data: {}\n\n", json)).await.is_err() { tracing::info!("client hung up"); cancel_token.cancel(); @@ -305,7 +307,32 @@ pub async fn reply( } all_messages.push(message.clone()); - stream_event(MessageEvent::Message { message }, &tx, &cancel_token).await; + + let token_state = match SessionManager::get_session(&session_id, false).await { + Ok(session) => { + TokenState { + input_tokens: session.input_tokens.unwrap_or(0), + output_tokens: session.output_tokens.unwrap_or(0), + total_tokens: session.total_tokens.unwrap_or(0), + accumulated_input_tokens: session.accumulated_input_tokens.unwrap_or(0), + accumulated_output_tokens: session.accumulated_output_tokens.unwrap_or(0), + accumulated_total_tokens: session.accumulated_total_tokens.unwrap_or(0), + } + }, + Err(e) => { + tracing::warn!("Failed to fetch session for token state: {}", e); + TokenState { + input_tokens: 0, + output_tokens: 0, + total_tokens: 0, + accumulated_input_tokens: 0, + accumulated_output_tokens: 0, + accumulated_total_tokens: 0, + } + } + }; + + stream_event(MessageEvent::Message { message, token_state }, &tx, &cancel_token).await; } Ok(Some(Ok(AgentEvent::HistoryReplaced(new_messages)))) => { all_messages = new_messages.clone(); diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 461843f4447f..5322f522ad3b 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -825,9 +825,11 @@ impl Agent { } } Err(e) => { - yield AgentEvent::Message(Message::assistant().with_text( - format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") - )); + yield AgentEvent::Message( + Message::assistant().with_text( + format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") + ) + ); } } })) @@ -917,7 +919,7 @@ impl Agent { if let Some(final_output_tool) = self.final_output_tool.lock().await.as_ref() { if final_output_tool.final_output.is_some() { let final_event = AgentEvent::Message( - Message::assistant().with_text(final_output_tool.final_output.clone().unwrap()), + Message::assistant().with_text(final_output_tool.final_output.clone().unwrap()) ); yield final_event; break; @@ -926,9 +928,11 @@ impl Agent { turns_taken += 1; if turns_taken > max_turns { - yield AgentEvent::Message(Message::assistant().with_text( - "I've reached the maximum number of actions I can do without user input. Would you like me to continue?" - )); + yield AgentEvent::Message( + Message::assistant().with_text( + "I've reached the maximum number of actions I can do without user input. Would you like me to continue?" + ) + ); break; } @@ -1178,18 +1182,22 @@ impl Agent { } Err(e) => { error!("Error: {}", e); - yield AgentEvent::Message(Message::assistant().with_text( + yield AgentEvent::Message( + Message::assistant().with_text( format!("Ran into this error trying to compact: {e}.\n\nPlease retry if you think this is a transient or recoverable error.") - )); + ) + ); break; } } } Err(e) => { error!("Error: {}", e); - yield AgentEvent::Message(Message::assistant().with_text( + yield AgentEvent::Message( + Message::assistant().with_text( format!("Ran into this error: {e}.\n\nPlease retry if you think this is a transient or recoverable error.") - )); + ) + ); break; } } @@ -1224,9 +1232,11 @@ impl Agent { } Err(e) => { error!("Retry logic failed: {}", e); - yield AgentEvent::Message(Message::assistant().with_text( - format!("Retry logic encountered an error: {}", e) - )); + yield AgentEvent::Message( + Message::assistant().with_text( + format!("Retry logic encountered an error: {}", e) + ) + ); exit_chat = true; } } diff --git a/crates/goose/src/conversation/message.rs b/crates/goose/src/conversation/message.rs index f432d3292e75..cc7d161dd841 100644 --- a/crates/goose/src/conversation/message.rs +++ b/crates/goose/src/conversation/message.rs @@ -711,6 +711,17 @@ impl Message { } } +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct TokenState { + pub input_tokens: i32, + pub output_tokens: i32, + pub total_tokens: i32, + pub accumulated_input_tokens: i32, + pub accumulated_output_tokens: i32, + pub accumulated_total_tokens: i32, +} + #[cfg(test)] mod tests { use crate::conversation::message::{Message, MessageContent, MessageMetadata}; diff --git a/crates/goose/src/providers/base.rs b/crates/goose/src/providers/base.rs index e55983caf669..ae7de6fbfebe 100644 --- a/crates/goose/src/providers/base.rs +++ b/crates/goose/src/providers/base.rs @@ -278,11 +278,11 @@ impl Add for Usage { type Output = Self; fn add(self, other: Self) -> Self { - Self { - input_tokens: sum_optionals(self.input_tokens, other.input_tokens), - output_tokens: sum_optionals(self.output_tokens, other.output_tokens), - total_tokens: sum_optionals(self.total_tokens, other.total_tokens), - } + Self::new( + sum_optionals(self.input_tokens, other.input_tokens), + sum_optionals(self.output_tokens, other.output_tokens), + sum_optionals(self.total_tokens, other.total_tokens), + ) } } @@ -298,10 +298,21 @@ impl Usage { output_tokens: Option, total_tokens: Option, ) -> Self { + let calculated_total = if total_tokens.is_none() { + match (input_tokens, output_tokens) { + (Some(input), Some(output)) => Some(input + output), + (Some(input), None) => Some(input), + (None, Some(output)) => Some(output), + (None, None) => None, + } + } else { + total_tokens + }; + Self { input_tokens, output_tokens, - total_tokens, + total_tokens: calculated_total, } } } diff --git a/crates/goose/src/providers/formats/bedrock.rs b/crates/goose/src/providers/formats/bedrock.rs index c1d627a6778d..d6488163000b 100644 --- a/crates/goose/src/providers/formats/bedrock.rs +++ b/crates/goose/src/providers/formats/bedrock.rs @@ -345,11 +345,11 @@ pub fn from_bedrock_role(role: &bedrock::ConversationRole) -> Result { } pub fn from_bedrock_usage(usage: &bedrock::TokenUsage) -> Usage { - Usage { - input_tokens: Some(usage.input_tokens), - output_tokens: Some(usage.output_tokens), - total_tokens: Some(usage.total_tokens), - } + Usage::new( + Some(usage.input_tokens), + Some(usage.output_tokens), + Some(usage.total_tokens), + ) } pub fn from_bedrock_json(document: &Document) -> Result { diff --git a/crates/goose/src/providers/sagemaker_tgi.rs b/crates/goose/src/providers/sagemaker_tgi.rs index 5861b09cdd59..e26c08eaf7b8 100644 --- a/crates/goose/src/providers/sagemaker_tgi.rs +++ b/crates/goose/src/providers/sagemaker_tgi.rs @@ -307,11 +307,11 @@ impl Provider for SageMakerTgiProvider { let message = self.parse_tgi_response(response)?; // TGI doesn't provide usage statistics, so we estimate - let usage = Usage { - input_tokens: Some(0), // Would need to tokenize input to get accurate count - output_tokens: Some(0), // Would need to tokenize output to get accurate count - total_tokens: Some(0), - }; + let usage = Usage::new( + Some(0), // Would need to tokenize input to get accurate count + Some(0), // Would need to tokenize output to get accurate count + Some(0), + ); // Add debug trace let debug_payload = serde_json::json!({ diff --git a/crates/goose/src/providers/venice.rs b/crates/goose/src/providers/venice.rs index 4a699222d4a5..0698fcea175c 100644 --- a/crates/goose/src/providers/venice.rs +++ b/crates/goose/src/providers/venice.rs @@ -508,11 +508,11 @@ impl Provider for VeniceProvider { // Extract usage let usage_data = &response_json["usage"]; - let usage = Usage { - input_tokens: usage_data["prompt_tokens"].as_i64().map(|v| v as i32), - output_tokens: usage_data["completion_tokens"].as_i64().map(|v| v as i32), - total_tokens: usage_data["total_tokens"].as_i64().map(|v| v as i32), - }; + let usage = Usage::new( + usage_data["prompt_tokens"].as_i64().map(|v| v as i32), + usage_data["completion_tokens"].as_i64().map(|v| v as i32), + usage_data["total_tokens"].as_i64().map(|v| v as i32), + ); Ok(( Message::new(Role::Assistant, Utc::now().timestamp(), content), diff --git a/openapi.json b/openapi.json deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 8fcd96b9553d..ca872392f667 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -3278,12 +3278,16 @@ "type": "object", "required": [ "message", + "token_state", "type" ], "properties": { "message": { "$ref": "#/components/schemas/Message" }, + "token_state": { + "$ref": "#/components/schemas/TokenState" + }, "type": { "type": "string", "enum": [ @@ -4526,6 +4530,43 @@ } } }, + "TokenState": { + "type": "object", + "required": [ + "inputTokens", + "outputTokens", + "totalTokens", + "accumulatedInputTokens", + "accumulatedOutputTokens", + "accumulatedTotalTokens" + ], + "properties": { + "accumulatedInputTokens": { + "type": "integer", + "format": "int32" + }, + "accumulatedOutputTokens": { + "type": "integer", + "format": "int32" + }, + "accumulatedTotalTokens": { + "type": "integer", + "format": "int32" + }, + "inputTokens": { + "type": "integer", + "format": "int32" + }, + "outputTokens": { + "type": "integer", + "format": "int32" + }, + "totalTokens": { + "type": "integer", + "format": "int32" + } + } + }, "Tool": { "type": "object", "required": [ diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index d2d9948f4225..70269fba0f10 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -367,6 +367,7 @@ export type MessageContent = (TextContent & { export type MessageEvent = { message: Message; + token_state: TokenState; type: 'Message'; } | { error: string; @@ -789,6 +790,15 @@ export type ThinkingContent = { thinking: string; }; +export type TokenState = { + accumulatedInputTokens: number; + accumulatedOutputTokens: number; + accumulatedTotalTokens: number; + inputTokens: number; + outputTokens: number; + totalTokens: number; +}; + export type Tool = { annotations?: ToolAnnotations | { [key: string]: unknown; diff --git a/ui/desktop/src/components/BaseChat.tsx b/ui/desktop/src/components/BaseChat.tsx index c5a96bcdcb3b..67090686db2c 100644 --- a/ui/desktop/src/components/BaseChat.tsx +++ b/ui/desktop/src/components/BaseChat.tsx @@ -132,6 +132,7 @@ function BaseChatContent({ sessionOutputTokens, localInputTokens, localOutputTokens, + tokenState, commandHistory, toolCallNotifications, sessionMetadata, @@ -442,9 +443,13 @@ function BaseChatContent({ commandHistory={commandHistory} initialValue={input || ''} setView={setView} - numTokens={sessionTokenCount} - inputTokens={sessionInputTokens || localInputTokens} - outputTokens={sessionOutputTokens || localOutputTokens} + totalTokens={tokenState?.totalTokens ?? sessionTokenCount} + accumulatedInputTokens={ + tokenState?.accumulatedInputTokens ?? sessionInputTokens ?? localInputTokens + } + accumulatedOutputTokens={ + tokenState?.accumulatedOutputTokens ?? sessionOutputTokens ?? localOutputTokens + } droppedFiles={droppedFiles} onFilesProcessed={() => setDroppedFiles([])} // Clear dropped files after processing messages={messages} diff --git a/ui/desktop/src/components/BaseChat2.tsx b/ui/desktop/src/components/BaseChat2.tsx index bef13f7860a7..8dfb8f5c2356 100644 --- a/ui/desktop/src/components/BaseChat2.tsx +++ b/ui/desktop/src/components/BaseChat2.tsx @@ -72,6 +72,7 @@ function BaseChatContent({ stopStreaming, sessionLoadError, setRecipeUserParams, + tokenState, } = useChatStream({ sessionId, onStreamFinish, @@ -281,9 +282,13 @@ function BaseChatContent({ //commandHistory={commandHistory} initialValue={initialPrompt} setView={setView} - numTokens={session?.total_tokens || undefined} - inputTokens={session?.input_tokens || undefined} - outputTokens={session?.output_tokens || undefined} + totalTokens={tokenState?.totalTokens ?? session?.total_tokens ?? undefined} + accumulatedInputTokens={ + tokenState?.accumulatedInputTokens ?? session?.accumulated_input_tokens ?? undefined + } + accumulatedOutputTokens={ + tokenState?.accumulatedOutputTokens ?? session?.accumulated_output_tokens ?? undefined + } droppedFiles={droppedFiles} onFilesProcessed={() => setDroppedFiles([])} // Clear dropped files after processing messages={messages} diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index e907b00ecdbd..863c7f65b5b7 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -70,9 +70,9 @@ interface ChatInputProps { droppedFiles?: DroppedFile[]; onFilesProcessed?: () => void; // Callback to clear dropped files after processing setView: (view: View) => void; - numTokens?: number; - inputTokens?: number; - outputTokens?: number; + totalTokens?: number; + accumulatedInputTokens?: number; + accumulatedOutputTokens?: number; messages?: Message[]; sessionCosts?: { [key: string]: { @@ -103,9 +103,9 @@ export default function ChatInput({ droppedFiles = [], onFilesProcessed, setView, - numTokens, - inputTokens, - outputTokens, + totalTokens, + accumulatedInputTokens, + accumulatedOutputTokens, messages = [], disableAnimation = false, sessionCosts, @@ -505,16 +505,16 @@ export default function ChatInput({ clearAlerts(); // Show alert when either there is registered token usage, or we know the limit - if ((numTokens && numTokens > 0) || (isTokenLimitLoaded && tokenLimit)) { + if ((totalTokens && totalTokens > 0) || (isTokenLimitLoaded && tokenLimit)) { addAlert({ type: AlertType.Info, message: 'Context window', progress: { - current: numTokens || 0, + current: totalTokens || 0, total: tokenLimit, }, showCompactButton: true, - compactButtonDisabled: !numTokens, + compactButtonDisabled: !totalTokens, onCompact: () => { window.dispatchEvent(new CustomEvent('hide-alert-popover')); @@ -542,7 +542,7 @@ export default function ChatInput({ } // We intentionally omit setView as it shouldn't trigger a re-render of alerts // eslint-disable-next-line react-hooks/exhaustive-deps - }, [numTokens, toolCount, tokenLimit, isTokenLimitLoaded, addAlert, clearAlerts]); + }, [totalTokens, toolCount, tokenLimit, isTokenLimitLoaded, addAlert, clearAlerts]); // Cleanup effect for component unmount - prevent memory leaks useEffect(() => { @@ -1540,8 +1540,8 @@ export default function ChatInput({ <>
diff --git a/ui/desktop/src/components/hub.tsx b/ui/desktop/src/components/hub.tsx index 4ae2e64978d9..3cae47ba04dc 100644 --- a/ui/desktop/src/components/hub.tsx +++ b/ui/desktop/src/components/hub.tsx @@ -78,9 +78,9 @@ export default function Hub({ commandHistory={[]} initialValue="" setView={setView} - numTokens={0} - inputTokens={0} - outputTokens={0} + totalTokens={0} + accumulatedInputTokens={0} + accumulatedOutputTokens={0} droppedFiles={[]} onFilesProcessed={() => {}} messages={[]} diff --git a/ui/desktop/src/hooks/useChatEngine.ts b/ui/desktop/src/hooks/useChatEngine.ts index 1c0f6b7e47a4..7c60038e6316 100644 --- a/ui/desktop/src/hooks/useChatEngine.ts +++ b/ui/desktop/src/hooks/useChatEngine.ts @@ -77,6 +77,7 @@ export const useChatEngine = ({ notifications, session, setError, + tokenState, } = useMessageStream({ api: getApiUrl('/reply'), id: chat.sessionId, @@ -451,6 +452,7 @@ export const useChatEngine = ({ sessionOutputTokens, localInputTokens, localOutputTokens, + tokenState, // UI helpers commandHistory, diff --git a/ui/desktop/src/hooks/useChatStream.ts b/ui/desktop/src/hooks/useChatStream.ts index 2b4c9f2b4e02..64ed1912de43 100644 --- a/ui/desktop/src/hooks/useChatStream.ts +++ b/ui/desktop/src/hooks/useChatStream.ts @@ -7,6 +7,7 @@ import { reply, resumeAgent, Session, + TokenState, updateFromSession, updateSessionUserRecipeValues, } from '../api'; @@ -60,6 +61,7 @@ interface UseChatStreamReturn { setRecipeUserParams: (values: Record) => Promise; stopStreaming: () => void; sessionLoadError?: string; + tokenState: TokenState; } function pushMessage(currentMessages: Message[], incomingMsg: Message): Message[] { @@ -88,6 +90,7 @@ async function streamFromResponse( stream: AsyncIterable, initialMessages: Message[], updateMessages: (messages: Message[]) => void, + updateTokenState: (tokenState: TokenState) => void, updateChatState: (state: ChatState) => void, onFinish: (error?: string) => void ): Promise { @@ -119,6 +122,8 @@ async function streamFromResponse( }); } + updateTokenState(event.token_state); + updateMessages(currentMessages); break; } @@ -171,6 +176,14 @@ export function useChatStream({ const [session, setSession] = useState(); const [sessionLoadError, setSessionLoadError] = useState(); const [chatState, setChatState] = useState(ChatState.Idle); + const [tokenState, setTokenState] = useState({ + inputTokens: 0, + outputTokens: 0, + totalTokens: 0, + accumulatedInputTokens: 0, + accumulatedOutputTokens: 0, + accumulatedTotalTokens: 0, + }); const abortControllerRef = useRef(null); useEffect(() => { @@ -288,6 +301,7 @@ export function useChatStream({ stream, currentMessages, (messages: Message[]) => setMessagesAndLog(messages, 'streaming'), + setTokenState, setChatState, onFinish ); @@ -373,5 +387,6 @@ export function useChatStream({ handleSubmit, stopStreaming, setRecipeUserParams, + tokenState, }; } diff --git a/ui/desktop/src/hooks/useMessageStream.ts b/ui/desktop/src/hooks/useMessageStream.ts index d05aaadbe067..081d264a7a54 100644 --- a/ui/desktop/src/hooks/useMessageStream.ts +++ b/ui/desktop/src/hooks/useMessageStream.ts @@ -6,7 +6,7 @@ import { getCompactingMessage, hasCompletedToolCalls, } from '../types/message'; -import { Conversation, Message, Role } from '../api'; +import { Conversation, Message, Role, TokenState } from '../api'; import { getSession, Session } from '../api'; import { ChatState } from '../types/chatState'; @@ -35,7 +35,7 @@ export interface NotificationEvent { // Event types for SSE stream type MessageEvent = - | { type: 'Message'; message: Message } + | { type: 'Message'; message: Message; token_state: TokenState } | { type: 'Error'; error: string } | { type: 'Finish'; reason: string } | { type: 'ModelChange'; model: string; mode: string } @@ -165,6 +165,9 @@ export interface UseMessageStreamHelpers { /** Clear error state */ setError: (error: Error | undefined) => void; + + /** Real-time token state from server */ + tokenState: TokenState; } /** @@ -197,6 +200,14 @@ export function useMessageStream({ null ); const [session, setSession] = useState(null); + const [tokenState, setTokenState] = useState({ + inputTokens: 0, + outputTokens: 0, + totalTokens: 0, + accumulatedInputTokens: 0, + accumulatedOutputTokens: 0, + accumulatedTotalTokens: 0, + }); // expose a way to update the body so we can update the session id when CLE occurs const updateMessageStreamBody = useCallback((newBody: object) => { @@ -280,6 +291,8 @@ export function useMessageStream({ // Transition from waiting to streaming on first message mutateChatState(ChatState.Streaming); + setTokenState(parsedEvent.token_state); + // Create a new message object with the properties preserved or defaulted const newMessage: Message = { ...parsedEvent.message, @@ -341,7 +354,6 @@ export function useMessageStream({ } case 'UpdateConversation': { - currentMessages = parsedEvent.conversation; setMessages(parsedEvent.conversation); break; } @@ -650,5 +662,6 @@ export function useMessageStream({ currentModelInfo, session, setError, + tokenState, }; } From 10d7ae07c4dc9ab746d54fdc4ae022c1c62c7d7c Mon Sep 17 00:00:00 2001 From: Better-Boy Date: Thu, 30 Oct 2025 19:34:23 +0530 Subject: [PATCH 028/121] apify doc fix (#5460) Signed-off-by: Better-Boy Signed-off-by: fbalicchia --- documentation/static/servers.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/static/servers.json b/documentation/static/servers.json index cd4ea333da59..44ae07233622 100644 --- a/documentation/static/servers.json +++ b/documentation/static/servers.json @@ -37,7 +37,7 @@ "id": "apify-mcp-server", "name": "Apify", "description": "Extract data from any website with thousands of scrapers, crawlers, and automations on Apify Store ⚡", - "command": "npx -y apify-mcp-server@latest", + "command": "npx -y @apify/actors-mcp-server", "link": "https://github.com/apify/apify-mcp-server", "installation_notes": "Install using npx. Requires an Apify API token.", "is_builtin": false, From 96fc9fe38a4ec0a62bd22c94b35a6c1c99a96615 Mon Sep 17 00:00:00 2001 From: Lymah Date: Thu, 30 Oct 2025 15:10:16 +0100 Subject: [PATCH 029/121] Doc (Blog): Managing goose Configurations Across Multiple Projects (#5467) Signed-off-by: Lymah123 Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 0debddb03b41..72e0175cfeaf 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -193,6 +193,19 @@ "submittedDate": "2025-10-29", "tags": ["hacktoberfest"], "hacktoberfest": true + }, + { + "title": "Managing goose Configurations Across Multiple Projects", + "author": { + "name": "Halimah", + "handle": "lymah123" + }, + "type": "blog", + "url": "https://dev.to/lymah/managing-goose-configurations-across-multiple-projects-58i3", + "thumbnail": "https://i.imgur.com/VvM8sMR.png", + "submittedDate": "2025-10-30", + "tags": ["hacktoberfest"], + "hacktoberfest": true } ] -} +} \ No newline at end of file From 5646c45156bc7d4cfd0b3850347ac6e5ff294b7b Mon Sep 17 00:00:00 2001 From: Anudhyan Datta <127120520+Anudhyan@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:02:48 +0530 Subject: [PATCH 030/121] docs: add "Building Custom Tools and Extensions for Goose" (#5469) Signed-off-by: Anudhyan <127120520+Anudhyan@users.noreply.github.com> Signed-off-by: Anudhyan Datta Co-authored-by: taniandjerry <126204004+taniandjerry@users.noreply.github.com> Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 72e0175cfeaf..112fb3db7a92 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -15,7 +15,7 @@ "url": "https://block.github.io/goose/blog/2025/09/26/hacktoberfest-2025", "thumbnail": "https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-09-26", - "tags": ["hacktoberfest", "open-source", "contributing"], + "tags": ["hacktoberfest", "open-source"], "hacktoberfest": true }, { @@ -52,7 +52,7 @@ "type": "blog", "url": "https://anudhyan.hashnode.dev/best-practices-for-using-goose-in-enterprise-environments", "submittedDate": "2025-10-15", - "tags": ["hacktoberfest", "goose", "enterprise"], + "tags": ["hacktoberfest", "enterprise"], "hacktoberfest": true }, { @@ -194,6 +194,18 @@ "tags": ["hacktoberfest"], "hacktoberfest": true }, + { + "title": "Building Custom Tools and Extensions for goose: A Developer's Guide", + "author": { + "name": "Anudhyan Datta", + "handle": "Anudhyan" + }, + "type": "blog", + "url": "https://anudhyan.hashnode.dev/building-custom-tools-and-extensions-for-goose-a-developers-guide", + "submittedDate": "2025-10-30", + "tags": ["hacktoberfest", "mcp"], + "hacktoberfest": true + }, { "title": "Managing goose Configurations Across Multiple Projects", "author": { From 11c65c03ab9f5d54065f3aba89b0e17c5b0652c7 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Thu, 30 Oct 2025 11:03:36 -0400 Subject: [PATCH 031/121] chore: upgrade rmcp to 0.8.3 (#5458) Signed-off-by: fbalicchia --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- ui/desktop/openapi.json | 5 ++++- ui/desktop/src/api/types.gen.ts | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4a2188851f2..7044d99416f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5553,9 +5553,9 @@ dependencies = [ [[package]] name = "rmcp" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f35acda8f89fca5fd8c96cae3c6d5b4c38ea0072df4c8030915f3b5ff469c1c" +checksum = "1fdad1258f7259fdc0f2dfc266939c82c3b5d1fd72bcde274d600cdc27e60243" dependencies = [ "base64 0.22.1", "chrono", @@ -5581,9 +5581,9 @@ dependencies = [ [[package]] name = "rmcp-macros" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f1d5220aaa23b79c3d02e18f7a554403b3ccea544bbb6c69d6bcb3e854a274" +checksum = "ede0589a208cc7ce81d1be68aa7e74b917fcd03c81528408bab0457e187dcd9b" dependencies = [ "darling 0.21.0", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 7d28bc13d5f5..6c312ee8c8ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ description = "An AI agent" uninlined_format_args = "allow" [workspace.dependencies] -rmcp = { version = "0.8.1", features = ["schemars", "auth"] } +rmcp = { version = "0.8.3", features = ["schemars", "auth"] } # Patch for Windows cross-compilation issue with crunchy [patch.crates-io] diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index ca872392f667..ea97a2c0b84c 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -2920,7 +2920,10 @@ "type": "string" }, "sizes": { - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "src": { "type": "string" diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 70269fba0f10..843822c14a53 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -285,7 +285,7 @@ export type GetToolsQuery = { export type Icon = { mimeType?: string; - sizes?: string; + sizes?: Array; src: string; }; From c67cef8907512175b38a80d9c749e70c566d0b3e Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Thu, 30 Oct 2025 12:04:18 -0400 Subject: [PATCH 032/121] Delete environment variable (#5479) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose/src/model.rs | 122 -------------------------------------- 1 file changed, 122 deletions(-) diff --git a/crates/goose/src/model.rs b/crates/goose/src/model.rs index 8d0be7fb53c8..2b3ee255b7f4 100644 --- a/crates/goose/src/model.rs +++ b/crates/goose/src/model.rs @@ -295,125 +295,3 @@ impl ModelConfig { .unwrap_or_else(|_| panic!("Failed to create model config for {}", model_name)) } } - -#[cfg(test)] -mod tests { - use super::*; - use serial_test::serial; - use temp_env::with_var; - - #[test] - #[serial] - fn test_model_config_context_limits() { - // Clear all GOOSE environment variables to ensure clean test environment - with_var("GOOSE_TEMPERATURE", None::<&str>, || { - with_var("GOOSE_CONTEXT_LIMIT", None::<&str>, || { - with_var("GOOSE_TOOLSHIM", None::<&str>, || { - with_var("GOOSE_TOOLSHIM_OLLAMA_MODEL", None::<&str>, || { - let config = ModelConfig::new("claude-3-opus") - .unwrap() - .with_context_limit(Some(150_000)); - assert_eq!(config.context_limit(), 150_000); - - let config = ModelConfig::new("claude-3-opus").unwrap(); - assert_eq!(config.context_limit(), 200_000); - - let config = ModelConfig::new("gpt-4-turbo").unwrap(); - assert_eq!(config.context_limit(), 128_000); - - let config = ModelConfig::new("unknown-model").unwrap(); - assert_eq!(config.context_limit(), DEFAULT_CONTEXT_LIMIT); - }); - }); - }); - }); - } - - #[test] - #[serial] - fn test_invalid_context_limit() { - with_var("GOOSE_CONTEXT_LIMIT", Some("abc"), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - if let Err(ConfigError::InvalidValue(var, val, msg)) = result { - assert_eq!(var, "GOOSE_CONTEXT_LIMIT"); - assert_eq!(val, "abc"); - assert!(msg.contains("positive integer")); - } - }); - - with_var("GOOSE_CONTEXT_LIMIT", Some("0"), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - assert!(matches!( - result.unwrap_err(), - ConfigError::InvalidRange(_, _) - )); - }); - } - - #[test] - #[serial] - fn test_invalid_temperature() { - with_var("GOOSE_TEMPERATURE", Some("hot"), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - }); - - with_var("GOOSE_TEMPERATURE", Some("-1.0"), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - }); - } - - #[test] - #[serial] - fn test_invalid_toolshim() { - with_var("GOOSE_TOOLSHIM", Some("maybe"), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - if let Err(ConfigError::InvalidValue(var, val, msg)) = result { - assert_eq!(var, "GOOSE_TOOLSHIM"); - assert_eq!(val, "maybe"); - assert!(msg.contains("must be one of")); - } - }); - } - - #[test] - #[serial] - fn test_empty_toolshim_model() { - with_var("GOOSE_TOOLSHIM_OLLAMA_MODEL", Some(""), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - assert!(matches!( - result.unwrap_err(), - ConfigError::InvalidValue(_, _, _) - )); - }); - - with_var("GOOSE_TOOLSHIM_OLLAMA_MODEL", Some(" "), || { - let result = ModelConfig::new("test-model"); - assert!(result.is_err()); - }); - } - - #[test] - #[serial] - fn test_valid_configurations() { - // Test with environment variables set - with_var("GOOSE_CONTEXT_LIMIT", Some("50000"), || { - with_var("GOOSE_TEMPERATURE", Some("0.7"), || { - with_var("GOOSE_TOOLSHIM", Some("true"), || { - with_var("GOOSE_TOOLSHIM_OLLAMA_MODEL", Some("llama3"), || { - let config = ModelConfig::new("test-model").unwrap(); - assert_eq!(config.context_limit(), 50_000); - assert_eq!(config.temperature, Some(0.7)); - assert!(config.toolshim); - assert_eq!(config.toolshim_model, Some("llama3".to_string())); - }); - }); - }); - }); - } -} From 888181b8bb32a0a6749d5160f9b59f9c7c96a6d2 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:24:24 -0700 Subject: [PATCH 033/121] Add menu option for setting window always on top (#5429) Signed-off-by: fbalicchia --- ui/desktop/src/main.ts | 48 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index c13d472d4b4e..da16344af096 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -483,9 +483,7 @@ let appConfig = { const windowMap = new Map(); const goosedClients = new Map(); - -// Track power save blockers per window -const windowPowerSaveBlockers = new Map(); // windowId -> blockerId +const windowPowerSaveBlockers = new Map(); const createChat = async ( app: App, @@ -1872,6 +1870,50 @@ async function appMain() { ); } + if (menu) { + let windowMenu = menu.items.find((item) => item.label === 'Window'); + + if (!windowMenu) { + windowMenu = new MenuItem({ + label: 'Window', + submenu: Menu.buildFromTemplate([]), + }); + + const helpMenuIndex = menu.items.findIndex((item) => item.label === 'Help'); + if (helpMenuIndex >= 0) { + menu.items.splice(helpMenuIndex, 0, windowMenu); + } else { + menu.items.push(windowMenu); + } + } + + if (windowMenu.submenu) { + windowMenu.submenu.append( + new MenuItem({ + label: 'Always on Top', + type: 'checkbox', + accelerator: process.platform === 'darwin' ? 'Cmd+Shift+T' : 'Ctrl+Shift+T', + click(menuItem) { + const focusedWindow = BrowserWindow.getFocusedWindow(); + if (focusedWindow) { + const isAlwaysOnTop = menuItem.checked; + + if (process.platform === 'darwin') { + focusedWindow.setAlwaysOnTop(isAlwaysOnTop, 'floating'); + } else { + focusedWindow.setAlwaysOnTop(isAlwaysOnTop); + } + + console.log( + `[Main] Set always-on-top to ${isAlwaysOnTop} for window ${focusedWindow.id}` + ); + } + }, + }) + ); + } + } + // on macOS, the topbar is hidden if (menu && process.platform !== 'darwin') { let helpMenu = menu.items.find((item) => item.label === 'Help'); From f2d86159bf11cb3a927c5c552bd817893da1d8b2 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Thu, 30 Oct 2025 12:54:05 -0400 Subject: [PATCH 034/121] Clear windows and fix build failure (#5452) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose-server/src/routes/agent.rs | 63 +++++++++++++------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index b16cea136058..d01580d7faa7 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -479,40 +479,41 @@ async fn agent_add_extension( State(state): State>, Json(request): Json, ) -> Result { - // If this is a Stdio extension that uses npx, check for Node.js installation - #[cfg(target_os = "windows")] - if let ExtensionConfig::Stdio { cmd, .. } = &request.config { - if cmd.ends_with("npx.cmd") || cmd.ends_with("npx") { - let node_exists = std::path::Path::new(r"C:\Program Files\nodejs\node.exe").exists() - || std::path::Path::new(r"C:\Program Files (x86)\nodejs\node.exe").exists(); - - if !node_exists { - let cmd_path = std::path::Path::new(&cmd); - let script_dir = cmd_path.parent().ok_or(StatusCode::INTERNAL_SERVER_ERROR)?; - let install_script = script_dir.join("install-node.cmd"); - - if install_script.exists() { - eprintln!("Installing Node.js..."); - let output = std::process::Command::new(&install_script) - .arg("https://nodejs.org/dist/v23.10.0/node-v23.10.0-x64.msi") - .output() - .map_err(|e| { - eprintln!("Failed to run Node.js installer: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - if !output.status.success() { + if cfg!(target_os = "windows") { + if let ExtensionConfig::Stdio { cmd, .. } = &request.config { + if cmd.ends_with("npx.cmd") || cmd.ends_with("npx") { + let node_exists = std::path::Path::new(r"C:\Program Files\nodejs\node.exe") + .exists() + || std::path::Path::new(r"C:\Program Files (x86)\nodejs\node.exe").exists(); + + if !node_exists { + let cmd_path = std::path::Path::new(&cmd); + let script_dir = cmd_path + .parent() + .ok_or_else(|| ErrorResponse::internal("Invalid command path"))?; + let install_script = script_dir.join("install-node.cmd"); + + if install_script.exists() { + eprintln!("Installing Node.js..."); + let output = std::process::Command::new(&install_script) + .arg("https://nodejs.org/dist/v23.10.0/node-v23.10.0-x64.msi") + .output() + .map_err(|_e| { + ErrorResponse::internal("Failed to run Node.js installer") + })?; + + if !output.status.success() { + return Err(ErrorResponse::internal(format!( + "Failed to install Node.js: {}", + String::from_utf8_lossy(&output.stderr) + ))); + } + } else { return Err(ErrorResponse::internal(format!( - "Failed to install Node.js: {}", - String::from_utf8_lossy(&output.stderr) + "Node.js not detected and no installer script not found at: {}", + install_script.display() ))); } - eprintln!("Node.js installation completed"); - } else { - return Err(ErrorResponse::internal(format!( - "Node.js not detected and no installer script not found at: {}", - install_script.display() - ))); } } } From 68914a71de38c14871903407e441bf8f78e2f945 Mon Sep 17 00:00:00 2001 From: Better-Boy Date: Thu, 30 Oct 2025 22:59:21 +0530 Subject: [PATCH 035/121] docs: video on goose with apify mcp (#5472) Signed-off-by: Better-Boy Co-authored-by: taniandjerry <126204004+taniandjerry@users.noreply.github.com> Signed-off-by: fbalicchia --- .../community/data/community-content.json | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 112fb3db7a92..67a91b81a2e3 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -19,7 +19,7 @@ "hacktoberfest": true }, { - "title": "Running Goose in Containers (Without Losing Your Mind)", + "title": "Running goose in Containers (Without Losing Your Mind)", "author": { "name": "Rupam Golui", "handle": "Itz-Agasta" @@ -32,7 +32,7 @@ "hacktoberfest": true }, { - "title": "Goose with Goose Docs MCP", + "title": "Goose with goose Docs MCP", "author": { "name": "Dakshata Mishra", "handle": "the-matrixneo" @@ -44,7 +44,7 @@ "hacktoberfest": true }, { - "title": "Best Practices for Using Goose in Enterprise Environments", + "title": "Best Practices for Using goose in Enterprise Environments", "author": { "name": "Anudhyan Datta", "handle": "Anudhyan" @@ -56,7 +56,7 @@ "hacktoberfest": true }, { - "title": "Getting started with Goose on Windows", + "title": "Getting started with goose on Windows", "author": { "name": "Halimah", "handle": "lymah123" @@ -133,7 +133,7 @@ "hacktoberfest": true }, { - "title": "Goose with Context7 MCP", + "title": "goose with Context7 MCP", "author": { "name": "Dakshata Mishra", "handle": "the-matrixneo" @@ -170,7 +170,7 @@ "hacktoberfest": true }, { - "title": "Optimizing Goose performance on Windows", + "title": "Optimizing goose Performance on Windows", "author": { "name": "Mohammed Thaha", "handle": "mohammed-thaha" @@ -183,7 +183,7 @@ "hacktoberfest": true }, { - "title": "Goose with Neon MCP", + "title": "goose with Neon MCP", "author": { "name": "Dakshata Mishra", "handle": "the-matrixneo" @@ -195,6 +195,18 @@ "hacktoberfest": true }, { + "title": "goose with Apify MCP", + "author": { + "name": "abhi", + "handle": "Better-Boy" + }, + "type": "video", + "url": "https://youtube.com/shorts/XhA2YqjNF7M", + "submittedDate": "2025-10-30", + "tags": ["hacktoberfest"], + "hacktoberfest": true + }, + { "title": "Building Custom Tools and Extensions for goose: A Developer's Guide", "author": { "name": "Anudhyan Datta", From af5feef7ff722bd2d8aef6779ae73dfea1646435 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Fri, 31 Oct 2025 04:33:51 +1100 Subject: [PATCH 036/121] only run fork on branch PRs (#5461) Signed-off-by: fbalicchia --- .github/workflows/pr-smoke-test.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/pr-smoke-test.yml b/.github/workflows/pr-smoke-test.yml index 84a0e6964790..8fee5945ed91 100644 --- a/.github/workflows/pr-smoke-test.yml +++ b/.github/workflows/pr-smoke-test.yml @@ -13,8 +13,16 @@ on: name: Live Provider Tests jobs: + check-fork: + runs-on: ubuntu-latest + # Skip entire workflow for PRs from forks (they don't have access to secrets) + if: github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository + steps: + - run: echo "Not a fork PR - proceeding with smoke tests" + changes: runs-on: ubuntu-latest + needs: check-fork outputs: code: ${{ steps.filter.outputs.code }} steps: From 0b0621cd4611e0d62b73da8c66d0850e01af04cf Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:35:22 -0700 Subject: [PATCH 037/121] docs: recipe activity parameter substitution (#5462) Signed-off-by: fbalicchia --- .../docs/guides/recipes/recipe-reference.md | 123 ++++++++++++++---- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/documentation/docs/guides/recipes/recipe-reference.md b/documentation/docs/guides/recipes/recipe-reference.md index 1e5e8258d80e..d7f1bad2b0e8 100644 --- a/documentation/docs/guides/recipes/recipe-reference.md +++ b/documentation/docs/guides/recipes/recipe-reference.md @@ -1,10 +1,10 @@ --- sidebar_position: 2 title: Recipe Reference Guide -description: Complete technical reference for creating and customizing recipes in Goose via the CLI. +description: Complete technical reference for creating and customizing recipes in goose via the CLI. --- -Recipes are reusable Goose configurations that package up a specific setup so it can be easily shared and launched by others. +Recipes are reusable goose configurations that package up a specific setup so it can be easily shared and launched by others. ## Recipe File Format @@ -20,10 +20,10 @@ After creating recipe files, you can use the [`goose recipe` subcommands](/docs/ ### CLI and Desktop Formats -Goose recipes use two formats: +goose recipes use two formats: - **CLI Format**: Recipe fields (like `title`, `description`, `instructions`) are at the root level of the YAML/JSON file. This format is used when recipes are created via the CLI `/recipe` command and [Recipe Generator](/recipe-generator) YAML option. -- **Desktop Format**: Recipe fields are nested inside a `recipe` object, with additional metadata fields at the root level. This format is used when recipes are created from Goose Desktop. +- **Desktop Format**: Recipe fields are nested inside a `recipe` object, with additional metadata fields at the root level. This format is used when recipes are created from goose Desktop. The CLI automatically detects and handles both formats when running `goose run --recipe ` and `goose recipe` commands. The Desktop can [import](/docs/guides/recipes/storing-recipes#importing-recipes) and use YAML recipes (or deeplinks) in either CLI or Desktop format. @@ -56,7 +56,7 @@ isArchived: false ``` :::note -Goose automatically adds metadata fields to recipes saved from the Desktop app. +goose automatically adds metadata fields to recipes saved from the Desktop app. ::: @@ -77,16 +77,17 @@ Goose automatically adds metadata fields to recipes saved from the Desktop app. |-------|------|-------------| | `instructions` | String | Template instructions that can include parameter substitutions | | `prompt` | String | A template prompt that can include parameter substitutions; required in headless (non-interactive) mode | -| `parameters` | Array | List of parameter definitions | -| `extensions` | Array | List of extension configurations | -| `settings` | Object | Configuration for model provider, model name, and other settings | -| `sub_recipes` | Array | List of subrecipes | -| `response` | Object | Configuration for structured output validation | -| `retry` | Object | Configuration for automated retry logic with success validation | +| [`parameters`](#parameters) | Array | List of parameter definitions | +| [`activities`](#activities) | Array | List of example prompts that appear as clickable bubbles in goose Desktop | +| [`extensions`](#extensions) | Array | List of extension configurations | +| [`settings`](#settings) | Object | Configuration for model provider, model name, and other settings | +| [`sub_recipes`](#subrecipes) | Array | List of subrecipes | +| [`response`](#structured-output-with-response) | Object | Structured output schema for automation workflows | +| [`retry`](#automated-retry-with-success-validation) | Object | Configuration for automated retry logic with success validation | ### Desktop Format Metadata Fields -When recipes are saved from Goose Desktop, additional metadata fields are included at the top level (outside the `recipe` key). These fields are used by the Desktop app for organization and management but are ignored by CLI operations. +When recipes are saved from goose Desktop, additional metadata fields are included at the top level (outside the `recipe` key). These fields are used by the Desktop app for organization and management but are ignored by CLI operations. | Field | Type | Description | |-------|------|-------------| @@ -97,7 +98,9 @@ When recipes are saved from Goose Desktop, additional metadata fields are includ ## Parameters -Each parameter in the `parameters` array has the following structure: +The `parameters` field allows you to create dynamic, reusable recipes that can be customized for different contexts. Parameters define placeholders that users fill in when running the recipe, making the recipe more flexible and adaptable. + +Parameter substitution uses Jinja-style template syntax with `{{ parameter_name }}` placeholders. Each parameter in the `parameters` array has the following structure: ### Required Parameter Fields @@ -120,7 +123,7 @@ Each parameter in the `parameters` array has the following structure: - `optional`: Can be omitted if a default value is specified - `user_prompt`: Will interactively prompt the user for input if not provided -The `required` and `optional` parameters work best for recipes opened in Goose Desktop. If a value isn't provided for a `user_prompt` parameter, the parameter won't be substituted and may appear as literal `{{ parameter_name }}` text in the recipe output. +The `required` and `optional` parameters work best for recipes opened in goose Desktop. If a value isn't provided for a `user_prompt` parameter, the parameter won't be substituted and may appear as literal `{{ parameter_name }}` text in the recipe output. ### Input Types @@ -140,15 +143,81 @@ parameters: prompt: "Please review this code:\n\n{{ source_code }}" ``` -When you run this recipe with `source_code: /path/to/app.py`, Goose will read the contents of `app.py` and substitute the actual code into the `{{ source_code }}` placeholder. +When you run this recipe with `source_code: /path/to/app.py`, goose will read the contents of `app.py` and substitute the actual code into the `{{ source_code }}` placeholder. :::important - Optional parameters MUST have a default value specified - Required parameters cannot have default values - File parameters cannot have default values regardless of requirement type to prevent unintended importing of sensitive files -- Parameter keys must match any template variables used in instructions or prompt +- Parameter keys must match any template variables used in instructions, prompt, or activities +::: + +### Parameter Substitution in Desktop + +When a recipe with parameters is opened in goose Desktop, users are presented with a **Recipe Parameters** dialog where they can: +- Provide values for required parameters +- Modify or accept default values for optional parameters +- Enter values for `user_prompt` parameters + +Once parameter values are submitted, they are substituted into the recipe's `instructions`, `prompt`, and `activities` fields before the recipe starts. + +## Activities + +The `activities` field defines an optional message and clickable activity bubbles (buttons) that appears when a recipe is opened in goose Desktop. + +:::info Desktop only +Activities are a Desktop-only feature. When recipes with activities are run via the CLI or as a scheduled job, the `activities` field is ignored and has no effect on recipe execution. ::: +### Activity Types + +Activities can be defined in two ways: + +1. **Message Activity**: Displays the markdown-formatted activity text in an info box above the activity bubbles. For example: + + ``` + activities: + - "message: **Welcome!** Here's what I can help with:\n\n• 📊 Data analysis\n• 🔍 Code review\n• 📝 Documentation\n\nSelect an option below to begin." + ``` + + Only include one `message:` prefixed activity. Additional `message:` prefixed activities become regular clickable bubbles (and display the literal "message:" text). + +2. **Button Activities**: Text to display in activity bubbles, which send the activity text as a prompt when clicked + +### Parameter Substitution + +Activities support [parameter substitution](#parameters), allowing you to create dynamic, personalized activity bubbles. After users provide parameter values in the **Recipe Parameters** dialog, the values are substituted into the activity text before the bubbles are displayed. + +### Example Configuration + +```yaml +version: "1.0.0" +title: "Code Review Assistant" +description: "Review code with customizable focus areas" +parameters: + - key: language + input_type: string + requirement: required + description: "Programming language to review" + - key: focus + input_type: string + requirement: optional + default: "best practices" + description: "Review focus area" + +activities: + - "message: Click an option below to start reviewing {{ language }} code with a focus on {{ focus }}." + - "Review the current file for {{ focus }}" + - "Suggest improvements for {{ language }} code quality" + - "Check for security vulnerabilities" + - "Generate unit tests" +``` + +In this example: +- The message activity displays instructions with substituted parameter values, for example: "Click an option below to start reviewing rust code with a focus on best practices." +- The first two activity bubbles use parameter substitution, for example: "Review the current file for best practices" +- The last two activity bubbles are static prompts that work regardless of parameters + ## Extensions The `extensions` field allows you to specify which Model Context Protocol (MCP) servers and other extensions the recipe needs to function. Each extension in the array has the following structure: @@ -163,7 +232,7 @@ The `extensions` field allows you to specify which Model Context Protocol (MCP) | `args` | Array | List of arguments for the command | | `env_keys` | Array | (Optional) Names of environment variables required by the extension | | `timeout` | Number | Timeout in seconds | -| `bundled` | Boolean | (Optional) Whether the extension is bundled with Goose | +| `bundled` | Boolean | (Optional) Whether the extension is bundled with goose | | `description` | String | Description of what the extension does | | `available_tools` | Array | List of tool names within the extension that will be available. When not specified all will be available | @@ -203,10 +272,10 @@ extensions: This feature is only available through the CLI. -If a recipe uses an extension that requires a secret, Goose can prompt users to provide the secret when running the recipe: +If a recipe uses an extension that requires a secret, goose can prompt users to provide the secret when running the recipe: -1. When a recipe is loaded, Goose scans all extensions (including those in subrecipes) for `env_keys` fields -2. If any required environment variables are missing from the secure keyring, Goose prompts the user to enter them +1. When a recipe is loaded, goose scans all extensions (including those in subrecipes) for `env_keys` fields +2. If any required environment variables are missing from the secure keyring, goose prompts the user to enter them 3. Values are stored securely in the system keyring and reused for subsequent runs To update a stored secret, remove it from the system keyring and run the recipe again to be re-prompted. @@ -246,7 +315,7 @@ settings: ``` :::note -Settings specified in a recipe will override your default Goose configuration when that recipe is executed. If no settings are specified, Goose will use your configured defaults. +Settings specified in a recipe will override your default goose configuration when that recipe is executed. If no settings are specified, goose will use your configured defaults. ::: ## Subrecipes @@ -359,12 +428,12 @@ These environment variables are overridden by recipe-specific timeout configurat ## Structured Output with `response` -The `response` field enables recipes to enforce a final structured JSON output from Goose. When you specify a `json_schema`, Goose will: +The `response` field enables recipes to enforce a final structured JSON output from goose. When you specify a `json_schema`, goose will: 1. **Validate the output**: Validates the output JSON against your JSON schema with basic JSON schema validations 2. **Final structured output**: Ensure the final output of the agent is a response matching your JSON structure -This **enables automation** by returning consistent, parseable results for scripts and workflows. Recipes can produce structured output when run from either the Goose CLI or Goose Desktop. See [use cases and ideas for automation workflows](/docs/guides/recipes/session-recipes#structured-output-for-automation). +This feature is designed for **non-interactive automation** to ensure consistent, parseable output. Recipes can produce structured output when run from either the goose CLI or goose Desktop. See [use cases and ideas for automation workflows](/docs/guides/recipes/session-recipes#structured-output-for-automation). ### Basic Structure @@ -407,11 +476,13 @@ response: ## Template Support -Recipes support Jinja-style template syntax in both `instructions` and `prompt` fields: +Recipes support Jinja-style template syntax in `instructions`, `prompt`, and `activities` fields: ```yaml instructions: "Follow these steps with {{ parameter_name }}" prompt: "Your task is to {{ action }}" +activities: + - "Process {{ parameter_name }} with {{ action }}" ``` Advanced template features include: @@ -563,7 +634,7 @@ Common errors to watch for: - Invalid extension configurations - Invalid retry configuration (missing required fields, invalid shell commands) -When these occur, Goose will provide helpful error messages indicating what needs to be fixed. +When these occur, goose will provide helpful error messages indicating what needs to be fixed. ### Retry-Specific Errors @@ -573,4 +644,4 @@ When these occur, Goose will provide helpful error messages indicating what need - **Missing required retry fields**: When `max_retries` or `checks` are not specified ## Learn More -Check out the [Goose Recipes](/docs/guides/recipes) guide for more docs, tools, and resources to help you master Goose recipes. \ No newline at end of file +Check out the [Recipes](/docs/guides/recipes) guide for more docs, tools, and resources to help you master goose recipes. \ No newline at end of file From fb531ff6c5e44fc2d2cdbb30dc9ba166681f0c2b Mon Sep 17 00:00:00 2001 From: David Katz Date: Thu, 30 Oct 2025 14:14:10 -0400 Subject: [PATCH 038/121] Fix: Compaction client <-> server sync (#5481) Signed-off-by: fbalicchia --- ui/desktop/src/hooks/useChatStream.ts | 2 ++ ui/desktop/src/hooks/useMessageStream.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/ui/desktop/src/hooks/useChatStream.ts b/ui/desktop/src/hooks/useChatStream.ts index 64ed1912de43..e084b04d6e2a 100644 --- a/ui/desktop/src/hooks/useChatStream.ts +++ b/ui/desktop/src/hooks/useChatStream.ts @@ -146,6 +146,8 @@ async function streamFromResponse( } case 'UpdateConversation': { log.messages('conversation-update', event.conversation.length); + // WARNING: Since Message handler uses this local variable, we need to update it here to avoid the client clobbering it. + // Longterm fix is to only send the agent the new messages, not the entire conversation. currentMessages = event.conversation; updateMessages(event.conversation); break; diff --git a/ui/desktop/src/hooks/useMessageStream.ts b/ui/desktop/src/hooks/useMessageStream.ts index 081d264a7a54..2eb98835935b 100644 --- a/ui/desktop/src/hooks/useMessageStream.ts +++ b/ui/desktop/src/hooks/useMessageStream.ts @@ -354,6 +354,9 @@ export function useMessageStream({ } case 'UpdateConversation': { + // WARNING: Since Message handler uses this local variable, we need to update it here to avoid the client clobbering it. + // Longterm fix is to only send the agent the new messages, not the entire conversation. + currentMessages = parsedEvent.conversation; setMessages(parsedEvent.conversation); break; } From c69cb5934b6d5769516bcb9a75fe0f265af2b8c5 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Thu, 30 Oct 2025 15:13:32 -0400 Subject: [PATCH 039/121] Stringly typed config (#5463) Signed-off-by: fbalicchia --- crates/goose-cli/src/commands/acp.rs | 4 +- crates/goose-cli/src/commands/configure.rs | 98 ++++++++----------- crates/goose-cli/src/commands/web.rs | 4 +- crates/goose-cli/src/recipes/recipe.rs | 3 +- crates/goose-cli/src/session/builder.rs | 4 +- crates/goose-cli/src/session/mod.rs | 51 +++++----- crates/goose-cli/src/session/output.rs | 4 +- crates/goose-server/src/routes/agent.rs | 28 +++--- crates/goose-server/src/routes/audio.rs | 2 +- .../src/routes/config_management.rs | 2 +- crates/goose/src/agents/agent.rs | 23 ++--- crates/goose/src/agents/prompt_manager.rs | 19 ++-- .../agents/recipe_tools/dynamic_task_tools.rs | 3 +- crates/goose/src/config/base.rs | 73 +++++++------- .../goose/src/config/declarative_providers.rs | 7 +- crates/goose/src/config/experiments.rs | 2 +- crates/goose/src/config/extensions.rs | 12 +-- crates/goose/src/config/goose_mode.rs | 26 +++++ crates/goose/src/config/mod.rs | 2 + .../goose/src/config/signup_openrouter/mod.rs | 10 +- crates/goose/src/config/signup_tetrate/mod.rs | 10 +- .../goose/src/config/signup_tetrate/tests.rs | 7 +- crates/goose/src/oauth/persist.rs | 3 +- .../src/permission/permission_inspector.rs | 73 +++++++------- crates/goose/src/providers/claude_code.rs | 20 +--- crates/goose/src/providers/githubcopilot.rs | 4 +- crates/goose/src/providers/ollama.rs | 9 +- crates/goose/src/scheduler.rs | 4 +- crates/goose/src/tool_inspection.rs | 3 +- crates/goose/src/tracing/otlp_layer.rs | 10 +- 30 files changed, 244 insertions(+), 276 deletions(-) create mode 100644 crates/goose/src/config/goose_mode.rs diff --git a/crates/goose-cli/src/commands/acp.rs b/crates/goose-cli/src/commands/acp.rs index 8ee9acfe09d4..95094ce7e908 100644 --- a/crates/goose-cli/src/commands/acp.rs +++ b/crates/goose-cli/src/commands/acp.rs @@ -101,11 +101,11 @@ impl GooseAcpAgent { let config = Config::global(); let provider_name: String = config - .get_param("GOOSE_PROVIDER") + .get_goose_provider() .map_err(|e| anyhow::anyhow!("No provider configured: {}", e))?; let model_name: String = config - .get_param("GOOSE_MODEL") + .get_goose_model() .map_err(|e| anyhow::anyhow!("No model configured: {}", e))?; let model_config = goose::model::ModelConfig { diff --git a/crates/goose-cli/src/commands/configure.rs b/crates/goose-cli/src/commands/configure.rs index bf0ef6a0e614..82653c08e9e1 100644 --- a/crates/goose-cli/src/commands/configure.rs +++ b/crates/goose-cli/src/commands/configure.rs @@ -14,7 +14,8 @@ use goose::config::paths::Paths; use goose::config::permission::PermissionLevel; use goose::config::signup_tetrate::TetrateAuth; use goose::config::{ - configure_tetrate, Config, ConfigError, ExperimentManager, ExtensionEntry, PermissionManager, + configure_tetrate, Config, ConfigError, ExperimentManager, ExtensionEntry, GooseMode, + PermissionManager, }; use goose::conversation::message::Message; use goose::model::ModelConfig; @@ -421,7 +422,7 @@ fn select_model_from_list( } fn try_store_secret(config: &Config, key_name: &str, value: String) -> anyhow::Result { - match config.set_secret(key_name, Value::String(value)) { + match config.set_secret(key_name, &value) { Ok(_) => Ok(true), Err(e) => { cliclack::outro(style(format!( @@ -450,7 +451,7 @@ pub async fn configure_provider_dialog() -> anyhow::Result { .collect(); // Get current default provider if it exists - let current_provider: Option = config.get_param("GOOSE_PROVIDER").ok(); + let current_provider: Option = config.get_goose_provider().ok(); let default_provider = current_provider.unwrap_or_default(); // Select provider @@ -487,7 +488,7 @@ pub async fn configure_provider_dialog() -> anyhow::Result { return Ok(false); } } else { - config.set_param(&key.name, Value::String(env_value))?; + config.set_param(&key.name, &env_value)?; } let _ = cliclack::log::info(format!("Saved {} to {}", key.name, config.path())); } @@ -529,7 +530,7 @@ pub async fn configure_provider_dialog() -> anyhow::Result { return Ok(false); } } else { - config.set_param(&key.name, Value::String(value))?; + config.set_param(&key.name, &value)?; } } } @@ -558,9 +559,9 @@ pub async fn configure_provider_dialog() -> anyhow::Result { }; if key.secret { - config.set_secret(&key.name, Value::String(value))?; + config.set_secret(&key.name, &value)?; } else { - config.set_param(&key.name, Value::String(value))?; + config.set_param(&key.name, &value)?; } } } @@ -648,9 +649,8 @@ pub async fn configure_provider_dialog() -> anyhow::Result { match result { Ok((_message, _usage)) => { - // Update config with new values only if the test succeeds - config.set_param("GOOSE_PROVIDER", Value::String(provider_name.to_string()))?; - config.set_param("GOOSE_MODEL", Value::String(model.clone()))?; + config.set_goose_provider(provider_name)?; + config.set_goose_model(&model)?; print_config_file_saved()?; Ok(true) } @@ -877,7 +877,7 @@ pub fn configure_extensions_dialog() -> anyhow::Result<()> { // Try to store in keychain let keychain_key = key.to_string(); - match config.set_secret(&keychain_key, Value::String(value.clone())) { + match config.set_secret(&keychain_key, &value) { Ok(_) => { // Successfully stored in keychain, add to env_keys env_keys.push(keychain_key); @@ -973,7 +973,7 @@ pub fn configure_extensions_dialog() -> anyhow::Result<()> { // Try to store in keychain let keychain_key = key.to_string(); - match config.set_secret(&keychain_key, Value::String(value.clone())) { + match config.set_secret(&keychain_key, &value) { Ok(_) => { // Successfully stored in keychain, add to env_keys env_keys.push(keychain_key); @@ -1093,7 +1093,7 @@ pub fn configure_extensions_dialog() -> anyhow::Result<()> { // Try to store in keychain let keychain_key = key.to_string(); - match config.set_secret(&keychain_key, Value::String(value.clone())) { + match config.set_secret(&keychain_key, &Value::String(value.clone())) { Ok(_) => { // Successfully stored in keychain, add to env_keys env_keys.push(keychain_key); @@ -1273,46 +1273,35 @@ pub fn configure_goose_mode_dialog() -> anyhow::Result<()> { let mode = cliclack::select("Which goose mode would you like to configure?") .item( - "auto", + GooseMode::Auto, "Auto Mode", "Full file modification, extension usage, edit, create and delete files freely" ) .item( - "approve", + GooseMode::Approve, "Approve Mode", "All tools, extensions and file modifications will require human approval" ) .item( - "smart_approve", + GooseMode::SmartApprove, "Smart Approve Mode", "Editing, creating, deleting files and using extensions will require human approval" ) .item( - "chat", + GooseMode::Chat, "Chat Mode", "Engage with the selected provider without using tools, extensions, or file modification" ) .interact()?; - match mode { - "auto" => { - config.set_param("GOOSE_MODE", Value::String("auto".to_string()))?; - cliclack::outro("Set to Auto Mode - full file modification enabled")?; - } - "approve" => { - config.set_param("GOOSE_MODE", Value::String("approve".to_string()))?; - cliclack::outro("Set to Approve Mode - all tools and modifications require approval")?; - } - "smart_approve" => { - config.set_param("GOOSE_MODE", Value::String("smart_approve".to_string()))?; - cliclack::outro("Set to Smart Approve Mode - modifications require approval")?; - } - "chat" => { - config.set_param("GOOSE_MODE", Value::String("chat".to_string()))?; - cliclack::outro("Set to Chat Mode - no tools or modifications enabled")?; - } - _ => unreachable!(), + config.set_goose_mode(mode)?; + let msg = match mode { + GooseMode::Auto => "Set to Auto Mode - full file modification enabled", + GooseMode::Approve => "Set to Approve Mode - all tools and modifications require approval", + GooseMode::SmartApprove => "Set to Smart Approve Mode - modifications require approval", + GooseMode::Chat => "Set to Chat Mode - no tools or modifications enabled", }; + cliclack::outro(msg)?; Ok(()) } @@ -1321,28 +1310,25 @@ pub fn configure_goose_router_strategy_dialog() -> anyhow::Result<()> { let enable_router = cliclack::select("Would you like to enable smart tool routing?") .item( - "true", + true, "Enable Router", "Use LLM-based intelligence to select tools", ) .item( - "false", + false, "Disable Router", "Use the default tool selection strategy", ) .interact()?; - match enable_router { - "true" => { - config.set_param("GOOSE_ENABLE_ROUTER", Value::String("true".to_string()))?; - cliclack::outro("Router enabled - using LLM-based intelligence for tool selection")?; - } - "false" => { - config.set_param("GOOSE_ENABLE_ROUTER", Value::String("false".to_string()))?; - cliclack::outro("Router disabled - using default tool selection")?; - } - _ => unreachable!(), + config.set_param("GOOSE_ENABLE_ROUTER", enable_router)?; + let msg = if enable_router { + "Router enabled - using LLM-based intelligence for tool selection" + } else { + "Router disabled - using default tool selection" }; + cliclack::outro(msg)?; + Ok(()) } @@ -1360,15 +1346,15 @@ pub fn configure_tool_output_dialog() -> anyhow::Result<()> { match tool_log_level { "high" => { - config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.8))?; + config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.8)?; cliclack::outro("Showing tool output of high importance only.")?; } "medium" => { - config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.2))?; + config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.2)?; cliclack::outro("Showing tool output of medium importance.")?; } "all" => { - config.set_param("GOOSE_CLI_MIN_PRIORITY", Value::from(0.0))?; + config.set_param("GOOSE_CLI_MIN_PRIORITY", 0.0)?; cliclack::outro("Showing all tool output.")?; } _ => unreachable!(), @@ -1441,11 +1427,11 @@ pub async fn configure_tool_permissions_dialog() -> anyhow::Result<()> { let config = Config::global(); let provider_name: String = config - .get_param("GOOSE_PROVIDER") + .get_goose_provider() .expect("No provider configured. Please set model provider first"); let model: String = config - .get_param("GOOSE_MODEL") + .get_goose_model() .expect("No model configured. Please set model first"); let model_config = ModelConfig::new(&model)?; @@ -1591,7 +1577,7 @@ fn configure_recipe_dialog() -> anyhow::Result<()> { if input_value.clone().trim().is_empty() { config.delete(key_name)?; } else { - config.set_param(key_name, Value::String(input_value))?; + config.set_param(key_name, &input_value)?; } Ok(()) } @@ -1618,7 +1604,7 @@ pub fn configure_max_turns_dialog() -> anyhow::Result<()> { .interact()?; let max_turns: u32 = max_turns_input.parse()?; - config.set_param("GOOSE_MAX_TURNS", Value::from(max_turns))?; + config.set_param("GOOSE_MAX_TURNS", max_turns)?; cliclack::outro(format!( "Set maximum turns to {} - goose will ask for input after {} consecutive actions", @@ -1651,7 +1637,7 @@ pub async fn handle_openrouter_auth() -> anyhow::Result<()> { // Test configuration - get the model that was configured println!("\nTesting configuration..."); - let configured_model: String = config.get_param("GOOSE_MODEL")?; + let configured_model: String = config.get_goose_model()?; let model_config = match goose::model::ModelConfig::new(&configured_model) { Ok(config) => config, Err(e) => { @@ -1729,7 +1715,7 @@ pub async fn handle_tetrate_auth() -> anyhow::Result<()> { // Test configuration println!("\nTesting configuration..."); - let configured_model: String = config.get_param("GOOSE_MODEL")?; + let configured_model: String = config.get_goose_model()?; let model_config = match goose::model::ModelConfig::new(&configured_model) { Ok(config) => config, Err(e) => { diff --git a/crates/goose-cli/src/commands/web.rs b/crates/goose-cli/src/commands/web.rs index 636b2590ebbb..f49e44fa919c 100644 --- a/crates/goose-cli/src/commands/web.rs +++ b/crates/goose-cli/src/commands/web.rs @@ -139,7 +139,7 @@ pub async fn handle_web( let config = goose::config::Config::global(); - let provider_name: String = match config.get_param("GOOSE_PROVIDER") { + let provider_name: String = match config.get_goose_provider() { Ok(p) => p, Err(_) => { eprintln!("No provider configured. Run 'goose configure' first"); @@ -147,7 +147,7 @@ pub async fn handle_web( } }; - let model: String = match config.get_param("GOOSE_MODEL") { + let model: String = match config.get_goose_model() { Ok(m) => m, Err(_) => { eprintln!("No model configured. Run 'goose configure' first"); diff --git a/crates/goose-cli/src/recipes/recipe.rs b/crates/goose-cli/src/recipes/recipe.rs index 987b7d295b6e..ff722657289a 100644 --- a/crates/goose-cli/src/recipes/recipe.rs +++ b/crates/goose-cli/src/recipes/recipe.rs @@ -11,7 +11,6 @@ use goose::recipe::build_recipe::{ }; use goose::recipe::validate_recipe::parse_and_validate_parameters; use goose::recipe::Recipe; -use serde_json::Value; fn create_user_prompt_callback() -> impl Fn(&str, &str) -> Result { |key: &str, description: &str| -> Result { @@ -98,7 +97,7 @@ pub fn collect_missing_secrets(requirements: &[SecretRequirement]) -> Result<()> .unwrap_or_else(|_| String::new()); if !value.trim().is_empty() { - config.set_secret(&req.key, Value::String(value))?; + config.set_secret(&req.key, &value)?; println!("✅ Secret stored securely for {}", req.extension_name); } else { println!("⏭️ Skipped {} for {}", req.key, req.extension_name); diff --git a/crates/goose-cli/src/session/builder.rs b/crates/goose-cli/src/session/builder.rs index 7e0f0fce7df1..8c0811a4b415 100644 --- a/crates/goose-cli/src/session/builder.rs +++ b/crates/goose-cli/src/session/builder.rs @@ -208,7 +208,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { .as_ref() .and_then(|s| s.goose_provider.clone()) }) - .or_else(|| config.get_param("GOOSE_PROVIDER").ok()) + .or_else(|| config.get_goose_provider().ok()) .expect("No provider configured. Run 'goose configure' first"); let model_name = session_config @@ -219,7 +219,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { .as_ref() .and_then(|s| s.goose_model.clone()) }) - .or_else(|| config.get_param("GOOSE_MODEL").ok()) + .or_else(|| config.get_goose_model().ok()) .expect("No model configured. Run 'goose configure' first"); let temperature = session_config.settings.as_ref().and_then(|s| s.temperature); diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index f4712ecb3351..529fff3a1fa7 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -12,6 +12,7 @@ use crate::session::task_execution_display::{ }; use goose::conversation::Conversation; use std::io::Write; +use std::str::FromStr; pub use self::export::message_to_markdown; pub use builder::{build_session, SessionBuilderConfig, SessionSettings}; @@ -28,7 +29,7 @@ use completion::GooseCompleter; use goose::agents::extension::{Envs, ExtensionConfig}; use goose::agents::types::RetryConfig; use goose::agents::{Agent, SessionConfig}; -use goose::config::Config; +use goose::config::{Config, GooseMode}; use goose::providers::pricing::initialize_pricing_cache; use goose::session::SessionManager; use input::InputResult; @@ -545,21 +546,18 @@ impl CliSession { save_history(&mut editor); let config = Config::global(); - let mode = mode.to_lowercase(); - - // Check if mode is valid - if !["auto", "approve", "chat", "smart_approve"].contains(&mode.as_str()) { - output::render_error(&format!( - "Invalid mode '{}'. Mode must be one of: auto, approve, chat", - mode - )); - continue; - } - - config - .set_param("GOOSE_MODE", Value::String(mode.to_string())) - .unwrap(); - output::goose_mode_message(&format!("Goose mode set to '{}'", mode)); + let mode = match GooseMode::from_str(&mode.to_lowercase()) { + Ok(mode) => mode, + Err(_) => { + output::render_error(&format!( + "Invalid mode '{}'. Mode must be one of: auto, approve, chat, smart_approve", + mode + )); + continue; + } + }; + config.set_goose_mode(mode)?; + output::goose_mode_message(&format!("Goose mode set to '{:?}'", mode)); continue; } input::InputResult::Plan(options) => { @@ -787,12 +785,9 @@ impl CliSession { self.run_mode = RunMode::Normal; // set goose mode: auto if that isn't already the case let config = Config::global(); - let curr_goose_mode = - config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); - if curr_goose_mode != "auto" { - config - .set_param("GOOSE_MODE", Value::String("auto".to_string())) - .unwrap(); + let curr_goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto); + if curr_goose_mode != GooseMode::Auto { + config.set_goose_mode(GooseMode::Auto).unwrap(); } // clear the messages before acting on the plan @@ -807,10 +802,8 @@ impl CliSession { output::hide_thinking(); // Reset run & goose mode - if curr_goose_mode != "auto" { - config - .set_param("GOOSE_MODE", Value::String(curr_goose_mode.to_string())) - .unwrap(); + if curr_goose_mode != GooseMode::Auto { + config.set_goose_mode(curr_goose_mode)?; } } else { // add the plan response (assistant message) & carry the conversation forward @@ -1324,7 +1317,7 @@ impl CliSession { .unwrap_or(false); let provider_name = config - .get_param::("GOOSE_PROVIDER") + .get_goose_provider() .unwrap_or_else(|_| "unknown".to_string()); // Do not get costing information if show cost is disabled @@ -1488,7 +1481,7 @@ async fn get_reasoner() -> Result, anyhow::Error> { } else { println!("WARNING: GOOSE_PLANNER_PROVIDER not found. Using default provider..."); config - .get_param::("GOOSE_PROVIDER") + .get_goose_provider() .expect("No provider configured. Run 'goose configure' first") }; @@ -1498,7 +1491,7 @@ async fn get_reasoner() -> Result, anyhow::Error> { } else { println!("WARNING: GOOSE_PLANNER_MODEL not found. Using default model..."); config - .get_param::("GOOSE_MODEL") + .get_goose_model() .expect("No model configured. Run 'goose configure' first") }; diff --git a/crates/goose-cli/src/session/output.rs b/crates/goose-cli/src/session/output.rs index b1e0066da556..7b115ff90a2c 100644 --- a/crates/goose-cli/src/session/output.rs +++ b/crates/goose-cli/src/session/output.rs @@ -68,7 +68,7 @@ thread_local! { pub fn set_theme(theme: Theme) { let config = Config::global(); config - .set_param("GOOSE_CLI_THEME", Value::String(theme.as_config_string())) + .set_param("GOOSE_CLI_THEME", theme.as_config_string()) .expect("Failed to set theme"); CURRENT_THEME.with(|t| *t.borrow_mut() = theme); @@ -79,7 +79,7 @@ pub fn set_theme(theme: Theme) { Theme::Ansi => "ansi", }; - if let Err(e) = config.set_param("GOOSE_CLI_THEME", Value::String(theme_str.to_string())) { + if let Err(e) = config.set_param("GOOSE_CLI_THEME", theme_str) { eprintln!("Failed to save theme setting to config: {}", e); } } diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index d01580d7faa7..29898542b8af 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -12,7 +12,7 @@ use axum::{ use goose::config::PermissionManager; use goose::agents::ExtensionConfig; -use goose::config::Config; +use goose::config::{Config, GooseMode}; use goose::model::ModelConfig; use goose::prompt_template::render_global_file; use goose::providers::{create, create_with_named_model}; @@ -211,15 +211,12 @@ async fn resume_agent( let config = Config::global(); let provider_result = async { - let provider_name: String = - config - .get_param("GOOSE_PROVIDER") - .map_err(|_| ErrorResponse { - message: "Could not configure agent: missing provider".into(), - status: StatusCode::INTERNAL_SERVER_ERROR, - })?; - - let model: String = config.get_param("GOOSE_MODEL").map_err(|_| ErrorResponse { + let provider_name: String = config.get_goose_provider().map_err(|_| ErrorResponse { + message: "Could not configure agent: missing provider".into(), + status: StatusCode::INTERNAL_SERVER_ERROR, + })?; + + let model: String = config.get_goose_model().map_err(|_| ErrorResponse { message: "Could not configure agent: missing model".into(), status: StatusCode::INTERNAL_SERVER_ERROR, })?; @@ -348,7 +345,7 @@ async fn get_tools( Query(query): Query, ) -> Result>, StatusCode> { let config = Config::global(); - let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); + let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto); let agent = state.get_agent_for_route(query.session_id).await?; let permission_manager = PermissionManager::default(); @@ -360,9 +357,9 @@ async fn get_tools( let permission = permission_manager .get_user_permission(&tool.name) .or_else(|| { - if goose_mode == "smart_approve" { + if goose_mode == GooseMode::SmartApprove { permission_manager.get_smart_approve_permission(&tool.name) - } else if goose_mode == "approve" { + } else if goose_mode == GooseMode::Approve { Some(PermissionLevel::AskBefore) } else { None @@ -406,10 +403,7 @@ async fn update_agent_provider( .await?; let config = Config::global(); - let model = match payload - .model - .or_else(|| config.get_param("GOOSE_MODEL").ok()) - { + let model = match payload.model.or_else(|| config.get_goose_model().ok()) { Some(m) => m, None => { tracing::error!("No model specified"); diff --git a/crates/goose-server/src/routes/audio.rs b/crates/goose-server/src/routes/audio.rs index 6985d96d1ce0..707f1b5b2742 100644 --- a/crates/goose-server/src/routes/audio.rs +++ b/crates/goose-server/src/routes/audio.rs @@ -251,7 +251,7 @@ async fn transcribe_elevenlabs_handler( // Migrate to secret storage if let Err(e) = config.set( "ELEVENLABS_API_KEY", - serde_json::Value::String(key.clone()), + &serde_json::Value::String(key.clone()), true, ) { tracing::error!("Failed to migrate ElevenLabs API key: {:?}", e); diff --git a/crates/goose-server/src/routes/config_management.rs b/crates/goose-server/src/routes/config_management.rs index c1b1de5d2777..8965b4e783e4 100644 --- a/crates/goose-server/src/routes/config_management.rs +++ b/crates/goose-server/src/routes/config_management.rs @@ -101,7 +101,7 @@ pub async fn upsert_config( Json(query): Json, ) -> Result, StatusCode> { let config = Config::global(); - let result = config.set(&query.key, query.value, query.is_secret); + let result = config.set(&query.key, &query.value, query.is_secret); match result { Ok(_) => Ok(Json(Value::String(format!("Upserted key {}", query.key)))), diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 5322f522ad3b..dd44f28850dd 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -29,7 +29,7 @@ use crate::agents::tool_route_manager::ToolRouteManager; use crate::agents::tool_router_index_manager::ToolRouterIndexManager; use crate::agents::types::SessionConfig; use crate::agents::types::{FrontendTool, SharedProvider, ToolResultReceiver}; -use crate::config::{get_enabled_extensions, Config}; +use crate::config::{get_enabled_extensions, Config, GooseMode}; use crate::context_mgmt::DEFAULT_COMPACTION_THRESHOLD; use crate::conversation::{debug_conversation_fix, fix_conversation, Conversation}; use crate::mcp_utils::ToolResult; @@ -73,7 +73,7 @@ pub struct ReplyContext { pub tools: Vec, pub toolshim_tools: Vec, pub system_prompt: String, - pub goose_mode: String, + pub goose_mode: GooseMode, pub initial_messages: Vec, pub config: &'static Config, } @@ -193,7 +193,7 @@ impl Agent { // Add permission inspector (medium-high priority) // Note: mode will be updated dynamically based on session config tool_inspection_manager.add_inspector(Box::new(PermissionInspector::new( - "smart_approve".to_string(), + GooseMode::SmartApprove, std::collections::HashSet::new(), // readonly tools - will be populated from extension manager std::collections::HashSet::new(), // regular tools - will be populated from extension manager ))); @@ -264,7 +264,7 @@ impl Agent { // Update permission inspector mode to match the session mode self.tool_inspection_manager - .update_permission_inspector_mode(goose_mode.clone()) + .update_permission_inspector_mode(goose_mode) .await; Ok(ReplyContext { @@ -1030,8 +1030,7 @@ impl Agent { yield AgentEvent::Message(msg); } - let mode = goose_mode.clone(); - if mode.as_str() == "chat" { + if goose_mode == GooseMode::Chat { // Skip all tool calls in chat mode for request in remaining_requests { let mut response = message_tool_response.lock().await; @@ -1258,15 +1257,13 @@ impl Agent { })) } - fn determine_goose_mode(session: Option<&SessionConfig>, config: &Config) -> String { + fn determine_goose_mode(session: Option<&SessionConfig>, config: &Config) -> GooseMode { let mode = session.and_then(|s| s.execution_mode.as_deref()); match mode { - Some("foreground") => "chat".to_string(), - Some("background") => "auto".to_string(), - _ => config - .get_param("GOOSE_MODE") - .unwrap_or_else(|_| "auto".to_string()), + Some("foreground") => GooseMode::Chat, + Some("background") => GooseMode::Auto, + _ => config.get_goose_mode().unwrap_or(GooseMode::Auto), } } @@ -1525,7 +1522,7 @@ impl Agent { // but it doesn't know and the plumbing looks complicated. let config = Config::global(); let provider_name: String = config - .get_param("GOOSE_PROVIDER") + .get_goose_provider() .expect("No provider configured. Run 'goose configure' first"); let settings = Settings { diff --git a/crates/goose/src/agents/prompt_manager.rs b/crates/goose/src/agents/prompt_manager.rs index 133624d12ad9..8f8ca85f2c09 100644 --- a/crates/goose/src/agents/prompt_manager.rs +++ b/crates/goose/src/agents/prompt_manager.rs @@ -3,13 +3,16 @@ use chrono::DateTime; use chrono::Utc; use serde::Serialize; use serde_json::Value; -use std::borrow::Cow; use std::collections::HashMap; use crate::agents::extension::ExtensionInfo; use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents; use crate::agents::router_tools::llm_search_tool_prompt; -use crate::{config::Config, prompt_template, utils::sanitize_unicode_tags}; +use crate::{ + config::{Config, GooseMode}, + prompt_template, + utils::sanitize_unicode_tags, +}; const MAX_EXTENSIONS: usize = 5; const MAX_TOOLS: usize = 50; @@ -34,7 +37,7 @@ struct SystemPromptContext { current_date_time: String, #[serde(skip_serializing_if = "Option::is_none")] extension_tool_limits: Option<(usize, usize)>, - goose_mode: String, + goose_mode: GooseMode, is_autonomous: bool, enable_subagents: bool, max_extensions: usize, @@ -106,9 +109,7 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> { .collect(); let config = Config::global(); - let goose_mode = config - .get_param("GOOSE_MODE") - .unwrap_or_else(|_| Cow::from("auto")); + let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto); let extension_tool_limits = self .extension_tool_count @@ -119,8 +120,8 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> { tool_selection_strategy: self.router_enabled.then(llm_search_tool_prompt), current_date_time: self.manager.current_date_timestamp.clone(), extension_tool_limits, - goose_mode: goose_mode.to_string(), - is_autonomous: goose_mode == "auto", + goose_mode, + is_autonomous: goose_mode == GooseMode::Auto, enable_subagents: should_enabled_subagents(self.model_name.as_str()), max_extensions: MAX_EXTENSIONS, max_tools: MAX_TOOLS, @@ -137,7 +138,7 @@ impl<'a> SystemPromptBuilder<'a, PromptManager> { }); let mut system_prompt_extras = self.manager.system_prompt_extras.clone(); - if goose_mode == "chat" { + if goose_mode == GooseMode::Chat { system_prompt_extras.push( "Right now you are in the chat only mode, no access to any tool use and system." .to_string(), diff --git a/crates/goose/src/agents/recipe_tools/dynamic_task_tools.rs b/crates/goose/src/agents/recipe_tools/dynamic_task_tools.rs index f87cda290337..8f6b2881b249 100644 --- a/crates/goose/src/agents/recipe_tools/dynamic_task_tools.rs +++ b/crates/goose/src/agents/recipe_tools/dynamic_task_tools.rs @@ -9,6 +9,7 @@ use crate::agents::subagent_execution_tool::{ task_types::{Task, TaskType}, }; use crate::agents::tool_execution::ToolCallResult; +use crate::config::GooseMode; use crate::recipe::{Recipe, RecipeBuilder}; use anyhow::{anyhow, Result}; use rmcp::model::{Content, ErrorCode, ErrorData, Tool, ToolAnnotations}; @@ -93,7 +94,7 @@ pub struct TaskParameter { pub fn should_enabled_subagents(model_name: &str) -> bool { let config = crate::config::Config::global(); - let is_autonomous = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()) == "auto"; + let is_autonomous = config.get_goose_mode().unwrap_or(GooseMode::Auto) == GooseMode::Auto; if !is_autonomous { return false; } diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index 3974a4b9a6cc..550695120b92 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -1,8 +1,9 @@ use crate::config::paths::Paths; +use crate::config::GooseMode; use fs2::FileExt; use keyring::Entry; use once_cell::sync::OnceCell; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; use std::env; @@ -143,6 +144,11 @@ macro_rules! declare_param { self.get_param(stringify!($param_name)) } } + paste::paste! { + pub fn [](&self, v: impl Into<$param_type>) -> Result<(), ConfigError> { + self.set_param(stringify!($param_name), &v.into()) + } + } }; } @@ -551,7 +557,10 @@ impl Config { } // save a parameter in the appropriate location based on if it's secret or not - pub fn set(&self, key: &str, value: Value, is_secret: bool) -> Result<(), ConfigError> { + pub fn set(&self, key: &str, value: &V, is_secret: bool) -> Result<(), ConfigError> + where + V: Serialize, + { if is_secret { self.set_secret(key, value) } else { @@ -606,17 +615,10 @@ impl Config { /// Returns a ConfigError if: /// - There is an error reading or writing the config file /// - There is an error serializing the value - pub fn set_param(&self, key: &str, value: Value) -> Result<(), ConfigError> { - // Lock before reading to prevent race condition. + pub fn set_param(&self, key: &str, value: V) -> Result<(), ConfigError> { let _guard = self.guard.lock().unwrap(); - - // Load current values with recovery if needed let mut values = self.load_values()?; - - // Modify values - values.insert(key.to_string(), value); - - // Save all values using the atomic write approach + values.insert(key.to_string(), serde_json::to_value(&value)?); self.save_values(values) } @@ -689,12 +691,15 @@ impl Config { /// Returns a ConfigError if: /// - There is an error accessing the keyring /// - There is an error serializing the value - pub fn set_secret(&self, key: &str, value: Value) -> Result<(), ConfigError> { + pub fn set_secret(&self, key: &str, value: &V) -> Result<(), ConfigError> + where + V: Serialize, + { // Lock before reading to prevent race condition. let _guard = self.guard.lock().unwrap(); let mut values = self.load_secrets()?; - values.insert(key.to_string(), value); + values.insert(key.to_string(), serde_json::to_value(value)?); match &self.secrets { SecretStorage::Keyring { service } => { @@ -742,6 +747,9 @@ impl Config { } declare_param!(GOOSE_SEARCH_PATHS, Vec); + declare_param!(GOOSE_MODE, GooseMode); + declare_param!(GOOSE_PROVIDER, String); + declare_param!(GOOSE_MODEL, String); } /// Load init-config.yaml from workspace root if it exists. @@ -819,7 +827,7 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Set a simple string value - config.set_param("test_key", Value::String("test_value".to_string()))?; + config.set_param("test_key", "test_value")?; // Test simple string retrieval let value: String = config.get_param("test_key")?; @@ -874,8 +882,8 @@ mod tests { let temp_file = NamedTempFile::new().unwrap(); let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; - config.set_param("key1", Value::String("value1".to_string()))?; - config.set_param("key2", Value::Number(42.into()))?; + config.set_param("key1", "value1")?; + config.set_param("key2", 42)?; // Read the file directly to check YAML formatting let content = std::fs::read_to_string(temp_file.path())?; @@ -890,12 +898,11 @@ mod tests { let temp_file = NamedTempFile::new().unwrap(); let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; - config.set_param("key", Value::String("value".to_string()))?; - - let value: String = config.get_param("key")?; - assert_eq!(value, "value"); + config.set_param("test_key", "test_value")?; + config.set_param("another_key", 42)?; + config.set_param("third_key", true)?; - config.delete("key")?; + let _values = config.load_values()?; let result: Result = config.get_param("key"); assert!(matches!(result, Err(ConfigError::NotFound(_)))); @@ -909,7 +916,7 @@ mod tests { let secrets_file = NamedTempFile::new().unwrap(); let config = Config::new_with_file_secrets(config_file.path(), secrets_file.path())?; - config.set_secret("key", Value::String("value".to_string()))?; + config.set_secret("key", &"value")?; let value: String = config.get_secret("key")?; assert_eq!(value, "value"); @@ -930,7 +937,7 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Test setting and getting a simple secret - config.set_secret("api_key", Value::String("secret123".to_string()))?; + config.set_secret("api_key", &Value::String("secret123".to_string()))?; let value: String = config.get_secret("api_key")?; assert_eq!(value, "secret123"); @@ -957,8 +964,8 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Set multiple secrets - config.set_secret("key1", Value::String("secret1".to_string()))?; - config.set_secret("key2", Value::String("secret2".to_string()))?; + config.set_secret("key1", &Value::String("secret1".to_string()))?; + config.set_secret("key2", &Value::String("secret2".to_string()))?; // Verify both exist let value1: String = config.get_secret("key1")?; @@ -1056,7 +1063,7 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Create a valid config first - config.set_param("key1", Value::String("value1".to_string()))?; + config.set_param("key1", "value1")?; // Verify the backup was created by the first write let backup_paths = config.get_backup_paths(); @@ -1066,7 +1073,7 @@ mod tests { } // Make another write to ensure backup is created - config.set_param("key2", Value::Number(42.into()))?; + config.set_param("key2", 42)?; // Check again for (i, path) in backup_paths.iter().enumerate() { @@ -1160,15 +1167,15 @@ mod tests { let config = Config::new(config_path, TEST_KEYRING_SERVICE)?; // First, create a config with some data - config.set_param("test_key_backup", Value::String("backup_value".to_string()))?; - config.set_param("another_key", Value::Number(42.into()))?; + config.set_param("test_key_backup", "backup_value")?; + config.set_param("another_key", 42)?; // Verify the backup was created let backup_paths = config.get_backup_paths(); let primary_backup = &backup_paths[0]; // .bak file // Make sure we have a backup by doing another write - config.set_param("third_key", Value::Bool(true))?; + config.set_param("third_key", true)?; assert!(primary_backup.exists(), "Backup should exist after writes"); // Now delete the main config file to simulate it being lost @@ -1204,7 +1211,7 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Set initial values - config.set_param("key1", Value::String("value1".to_string()))?; + config.set_param("key1", "value1")?; // Verify the config file exists and is valid assert!(temp_file.path().exists()); @@ -1225,7 +1232,7 @@ mod tests { // Create multiple versions to test rotation for i in 1..=7 { - config.set_param("version", Value::Number(i.into()))?; + config.set_param("version", i)?; } let backup_paths = config.get_backup_paths(); @@ -1460,7 +1467,7 @@ mod tests { let config = Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?; // Set value in config file - config.set_param("test_precedence", Value::String("file_value".to_string()))?; + config.set_param("test_precedence", "file_value")?; // Verify file value is returned when no env var let value: String = config.get_param("test_precedence")?; diff --git a/crates/goose/src/config/declarative_providers.rs b/crates/goose/src/config/declarative_providers.rs index 10df3ff1021b..a063ec475696 100644 --- a/crates/goose/src/config/declarative_providers.rs +++ b/crates/goose/src/config/declarative_providers.rs @@ -97,7 +97,7 @@ pub fn create_custom_provider( let api_key_name = generate_api_key_name(&id); let config = Config::global(); - config.set_secret(&api_key_name, serde_json::Value::String(api_key))?; + config.set_secret(&api_key_name, &api_key)?; let model_infos: Vec = models .into_iter() @@ -147,10 +147,7 @@ pub fn update_custom_provider( let config = Config::global(); if !api_key.is_empty() { - config.set_secret( - &existing_config.api_key_env, - serde_json::Value::String(api_key), - )?; + config.set_secret(&existing_config.api_key_env, &api_key)?; } if editable { diff --git a/crates/goose/src/config/experiments.rs b/crates/goose/src/config/experiments.rs index 80135adb19a7..c60802e2bc04 100644 --- a/crates/goose/src/config/experiments.rs +++ b/crates/goose/src/config/experiments.rs @@ -35,7 +35,7 @@ impl ExperimentManager { Self::refresh_experiments(&mut experiments); experiments.insert(name.to_string(), enabled); - config.set_param("experiments", serde_json::to_value(experiments)?)?; + config.set_param("experiments", experiments)?; Ok(()) } diff --git a/crates/goose/src/config/extensions.rs b/crates/goose/src/config/extensions.rs index 4241e1b42245..fac3d6f23c67 100644 --- a/crates/goose/src/config/extensions.rs +++ b/crates/goose/src/config/extensions.rs @@ -101,15 +101,9 @@ fn get_extensions_map() -> HashMap { fn save_extensions_map(extensions: HashMap) { let config = Config::global(); - match serde_json::to_value(extensions) { - Ok(value) => { - if let Err(e) = config.set_param(EXTENSIONS_CONFIG_KEY, value) { - tracing::debug!("Failed to save extensions config: {}", e); - } - } - Err(e) => { - tracing::debug!("Failed to serialize extensions: {}", e); - } + if let Err(e) = config.set_param(EXTENSIONS_CONFIG_KEY, &extensions) { + // TODO(jack) why is this just a debug statement? + tracing::debug!("Failed to save extensions config: {}", e); } } diff --git a/crates/goose/src/config/goose_mode.rs b/crates/goose/src/config/goose_mode.rs new file mode 100644 index 000000000000..e778aa8df729 --- /dev/null +++ b/crates/goose/src/config/goose_mode.rs @@ -0,0 +1,26 @@ +use std::str::FromStr; + +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum GooseMode { + Auto, + Approve, + SmartApprove, + Chat, +} + +impl FromStr for GooseMode { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "auto" => Ok(GooseMode::Auto), + "approve" => Ok(GooseMode::Approve), + "smart_approve" => Ok(GooseMode::SmartApprove), + "chat" => Ok(GooseMode::Chat), + _ => Err(format!("invalid mode: {}", s)), + } + } +} diff --git a/crates/goose/src/config/mod.rs b/crates/goose/src/config/mod.rs index c37a49e66b89..ffae26d460aa 100644 --- a/crates/goose/src/config/mod.rs +++ b/crates/goose/src/config/mod.rs @@ -2,6 +2,7 @@ pub mod base; pub mod declarative_providers; mod experiments; pub mod extensions; +pub mod goose_mode; pub mod paths; pub mod permission; pub mod search_path; @@ -16,6 +17,7 @@ pub use extensions::{ get_all_extension_names, get_all_extensions, get_enabled_extensions, get_extension_by_name, is_extension_enabled, remove_extension, set_extension, set_extension_enabled, ExtensionEntry, }; +pub use goose_mode::GooseMode; pub use permission::PermissionManager; pub use signup_openrouter::configure_openrouter; pub use signup_tetrate::configure_tetrate; diff --git a/crates/goose/src/config/signup_openrouter/mod.rs b/crates/goose/src/config/signup_openrouter/mod.rs index cc5c8b079c06..0423727079ec 100644 --- a/crates/goose/src/config/signup_openrouter/mod.rs +++ b/crates/goose/src/config/signup_openrouter/mod.rs @@ -162,14 +162,10 @@ impl PkceAuthFlow { pub use self::PkceAuthFlow as OpenRouterAuth; use crate::config::Config; -use serde_json::Value; pub fn configure_openrouter(config: &Config, api_key: String) -> Result<()> { - config.set_secret("OPENROUTER_API_KEY", Value::String(api_key))?; - config.set_param("GOOSE_PROVIDER", Value::String("openrouter".to_string()))?; - config.set_param( - "GOOSE_MODEL", - Value::String(OPENROUTER_DEFAULT_MODEL.to_string()), - )?; + config.set_secret("OPENROUTER_API_KEY", &api_key)?; + config.set_goose_provider("openrouter")?; + config.set_goose_model(OPENROUTER_DEFAULT_MODEL)?; Ok(()) } diff --git a/crates/goose/src/config/signup_tetrate/mod.rs b/crates/goose/src/config/signup_tetrate/mod.rs index b8b97c967a6c..b868983a8344 100644 --- a/crates/goose/src/config/signup_tetrate/mod.rs +++ b/crates/goose/src/config/signup_tetrate/mod.rs @@ -163,14 +163,10 @@ impl PkceAuthFlow { pub use self::PkceAuthFlow as TetrateAuth; use crate::config::Config; -use serde_json::Value; pub fn configure_tetrate(config: &Config, api_key: String) -> Result<()> { - config.set_secret("TETRATE_API_KEY", Value::String(api_key))?; - config.set_param("GOOSE_PROVIDER", Value::String("tetrate".to_string()))?; - config.set_param( - "GOOSE_MODEL", - Value::String(TETRATE_DEFAULT_MODEL.to_string()), - )?; + config.set_secret("TETRATE_API_KEY", &api_key)?; + config.set_goose_provider("tetrate")?; + config.set_goose_model(TETRATE_DEFAULT_MODEL)?; Ok(()) } diff --git a/crates/goose/src/config/signup_tetrate/tests.rs b/crates/goose/src/config/signup_tetrate/tests.rs index 8335337c2fd3..64f9136beb90 100644 --- a/crates/goose/src/config/signup_tetrate/tests.rs +++ b/crates/goose/src/config/signup_tetrate/tests.rs @@ -76,12 +76,9 @@ fn test_configure_tetrate() { config.get_secret::("TETRATE_API_KEY").unwrap(), test_key ); + assert_eq!(config.get_goose_provider().unwrap(), "tetrate"); assert_eq!( - config.get_param::("GOOSE_PROVIDER").unwrap(), - "tetrate" - ); - assert_eq!( - config.get_param::("GOOSE_MODEL").unwrap(), + config.get_goose_model().unwrap(), TETRATE_DEFAULT_MODEL.to_string() ); } diff --git a/crates/goose/src/oauth/persist.rs b/crates/goose/src/oauth/persist.rs index cf6fccaa1481..1600b8424862 100644 --- a/crates/goose/src/oauth/persist.rs +++ b/crates/goose/src/oauth/persist.rs @@ -27,9 +27,8 @@ pub async fn save_credentials( token_response, }; - let value = serde_json::to_value(&credentials)?; let key = secret_key(name); - config.set_secret(&key, value)?; + config.set_secret(&key, &credentials)?; Ok(()) } diff --git a/crates/goose/src/permission/permission_inspector.rs b/crates/goose/src/permission/permission_inspector.rs index fe4a347d4b43..88b99a6b05d9 100644 --- a/crates/goose/src/permission/permission_inspector.rs +++ b/crates/goose/src/permission/permission_inspector.rs @@ -1,6 +1,6 @@ use crate::agents::extension_manager_extension::MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE; use crate::config::permission::PermissionLevel; -use crate::config::PermissionManager; +use crate::config::{GooseMode, PermissionManager}; use crate::conversation::message::{Message, ToolRequest}; use crate::permission::permission_judge::PermissionCheckResult; use crate::tool_inspection::{InspectionAction, InspectionResult, ToolInspector}; @@ -12,7 +12,7 @@ use tokio::sync::Mutex; /// Permission Inspector that handles tool permission checking pub struct PermissionInspector { - mode: Arc>, + mode: Arc>, readonly_tools: HashSet, regular_tools: HashSet, pub permission_manager: Arc>, @@ -20,7 +20,7 @@ pub struct PermissionInspector { impl PermissionInspector { pub fn new( - mode: String, + mode: GooseMode, readonly_tools: HashSet, regular_tools: HashSet, ) -> Self { @@ -33,7 +33,7 @@ impl PermissionInspector { } pub fn with_permission_manager( - mode: String, + mode: GooseMode, readonly_tools: HashSet, regular_tools: HashSet, permission_manager: Arc>, @@ -47,7 +47,7 @@ impl PermissionInspector { } /// Update the mode of this permission inspector - pub async fn update_mode(&self, new_mode: String) { + pub async fn update_mode(&self, new_mode: GooseMode) { let mut mode = self.mode.lock().await; *mode = new_mode; } @@ -139,45 +139,42 @@ impl ToolInspector for PermissionInspector { if let Ok(tool_call) = &request.tool_call { let tool_name = &tool_call.name; - // Handle different modes - let action = if *mode == "chat" { - // In chat mode, all tools are skipped (handled elsewhere) - continue; - } else if *mode == "auto" { - // In auto mode, all tools are approved - InspectionAction::Allow - } else { - // Smart mode - check permissions - - // 1. Check user-defined permission first - if let Some(level) = permission_manager.get_user_permission(tool_name) { - match level { - PermissionLevel::AlwaysAllow => InspectionAction::Allow, - PermissionLevel::NeverAllow => InspectionAction::Deny, - PermissionLevel::AskBefore => InspectionAction::RequireApproval(None), + let action = match *mode { + GooseMode::Chat => continue, + GooseMode::Auto => InspectionAction::Allow, + GooseMode::Approve | GooseMode::SmartApprove => { + // 1. Check user-defined permission first + if let Some(level) = permission_manager.get_user_permission(tool_name) { + match level { + PermissionLevel::AlwaysAllow => InspectionAction::Allow, + PermissionLevel::NeverAllow => InspectionAction::Deny, + PermissionLevel::AskBefore => { + InspectionAction::RequireApproval(None) + } + } + } + // 2. Check if it's a readonly or regular tool (both pre-approved) + else if self.readonly_tools.contains(tool_name.as_ref()) + || self.regular_tools.contains(tool_name.as_ref()) + { + InspectionAction::Allow + } + // 4. Special case for extension management + else if tool_name == MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE { + InspectionAction::RequireApproval(Some( + "Extension management requires approval for security".to_string(), + )) + } + // 5. Default: require approval for unknown tools + else { + InspectionAction::RequireApproval(None) } - } - // 2. Check if it's a readonly or regular tool (both pre-approved) - else if self.readonly_tools.contains(tool_name.as_ref()) - || self.regular_tools.contains(tool_name.as_ref()) - { - InspectionAction::Allow - } - // 4. Special case for extension management - else if tool_name == MANAGE_EXTENSIONS_TOOL_NAME_COMPLETE { - InspectionAction::RequireApproval(Some( - "Extension management requires approval for security".to_string(), - )) - } - // 5. Default: require approval for unknown tools - else { - InspectionAction::RequireApproval(None) } }; let reason = match &action { InspectionAction::Allow => { - if *mode == "auto" { + if *mode == GooseMode::Auto { "Auto mode - all tools approved".to_string() } else if self.readonly_tools.contains(tool_name.as_ref()) { "Tool marked as read-only".to_string() diff --git a/crates/goose/src/providers/claude_code.rs b/crates/goose/src/providers/claude_code.rs index 9683c2ee03d4..e64a212bd2d9 100644 --- a/crates/goose/src/providers/claude_code.rs +++ b/crates/goose/src/providers/claude_code.rs @@ -10,7 +10,7 @@ use tokio::process::Command; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; use super::utils::RequestLog; -use crate::config::Config; +use crate::config::{Config, GooseMode}; use crate::conversation::message::{Message, MessageContent}; use crate::model::ModelConfig; use rmcp::model::Tool; @@ -338,10 +338,8 @@ impl ClaudeCodeProvider { // Add permission mode based on GOOSE_MODE setting let config = Config::global(); - if let Ok(goose_mode) = config.get_param::("GOOSE_MODE") { - if goose_mode.as_str() == "auto" { - cmd.arg("--permission-mode").arg("acceptEdits"); - } + if let Ok(GooseMode::Auto) = config.get_goose_mode() { + cmd.arg("--permission-mode").arg("acceptEdits"); } cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); @@ -523,18 +521,6 @@ mod tests { use super::ModelConfig; use super::*; - #[test] - fn test_permission_mode_flag_construction() { - // Test that in auto mode, the --permission-mode acceptEdits flag is added - std::env::set_var("GOOSE_MODE", "auto"); - - let config = Config::global(); - let goose_mode: String = config.get_param("GOOSE_MODE").unwrap(); - assert_eq!(goose_mode, "auto"); - - std::env::remove_var("GOOSE_MODE"); - } - #[tokio::test] async fn test_claude_code_invalid_model_no_fallback() { // Test that an invalid model is kept as-is (no fallback) diff --git a/crates/goose/src/providers/githubcopilot.rs b/crates/goose/src/providers/githubcopilot.rs index 08a7074c48ba..1b503aa50a38 100644 --- a/crates/goose/src/providers/githubcopilot.rs +++ b/crates/goose/src/providers/githubcopilot.rs @@ -235,7 +235,7 @@ impl GithubCopilotProvider { .get_access_token() .await .context("unable to login into github")?; - config.set_secret("GITHUB_COPILOT_TOKEN", Value::String(token.clone()))?; + config.set_secret("GITHUB_COPILOT_TOKEN", &token)?; token } _ => return Err(err.into()), @@ -500,7 +500,7 @@ impl Provider for GithubCopilotProvider { // Save the token config - .set_secret("GITHUB_COPILOT_TOKEN", Value::String(token)) + .set_secret("GITHUB_COPILOT_TOKEN", &token) .map_err(|e| ProviderError::ExecutionError(format!("Failed to save token: {}", e)))?; Ok(()) diff --git a/crates/goose/src/providers/ollama.rs b/crates/goose/src/providers/ollama.rs index 3a180084634b..87f17aabd9ab 100644 --- a/crates/goose/src/providers/ollama.rs +++ b/crates/goose/src/providers/ollama.rs @@ -6,6 +6,7 @@ use super::utils::{ get_model, handle_response_openai_compat, handle_status_openai_compat, RequestLog, }; use crate::config::declarative_providers::DeclarativeProviderConfig; +use crate::config::GooseMode; use crate::conversation::message::Message; use crate::conversation::Conversation; @@ -199,8 +200,12 @@ impl Provider for OllamaProvider { tools: &[Tool], ) -> Result<(Message, ProviderUsage), ProviderError> { let config = crate::config::Config::global(); - let goose_mode = config.get_param("GOOSE_MODE").unwrap_or("auto".to_string()); - let filtered_tools = if goose_mode == "chat" { &[] } else { tools }; + let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto); + let filtered_tools = if goose_mode == GooseMode::Chat { + &[] + } else { + tools + }; let payload = create_request( &self.model, diff --git a/crates/goose/src/scheduler.rs b/crates/goose/src/scheduler.rs index 85269ae2fa37..0fd040817e1b 100644 --- a/crates/goose/src/scheduler.rs +++ b/crates/goose/src/scheduler.rs @@ -1104,7 +1104,7 @@ async fn run_scheduled_job_internal( agent_provider = provider; } else { let global_config = Config::global(); - let provider_name: String = match global_config.get_param("GOOSE_PROVIDER") { + let provider_name: String = match global_config.get_goose_provider() { Ok(name) => name, Err(_) => return Err(JobExecutionError { job_id: job.id.clone(), @@ -1114,7 +1114,7 @@ async fn run_scheduled_job_internal( }), }; let model_name: String = - match global_config.get_param("GOOSE_MODEL") { + match global_config.get_goose_model() { Ok(name) => name, Err(_) => return Err(JobExecutionError { job_id: job.id.clone(), diff --git a/crates/goose/src/tool_inspection.rs b/crates/goose/src/tool_inspection.rs index 56f1cdce66ac..2e372c91ae96 100644 --- a/crates/goose/src/tool_inspection.rs +++ b/crates/goose/src/tool_inspection.rs @@ -2,6 +2,7 @@ use anyhow::Result; use async_trait::async_trait; use std::collections::HashMap; +use crate::config::GooseMode; use crate::conversation::message::{Message, ToolRequest}; use crate::permission::permission_inspector::PermissionInspector; use crate::permission::permission_judge::PermissionCheckResult; @@ -116,7 +117,7 @@ impl ToolInspectionManager { } /// Update the permission inspector's mode - pub async fn update_permission_inspector_mode(&self, mode: String) { + pub async fn update_permission_inspector_mode(&self, mode: GooseMode) { for inspector in &self.inspectors { if inspector.name() == "permission" { // Downcast to PermissionInspector to access update_mode method diff --git a/crates/goose/src/tracing/otlp_layer.rs b/crates/goose/src/tracing/otlp_layer.rs index 958e188f31a1..b8edd745e125 100644 --- a/crates/goose/src/tracing/otlp_layer.rs +++ b/crates/goose/src/tracing/otlp_layer.rs @@ -301,16 +301,10 @@ mod tests { // Set values in config test_config - .set_param( - "otel_exporter_otlp_endpoint", - serde_json::Value::String("http://config:4318".to_string()), - ) + .set_param("otel_exporter_otlp_endpoint", "http://config:4318") .unwrap(); test_config - .set_param( - "otel_exporter_otlp_timeout", - serde_json::Value::Number(3000.into()), - ) + .set_param("otel_exporter_otlp_timeout", 3000) .unwrap(); // Test that from_config reads from the config file From 07a044cb79a9ce467538dff9f032515c95a9868e Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Thu, 30 Oct 2025 16:04:38 -0400 Subject: [PATCH 040/121] feat/fix: set optional config params, and don't overwrite unset secrets (#5325) Signed-off-by: fbalicchia --- .../src/routes/config_management.rs | 59 +++-- .../settings/providers/ProviderGrid.tsx | 91 +++---- .../modal/ProviderConfiguationModal.tsx | 184 ++++---------- .../providers/modal/ProviderModalProvider.tsx | 65 ----- .../forms/DefaultProviderSetupForm.tsx | 231 +++++++++++------- .../modal/subcomponents/forms/OllamaForm.tsx | 149 ----------- .../handlers/DefaultSubmitHandler.tsx | 4 +- .../handlers/OllamaSubmitHandler.tsx | 7 - .../providers/subcomponents/ProviderCard.tsx | 7 +- ui/desktop/src/components/ui/input.tsx | 2 +- 10 files changed, 276 insertions(+), 523 deletions(-) delete mode 100644 ui/desktop/src/components/settings/providers/modal/ProviderModalProvider.tsx delete mode 100644 ui/desktop/src/components/settings/providers/modal/subcomponents/forms/OllamaForm.tsx delete mode 100644 ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/OllamaSubmitHandler.tsx diff --git a/crates/goose-server/src/routes/config_management.rs b/crates/goose-server/src/routes/config_management.rs index 8965b4e783e4..2761fdb7a1a4 100644 --- a/crates/goose-server/src/routes/config_management.rs +++ b/crates/goose-server/src/routes/config_management.rs @@ -88,6 +88,19 @@ pub struct UpdateCustomProviderRequest { pub supports_streaming: Option, } +#[derive(Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct MaskedSecret { + pub masked_value: String, +} + +#[derive(Serialize, ToSchema)] +#[serde(untagged)] +pub enum ConfigValueResponse { + Value(Value), + MaskedValue(MaskedSecret), +} + #[utoipa::path( post, path = "/config/upsert", @@ -134,6 +147,22 @@ pub async fn remove_config(Json(query): Json) -> Result String { + let as_string = match secret { + Value::String(s) => s, + _ => serde_json::to_string(&secret).unwrap_or_else(|_| secret.to_string()), + }; + + let chars: Vec<_> = as_string.chars().collect(); + let show_len = std::cmp::min(chars.len() / 2, SECRET_MASK_SHOW_LEN); + let visible: String = chars.iter().take(show_len).collect(); + let mask = "*".repeat(chars.len() - show_len); + + format!("{}{}", visible, mask) +} + #[utoipa::path( post, path = "/config/read", @@ -143,12 +172,14 @@ pub async fn remove_config(Json(query): Json) -> Result) -> Result, StatusCode> { +pub async fn read_config( + Json(query): Json, +) -> Result, StatusCode> { if query.key == "model-limits" { let limits = ModelConfig::get_all_model_limits(); - return Ok(Json( + return Ok(Json(ConfigValueResponse::Value( serde_json::to_value(limits).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?, - )); + ))); } let config = Config::global(); @@ -156,18 +187,14 @@ pub async fn read_config(Json(query): Json) -> Result { if query.is_secret { - Value::Bool(true) - } else { - value - } - } - Err(ConfigError::NotFound(_)) => { - if query.is_secret { - Value::Bool(false) + ConfigValueResponse::MaskedValue(MaskedSecret { + masked_value: mask_secret(value), + }) } else { - Value::Null + ConfigValueResponse::Value(value) } } + Err(ConfigError::NotFound(_)) => ConfigValueResponse::Value(Value::Null), Err(_) => { return Err(StatusCode::INTERNAL_SERVER_ERROR); } @@ -752,10 +779,12 @@ mod tests { .await; assert!(result.is_ok()); - let response = result.unwrap(); + let response = match result.unwrap().0 { + ConfigValueResponse::Value(value) => value, + ConfigValueResponse::MaskedValue(_) => panic!("unexpected secret"), + }; - let limits: Vec = - serde_json::from_value(response.0).unwrap(); + let limits: Vec = serde_json::from_value(response).unwrap(); assert!(!limits.is_empty()); let gpt4_limit = limits.iter().find(|l| l.pattern == "gpt-4o"); diff --git a/ui/desktop/src/components/settings/providers/ProviderGrid.tsx b/ui/desktop/src/components/settings/providers/ProviderGrid.tsx index b4bb70fcf23e..f970e9335678 100644 --- a/ui/desktop/src/components/settings/providers/ProviderGrid.tsx +++ b/ui/desktop/src/components/settings/providers/ProviderGrid.tsx @@ -1,7 +1,6 @@ import React, { memo, useMemo, useCallback, useState } from 'react'; import { ProviderCard } from './subcomponents/ProviderCard'; import CardContainer from './subcomponents/CardContainer'; -import { ProviderModalProvider, useProviderModal } from './modal/ProviderModalProvider'; import ProviderConfigurationModal from './modal/ProviderConfiguationModal'; import { DeclarativeProviderConfig, @@ -47,7 +46,7 @@ const CustomProviderCard = memo(function CustomProviderCard({ onClick }: { onCli ); }); -const ProviderCards = memo(function ProviderCards({ +function ProviderCards({ providers, isOnboarding, refreshProviders, @@ -58,7 +57,7 @@ const ProviderCards = memo(function ProviderCards({ refreshProviders?: () => void; onProviderLaunch: (provider: ProviderDetails) => void; }) { - const { openModal } = useProviderModal(); + const [configuringProvider, setConfiguringProvider] = useState(null); const [showCustomProviderModal, setShowCustomProviderModal] = useState(false); const [editingProvider, setEditingProvider] = useState<{ id: string; @@ -66,6 +65,11 @@ const ProviderCards = memo(function ProviderCards({ isEditable: boolean; } | null>(null); + const openModal = useCallback( + (provider: ProviderDetails) => setConfiguringProvider(provider), + [] + ); + const configureProviderViaModal = useCallback( async (provider: ProviderDetails) => { if (provider.provider_type === 'Custom' || provider.provider_type === 'Declarative') { @@ -81,22 +85,10 @@ const ProviderCards = memo(function ProviderCards({ setShowCustomProviderModal(true); } } else { - openModal(provider, { - onSubmit: () => { - if (refreshProviders) { - refreshProviders(); - } - }, - onDelete: (_values: unknown) => { - if (refreshProviders) { - refreshProviders(); - } - }, - formProps: {}, - }); + openModal(provider); } }, - [openModal, refreshProviders] + [openModal] ); const handleUpdateCustomProvider = useCallback( @@ -123,20 +115,12 @@ const ProviderCards = memo(function ProviderCards({ setEditingProvider(null); }, []); - const deleteProviderConfigViaModal = useCallback( - (provider: ProviderDetails) => { - openModal(provider, { - onDelete: (_values: unknown) => { - // Only refresh if the function is provided - if (refreshProviders) { - refreshProviders(); - } - }, - formProps: {}, - }); - }, - [openModal, refreshProviders] - ); + const onCloseProviderConfig = useCallback(() => { + setConfiguringProvider(null); + if (refreshProviders) { + refreshProviders(); + } + }, [refreshProviders]); const handleCreateCustomProvider = useCallback( async (data: UpdateCustomProviderRequest) => { @@ -160,7 +144,6 @@ const ProviderCards = memo(function ProviderCards({ key={provider.name} provider={provider} onConfigure={() => configureProviderViaModal(provider)} - onDelete={() => deleteProviderConfigViaModal(provider)} onLaunch={() => onProviderLaunch(provider)} isOnboarding={isOnboarding} /> @@ -171,13 +154,7 @@ const ProviderCards = memo(function ProviderCards({ ); return cards; - }, [ - providers, - isOnboarding, - configureProviderViaModal, - deleteProviderConfigViaModal, - onProviderLaunch, - ]); + }, [providers, isOnboarding, configureProviderViaModal, onProviderLaunch]); const initialData = editingProvider && { engine: editingProvider.config.engine.toLowerCase() + '_compatible', @@ -206,11 +183,17 @@ const ProviderCards = memo(function ProviderCards({ /> {' '} + {configuringProvider && ( + + )} ); -}); +} -export default memo(function ProviderGrid({ +export default function ProviderGrid({ providers, isOnboarding, refreshProviders, @@ -221,20 +204,14 @@ export default memo(function ProviderGrid({ refreshProviders?: () => void; onProviderLaunch?: (provider: ProviderDetails) => void; }) { - // Memoize the modal provider and its children to avoid recreating on every render - const modalProviderContent = useMemo( - () => ( - - {})} - /> - - - ), - [providers, isOnboarding, refreshProviders, onProviderLaunch] + return ( + + {})} + /> + ); - return {modalProviderContent}; -}); +} diff --git a/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx b/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx index b8971a69b6de..e04b5ec49a13 100644 --- a/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx +++ b/ui/desktop/src/components/settings/providers/modal/ProviderConfiguationModal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { Dialog, DialogContent, @@ -7,198 +7,123 @@ import { DialogHeader, DialogTitle, } from '../../../ui/dialog'; -import DefaultProviderSetupForm from './subcomponents/forms/DefaultProviderSetupForm'; +import DefaultProviderSetupForm, { + ConfigInput, +} from './subcomponents/forms/DefaultProviderSetupForm'; import ProviderSetupActions from './subcomponents/ProviderSetupActions'; import ProviderLogo from './subcomponents/ProviderLogo'; -import { useProviderModal } from './ProviderModalProvider'; import { SecureStorageNotice } from './subcomponents/SecureStorageNotice'; -import { DefaultSubmitHandler } from './subcomponents/handlers/DefaultSubmitHandler'; -import OllamaSubmitHandler from './subcomponents/handlers/OllamaSubmitHandler'; -import OllamaForm from './subcomponents/forms/OllamaForm'; +import { providerConfigSubmitHandler } from './subcomponents/handlers/DefaultSubmitHandler'; import { useConfig } from '../../../ConfigContext'; import { useModelAndProvider } from '../../../ModelAndProviderContext'; import { AlertTriangle } from 'lucide-react'; -import { ConfigKey, removeCustomProvider } from '../../../../api'; +import { ProviderDetails, removeCustomProvider } from '../../../../api'; -interface FormValues { - [key: string]: string | number | boolean | null; +interface ProviderConfigurationModalProps { + provider: ProviderDetails; + onClose: () => void; } -const customSubmitHandlerMap: Record = { - provider_name: OllamaSubmitHandler, // example -}; - -const customFormsMap: Record = { - provider_name: OllamaForm, // example -}; - -export default function ProviderConfigurationModal() { +export default function ProviderConfigurationModal({ + provider, + onClose, +}: ProviderConfigurationModalProps) { const [validationErrors, setValidationErrors] = useState>({}); const { upsert, remove } = useConfig(); const { getCurrentModelAndProvider } = useModelAndProvider(); - const { isOpen, currentProvider, modalProps, closeModal } = useProviderModal(); - const [configValues, setConfigValues] = useState>({}); + const [configValues, setConfigValues] = useState>({}); const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); - const [isActiveProvider, setIsActiveProvider] = useState(false); // New state for tracking active provider - const [requiredParameters, setRequiredParameters] = useState([]); // New state for tracking active provider + const [isActiveProvider, setIsActiveProvider] = useState(false); - useEffect(() => { - if (isOpen && currentProvider) { - // Reset form state when the modal opens with a new provider - const requiredParameters = currentProvider.metadata.config_keys.filter( - (param) => param.required === true - ); - setRequiredParameters(requiredParameters); - setConfigValues({}); - setValidationErrors({}); - setShowDeleteConfirmation(false); - setIsActiveProvider(false); // Reset active provider state - } - }, [isOpen, currentProvider]); - - if (!isOpen || !currentProvider) return null; + const requiredParameters = provider.metadata.config_keys.filter( + (param) => param.required === true + ); - const isConfigured = currentProvider.is_configured; + const isConfigured = provider.is_configured; const headerText = showDeleteConfirmation - ? `Delete configuration for ${currentProvider.metadata.display_name}` - : `Configure ${currentProvider.metadata.display_name}`; + ? `Delete configuration for ${provider.metadata.display_name}` + : `Configure ${provider.metadata.display_name}`; - // Modify description text to show warning if it's the active provider const descriptionText = showDeleteConfirmation ? isActiveProvider ? `You cannot delete this provider while it's currently in use. Please switch to a different model first.` : 'This will permanently delete the current provider configuration.' : `Add your API key(s) for this provider to integrate into Goose`; - const SubmitHandler = - (customSubmitHandlerMap[currentProvider.name] as typeof DefaultSubmitHandler) || - DefaultSubmitHandler; - const FormComponent = - (customFormsMap[currentProvider.name] as typeof DefaultProviderSetupForm) || - DefaultProviderSetupForm; - const handleSubmitForm = async (e: React.FormEvent) => { e.preventDefault(); - console.log('Form submitted for:', currentProvider.name); - // Reset previous validation errors setValidationErrors({}); - // Validation logic - const parameters = currentProvider.metadata.config_keys || []; + const parameters = provider.metadata.config_keys || []; const errors: Record = {}; - // Check required fields parameters.forEach((parameter) => { if ( parameter.required && - (configValues[parameter.name] === undefined || - configValues[parameter.name] === null || - configValues[parameter.name] === '') + !configValues[parameter.name]?.value && + !configValues[parameter.name]?.serverValue ) { errors[parameter.name] = `${parameter.name} is required`; } }); - // If there are validation errors, stop the submission if (Object.keys(errors).length > 0) { setValidationErrors(errors); - return; // Stop the submission process + return; } - try { - // Wait for the submission to complete - await SubmitHandler(upsert, currentProvider, configValues); - - // Close the modal before triggering refreshes to avoid UI issues - closeModal(); + const toSubmit = Object.fromEntries( + Object.entries(configValues) + .filter(([_k, entry]) => !!entry.value) + .map(([k, entry]) => [k, entry.value || '']) + ); - // Call onSubmit callback if provided (from modal props) - if (modalProps.onSubmit) { - modalProps.onSubmit(configValues as FormValues); - } - } catch (error) { - console.error('Failed to save configuration:', error); - // Keep modal open if there's an error - } + await providerConfigSubmitHandler(upsert, provider, toSubmit); + onClose(); }; const handleCancel = () => { - // Reset delete confirmation state - setShowDeleteConfirmation(false); - setIsActiveProvider(false); - - // Use custom cancel handler if provided - if (modalProps.onCancel) { - modalProps.onCancel(); - } - - closeModal(); + onClose(); }; const handleDelete = async () => { - // Check if this is the currently active provider try { const providerModel = await getCurrentModelAndProvider(); - if (currentProvider.name === providerModel.provider) { - // It's the active provider - set state and show warning + if (provider.name === providerModel.provider) { setIsActiveProvider(true); setShowDeleteConfirmation(true); - return; // Exit early - don't allow actual deletion + return; } } catch (error) { console.error('Failed to check current provider:', error); } - // If we get here, it's not the active provider setIsActiveProvider(false); setShowDeleteConfirmation(true); }; const handleConfirmDelete = async () => { - // Don't proceed if this is the active provider if (isActiveProvider) { return; } - try { - const isCustomProvider = currentProvider.provider_type === 'Custom'; - - if (isCustomProvider) { - await removeCustomProvider({ - path: { id: currentProvider.name }, - }); - } else { - // Remove the provider configuration - // get the keys - const params = currentProvider.metadata.config_keys; - - // go through the keys are remove them - for (const param of params) { - await remove(param.name, param.secret); - } - } + const isCustomProvider = provider.provider_type === 'Custom'; - // Call onDelete callback if provided - // This should trigger the refreshProviders function - if (modalProps.onDelete) { - modalProps.onDelete(currentProvider.name as unknown as FormValues); + if (isCustomProvider) { + await removeCustomProvider({ + path: { id: provider.name }, + }); + } else { + const params = provider.metadata.config_keys; + for (const param of params) { + await remove(param.name, param.secret); } - - // Reset the delete confirmation state before closing - setShowDeleteConfirmation(false); - setIsActiveProvider(false); - - // Close the modal - // Close the modal after deletion and callback - closeModal(); - } catch (error) { - console.error('Failed to delete provider:', error); - // Keep modal open if there's an error } + + onClose(); }; - // Function to determine which icon to display const getModalIcon = () => { if (showDeleteConfirmation) { return ( @@ -208,11 +133,11 @@ export default function ProviderConfigurationModal() { /> ); } - return ; + return ; }; return ( - !open && closeModal()}> + !open && onClose()}> @@ -228,17 +153,16 @@ export default function ProviderConfigurationModal() { {!showDeleteConfirmation ? ( <> {/* Contains information used to set up each provider */} - {requiredParameters.length > 0 && - currentProvider.metadata.config_keys && - currentProvider.metadata.config_keys.length > 0 && } + provider.metadata.config_keys && + provider.metadata.config_keys.length > 0 && } ) : null} @@ -252,11 +176,11 @@ export default function ProviderConfigurationModal() { showDeleteConfirmation={showDeleteConfirmation} onConfirmDelete={handleConfirmDelete} onCancelDelete={() => { - setShowDeleteConfirmation(false); setIsActiveProvider(false); + setShowDeleteConfirmation(false); }} canDelete={isConfigured && !isActiveProvider} - providerName={currentProvider.metadata.display_name} + providerName={provider.metadata.display_name} isActiveProvider={isActiveProvider} />
diff --git a/ui/desktop/src/components/settings/providers/modal/ProviderModalProvider.tsx b/ui/desktop/src/components/settings/providers/modal/ProviderModalProvider.tsx deleted file mode 100644 index 5c1a48a9b29b..000000000000 --- a/ui/desktop/src/components/settings/providers/modal/ProviderModalProvider.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { createContext, useContext, useState } from 'react'; -import { ProviderDetails } from '../../../../api/types.gen'; - -interface FormValues { - [key: string]: string | number | boolean | null; -} - -interface ModalProps { - onSubmit?: (values: FormValues) => void; - onCancel?: () => void; - onDelete?: (values: FormValues) => void; - formProps?: { - initialValues?: FormValues; - validationSchema?: object; - [key: string]: unknown; - }; -} - -interface ProviderModalContextType { - isOpen: boolean; - currentProvider: ProviderDetails | null; - modalProps: ModalProps; - openModal: (provider: ProviderDetails, additionalProps?: ModalProps) => void; - closeModal: () => void; -} - -const ProviderModalContext = createContext(undefined); - -export const ProviderModalProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const [isOpen, setIsOpen] = useState(false); - const [currentProvider, setCurrentProvider] = useState(null); - const [modalProps, setModalProps] = useState({}); - - const openModal = (provider: ProviderDetails, additionalProps: ModalProps = {}) => { - setCurrentProvider(provider); - setModalProps(additionalProps); - setIsOpen(true); - }; - - const closeModal = () => { - setIsOpen(false); - }; - - return ( - - {children} - - ); -}; - -export const useProviderModal = () => { - const context = useContext(ProviderModalContext); - if (context === undefined) { - throw new Error('useProviderModal must be used within a ProviderModalProvider'); - } - return context; -}; diff --git a/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx b/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx index 6f8e2dd69476..3d15a979838c 100644 --- a/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx +++ b/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/DefaultProviderSetupForm.tsx @@ -1,17 +1,40 @@ import React, { useEffect, useMemo, useState, useCallback } from 'react'; import { Input } from '../../../../../ui/input'; -import { useConfig } from '../../../../../ConfigContext'; // Adjust this import path as needed +import { useConfig } from '../../../../../ConfigContext'; import { ProviderDetails, ConfigKey } from '../../../../../../api'; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../../../../ui/collapsible'; type ValidationErrors = Record; +type ConfigValue = string | { maskedValue: string }; +export interface ConfigInput { + serverValue?: ConfigValue; + value?: string; +} + interface DefaultProviderSetupFormProps { - configValues: Record; - setConfigValues: React.Dispatch>>; + configValues: Record; + setConfigValues: React.Dispatch>>; provider: ProviderDetails; validationErrors: ValidationErrors; } +const envToPrettyName = (envVar: string) => { + const wordReplacements: { [w: string]: string } = { + Api: 'API', + Aws: 'AWS', + Gcp: 'GCP', + }; + + return envVar + .toLowerCase() + .split('_') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .map((word) => wordReplacements[word] || word) + .join(' ') + .trim(); +}; + export default function DefaultProviderSetupForm({ configValues, setConfigValues, @@ -23,73 +46,49 @@ export default function DefaultProviderSetupForm({ [provider.metadata.config_keys] ); const [isLoading, setIsLoading] = useState(true); + const [optionalExpanded, setOptionalExpanded] = useState(false); const { read } = useConfig(); - console.log('configValues default form', configValues); - - // Initialize values when the component mounts or provider changes const loadConfigValues = useCallback(async () => { setIsLoading(true); - const newValues = { ...configValues }; + try { + const values: { [k: string]: ConfigInput } = {}; - // Try to load actual values from config for each parameter that is not secret - for (const parameter of parameters) { - try { - // Check if there's a stored value in the config system + for (const parameter of parameters) { const configKey = `${parameter.name}`; - const configResponse = await read(configKey, parameter.secret || false); - - if (configResponse) { - newValues[parameter.name] = parameter.secret ? 'true' : String(configResponse); - } else if ( - parameter.default !== undefined && - parameter.default !== null && - !configValues[parameter.name] - ) { - // Fall back to default value if no config value exists - newValues[parameter.name] = String(parameter.default); - } - } catch (error) { - console.error(`Failed to load config for ${parameter.name}:`, error); - // Fall back to default if read operation fails - if ( - parameter.default !== undefined && - parameter.default !== null && - !configValues[parameter.name] - ) { - newValues[parameter.name] = String(parameter.default); + const configValue = (await read(configKey, parameter.secret || false)) as ConfigValue; + + if (configValue) { + values[parameter.name] = { serverValue: configValue }; + } else if (parameter.default !== undefined && parameter.default !== null) { + values[parameter.name] = { value: parameter.default }; } } - } - // Update state with loaded values - setConfigValues((prev) => ({ - ...prev, - ...newValues, - })); - setIsLoading(false); - }, [configValues, parameters, read, setConfigValues]); + setConfigValues((prev) => ({ + ...prev, + ...values, + })); + } finally { + setIsLoading(false); + } + }, [parameters, read, setConfigValues]); useEffect(() => { loadConfigValues(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // Filter parameters to only show required ones - const requiredParameters = useMemo(() => { - return parameters.filter((param) => param.required === true); - }, [parameters]); - - // TODO: show all params, not just required ones - // const allParameters = useMemo(() => { - // return parameters; - // }, [parameters]); - - // Helper function to generate appropriate placeholder text const getPlaceholder = (parameter: ConfigKey): string => { - // If default is defined and not null, show it + if (parameter.secret) { + const serverValue = configValues[parameter.name]?.serverValue; + if (typeof serverValue === 'object' && 'maskedValue' in serverValue) { + return serverValue.maskedValue; + } + } + if (parameter.default !== undefined && parameter.default !== null) { - return `Default: ${parameter.default}`; + return parameter.default; } const name = parameter.name.toLowerCase(); @@ -99,66 +98,112 @@ export default function DefaultProviderSetupForm({ return parameter.name .replace(/_/g, ' ') - .replace(/([A-Z])/g, ' $1') .replace(/^./, (str) => str.toUpperCase()) .trim(); }; - // helper for custom labels - const getFieldLabel = (parameter: ConfigKey): string => { + const getFieldLabel = (parameter: ConfigKey) => { const name = parameter.name.toLowerCase(); if (name.includes('api_key')) return 'API Key'; if (name.includes('api_url') || name.includes('host')) return 'API Host'; if (name.includes('models')) return 'Models'; - return parameter.name - .replace(/_/g, ' ') - .replace(/([A-Z])/g, ' $1') - .replace(/^./, (str) => str.toUpperCase()) - .trim(); + let parameter_name = parameter.name.toUpperCase(); + if (parameter_name.startsWith(provider.name.toUpperCase().replace('-', '_'))) { + parameter_name = parameter_name.slice(provider.name.length + 1); + } + let pretty = envToPrettyName(parameter_name); + return ( + + {pretty} + ({parameter.name}) + + ); }; if (isLoading) { return
Loading configuration values...
; } - console.log('required params', requiredParameters); + function getRenderValue(parameter: ConfigKey): string | undefined { + if (parameter.secret) { + return undefined; + } + + const entry = configValues[parameter.name]; + return entry?.value || (entry?.serverValue as string) || ''; + } + + const renderParametersList = (parameters: ConfigKey[]) => { + return parameters.map((parameter) => ( +
+ + ) => { + setConfigValues((prev) => { + const newValue = { ...(prev[parameter.name] || {}), value: e.target.value }; + return { + ...prev, + [parameter.name]: newValue, + }; + }); + }} + placeholder={getPlaceholder(parameter)} + className={`w-full h-14 px-4 font-regular rounded-lg shadow-none ${ + validationErrors[parameter.name] + ? 'border-2 border-red-500' + : 'border border-borderSubtle hover:border-borderStandard' + } bg-background-default text-lg placeholder:text-textSubtle font-regular text-textStandard`} + required={parameter.required} + /> + {validationErrors[parameter.name] && ( +

{validationErrors[parameter.name]}

+ )} +
+ )); + }; + + let aboveFoldParameters = parameters.filter((p) => p.required); + let belowFoldParameters = parameters.filter((p) => !p.required); + if (aboveFoldParameters.length === 0) { + aboveFoldParameters = belowFoldParameters; + belowFoldParameters = []; + } + + const expandCtaText = `${optionalExpanded ? 'Hide' : 'Show'} ${belowFoldParameters.length} options `; + return (
- {requiredParameters.length === 0 ? ( + {aboveFoldParameters.length === 0 && belowFoldParameters.length === 0 ? (
- No required configuration for this provider. + No configuration parameters for this provider.
) : ( - requiredParameters.map((parameter) => ( -
- - ) => { - console.log(`Setting ${parameter.name} to:`, e.target.value); - setConfigValues((prev) => ({ - ...prev, - [parameter.name]: e.target.value, - })); - }} - placeholder={getPlaceholder(parameter)} - className={`w-full h-14 px-4 font-regular rounded-lg shadow-none ${ - validationErrors[parameter.name] - ? 'border-2 border-red-500' - : 'border border-borderSubtle hover:border-borderStandard' - } bg-background-default text-lg placeholder:text-textSubtle font-regular text-textStandard`} - required={parameter.required} - /> - {validationErrors[parameter.name] && ( -

{validationErrors[parameter.name]}

- )} -
- )) +
+
{renderParametersList(aboveFoldParameters)}
+ {belowFoldParameters.length > 0 && ( + + +
+ {expandCtaText} + {optionalExpanded ? '↑' : '↓'} +
+
+ + {renderParametersList(belowFoldParameters)} + +
+ )} +
)}
); diff --git a/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/OllamaForm.tsx b/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/OllamaForm.tsx deleted file mode 100644 index fba9a68fa6f3..000000000000 --- a/ui/desktop/src/components/settings/providers/modal/subcomponents/forms/OllamaForm.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { PROVIDER_REGISTRY } from '../../../ProviderRegistry'; -import { Input } from '../../../../../ui/input'; - -import React, { useState, useEffect, useCallback } from 'react'; -import { RefreshCw } from 'lucide-react'; -import CustomRadio from '../../../../../ui/CustomRadio'; - -export default function OllamaForm({ - configValues, - setConfigValues, - provider, -}: { - configValues: Record; - setConfigValues: React.Dispatch>>; - provider: { name: string; [key: string]: unknown }; -}) { - const providerEntry = PROVIDER_REGISTRY.find((p) => p.name === provider.name); - const parameters = providerEntry?.details?.parameters || []; - const [isCheckingLocal, setIsCheckingLocal] = useState(false); - const [isLocalAvailable, setIsLocalAvailable] = useState(false); - - const handleConnectionTypeChange = useCallback( - (value: string) => { - setConfigValues((prev) => ({ - ...prev, - connection_type: value, - })); - }, - [setConfigValues] - ); - - // Function to handle input changes and auto-select/deselect the host radio - const handleInputChange = (paramName: string, value: string) => { - // Update the parameter value - setConfigValues((prev) => ({ - ...prev, - [paramName]: value, - })); - - // If the user is typing, auto-select the host radio button - if (value && configValues.connection_type !== 'host') { - handleConnectionTypeChange('host'); - } - // If the input becomes empty and the host radio is selected, switch to local if available - else if (!value && configValues.connection_type === 'host') { - if (isLocalAvailable) { - handleConnectionTypeChange('local'); - } - // If local is not available, we keep the host selected but leave the input empty - } - }; - - const checkLocalAvailability = useCallback(async () => { - setIsCheckingLocal(true); - - // Dummy implementation - simulates checking local availability - try { - console.log('Checking for local Ollama instance...'); - // Simulate a network request with a delay - await new Promise((resolve) => setTimeout(resolve, 800)); - - // Randomly determine if Ollama is available (for demo purposes) - const isAvailable = Math.random() > 0.3; - setIsLocalAvailable(isAvailable); - - if (isAvailable) { - console.log('Local Ollama instance found'); - // Enable local radio button - } else { - console.log('No local Ollama instance found'); - // If current selection is local, switch to host - if (configValues.connection_type === 'local') { - handleConnectionTypeChange('host'); - } - } - } catch (error) { - console.error('Error checking for local Ollama:', error); - setIsLocalAvailable(false); - } finally { - setIsCheckingLocal(false); - } - }, [configValues.connection_type, handleConnectionTypeChange]); - - // Check local availability on initial load - useEffect(() => { - checkLocalAvailability(); - }, [checkLocalAvailability]); - - return ( -
-
Connection
- - {/* Local Option */} -
-
- Background App - -
- - handleConnectionTypeChange('local')} - disabled={!isLocalAvailable} - /> -
- - {/* Other Parameters */} - {parameters - .filter((param) => param.name !== 'host_url') // Skip host_url as we handle it above - .map((parameter) => ( -
-
- handleInputChange(parameter.name, e.target.value)} - placeholder={ - parameter.default ? parameter.default : parameter.name.replace(/_/g, ' ') - } - className="w-full h-14 px-4 font-regular rounded-lg border shadow-none border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-lg placeholder:text-gray-400 dark:placeholder:text-gray-500 font-regular text-gray-900 dark:text-gray-100" - required={parameter.default == null} - /> -
-
- handleConnectionTypeChange('host')} - /> -
-
- ))} -
- ); -} diff --git a/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx b/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx index 3356f4a8af88..2c9bb82c1500 100644 --- a/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx +++ b/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/DefaultSubmitHandler.tsx @@ -2,7 +2,7 @@ * Standalone function to submit provider configuration * Useful for components that don't want to use the hook */ -export const DefaultSubmitHandler = async ( +export const providerConfigSubmitHandler = async ( upsertFn: (key: string, value: unknown, isSecret: boolean) => Promise, provider: { name: string; @@ -15,7 +15,7 @@ export const DefaultSubmitHandler = async ( }>; }; }, - configValues: Record + configValues: Record ) => { const parameters = provider.metadata.config_keys || []; diff --git a/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/OllamaSubmitHandler.tsx b/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/OllamaSubmitHandler.tsx deleted file mode 100644 index 329babcc8656..000000000000 --- a/ui/desktop/src/components/settings/providers/modal/subcomponents/handlers/OllamaSubmitHandler.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function OllamaSubmitHandler(configValues: Record) { - // Log each field value individually for clarity - console.log('Ollama field values:'); - Object.entries(configValues).forEach(([key, value]) => { - console.log(`${key}: ${value}`); - }); -} diff --git a/ui/desktop/src/components/settings/providers/subcomponents/ProviderCard.tsx b/ui/desktop/src/components/settings/providers/subcomponents/ProviderCard.tsx index 25d4d9c9f295..4be31bdf41bc 100644 --- a/ui/desktop/src/components/settings/providers/subcomponents/ProviderCard.tsx +++ b/ui/desktop/src/components/settings/providers/subcomponents/ProviderCard.tsx @@ -1,4 +1,4 @@ -import { memo, useMemo } from 'react'; +import { useMemo } from 'react'; import CardContainer from './CardContainer'; import CardHeader from './CardHeader'; import CardBody from './CardBody'; @@ -9,11 +9,10 @@ type ProviderCardProps = { provider: ProviderDetails; onConfigure: () => void; onLaunch: () => void; - onDelete: () => void; isOnboarding: boolean; }; -export const ProviderCard = memo(function ProviderCard({ +export const ProviderCard = function ProviderCard({ provider, onConfigure, onLaunch, @@ -59,4 +58,4 @@ export const ProviderCard = memo(function ProviderCard({ } /> ); -}); +}; diff --git a/ui/desktop/src/components/ui/input.tsx b/ui/desktop/src/components/ui/input.tsx index 73fdb5155de8..39bab270b9d9 100644 --- a/ui/desktop/src/components/ui/input.tsx +++ b/ui/desktop/src/components/ui/input.tsx @@ -8,7 +8,7 @@ const Input = React.forwardRef>( Date: Thu, 30 Oct 2025 13:40:32 -0700 Subject: [PATCH 041/121] nextcamp - fix session resume when navigating back to chat in sidebar (#5370) Signed-off-by: fbalicchia --- ui/desktop/src/App.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index 5fa3fde7a047..5ae00641abc1 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -76,6 +76,8 @@ const PairRouteWrapper = ({ setFatalError, agentState, loadCurrentChat, + activeSessionId, + setActiveSessionId, }: { chat: ChatType; setChat: (chat: ChatType) => void; @@ -84,6 +86,8 @@ const PairRouteWrapper = ({ setFatalError: (value: ((prevState: string | null) => string | null) | string | null) => void; agentState: AgentState; loadCurrentChat: (context: InitializationContext) => Promise; + activeSessionId: string | null; + setActiveSessionId: (id: string | null) => void; }) => { const location = useLocation(); const setView = useNavigation(); @@ -96,11 +100,13 @@ const PairRouteWrapper = ({ // Determine which session ID to use: // 1. From route state (when navigating from Hub with a new session) - // 2. From URL params (when resuming a session) - // 3. From the existing chat state (when navigating to Pair directly) - const sessionId = routeState.resumeSessionId || resumeSessionId || chat.sessionId; + // 2. From URL params (when resuming a session or after refresh) + // 3. From active session state (when navigating back from other routes) + // 4. From the existing chat state + const sessionId = + routeState.resumeSessionId || resumeSessionId || activeSessionId || chat.sessionId; - // Update URL with session ID if it's not already there (new chat from pair) + // Update URL with session ID when on /pair route (for refresh support) useEffect(() => { if (process.env.ALPHA && sessionId && sessionId !== resumeSessionId) { setSearchParams((prev) => { @@ -110,6 +116,13 @@ const PairRouteWrapper = ({ } }, [sessionId, resumeSessionId, setSearchParams]); + // Update active session state when session ID changes + useEffect(() => { + if (process.env.ALPHA && sessionId && sessionId !== activeSessionId) { + setActiveSessionId(sessionId); + } + }, [sessionId, activeSessionId, setActiveSessionId]); + return process.env.ALPHA ? ( (null); + const { addExtension } = useConfig(); const { agentState, loadCurrentChat, resetChat } = useAgent(); const resetChatIfNecessary = useCallback(() => { @@ -574,6 +590,8 @@ export function AppInner() { setFatalError={setFatalError} setAgentWaitingMessage={setAgentWaitingMessage} setIsGoosehintsModalOpen={setIsGoosehintsModalOpen} + activeSessionId={activeSessionId} + setActiveSessionId={setActiveSessionId} /> } /> From eb98d07229917fbe5efe06731d44552d04ee128d Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:04:53 -0700 Subject: [PATCH 042/121] Removed drafts and agentIsReady in ChatInput (#5366) Signed-off-by: fbalicchia --- ui/desktop/src/App.test.tsx | 7 --- ui/desktop/src/App.tsx | 15 ++--- ui/desktop/src/components/ChatInput.tsx | 70 ++---------------------- ui/desktop/src/contexts/ChatContext.tsx | 22 -------- ui/desktop/src/contexts/DraftContext.tsx | 44 --------------- 5 files changed, 10 insertions(+), 148 deletions(-) delete mode 100644 ui/desktop/src/contexts/DraftContext.tsx diff --git a/ui/desktop/src/App.test.tsx b/ui/desktop/src/App.test.tsx index 1955821280d4..92313dfcf8cc 100644 --- a/ui/desktop/src/App.test.tsx +++ b/ui/desktop/src/App.test.tsx @@ -131,18 +131,11 @@ vi.mock('./contexts/ChatContext', () => ({ hasActiveSession: false, setRecipe: vi.fn(), clearRecipe: vi.fn(), - draft: '', - setDraft: vi.fn(), - clearDraft: vi.fn(), contextKey: 'hub', }), DEFAULT_CHAT_TITLE: 'New Chat', // Keep this from HEAD })); -vi.mock('./contexts/DraftContext', () => ({ - DraftProvider: ({ children }: { children: React.ReactNode }) => <>{children}, -})); - vi.mock('./components/ui/ConfirmationModal', () => ({ ConfirmationModal: () => null, })); diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index 5ae00641abc1..90199c4dd45b 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -27,7 +27,6 @@ import SchedulesView from './components/schedule/SchedulesView'; import ProviderSettings from './components/settings/providers/ProviderSettingsPage'; import { AppLayout } from './components/Layout/AppLayout'; import { ChatProvider } from './contexts/ChatContext'; -import { DraftProvider } from './contexts/DraftContext'; import 'react-toastify/dist/ReactToastify.css'; import { useConfig } from './components/ConfigContext'; @@ -638,13 +637,11 @@ export function AppInner() { export default function App() { return ( - - - - - - - - + + + + + + ); } diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index 863c7f65b5b7..63da447e0ce2 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -20,7 +20,6 @@ import { WaveformVisualizer } from './WaveformVisualizer'; import { toastError } from '../toasts'; import MentionPopover, { FileItemWithMatch } from './MentionPopover'; import { useDictationSettings } from '../hooks/useDictationSettings'; -import { useChatContext } from '../contexts/ChatContext'; import { COST_TRACKING_ENABLED, VOICE_DICTATION_ELEVENLABS_ENABLED } from '../updates'; import { CostTracker } from './bottom_menu/CostTracker'; import { DroppedFile, useFileDrop } from '../hooks/useFileDrop'; @@ -142,20 +141,8 @@ export default function ChatInput({ const { getCurrentModelAndProvider, currentModel, currentProvider } = useModelAndProvider(); const [tokenLimit, setTokenLimit] = useState(TOKEN_LIMIT_DEFAULT); const [isTokenLimitLoaded, setIsTokenLimitLoaded] = useState(false); - - // Draft functionality - get chat context and global draft context - // We need to handle the case where ChatInput is used without ChatProvider (e.g., in Hub) - const chatContext = useChatContext(); // This should always be available now - const agentIsReady = chatContext === null || chatContext.agentWaitingMessage === null; - const draftLoadedRef = useRef(false); - const [diagnosticsOpen, setDiagnosticsOpen] = useState(false); - // Debug logging for draft context - useEffect(() => { - // Debug logging removed - draft functionality is working correctly - }, [chatContext?.contextKey, chatContext?.draft, chatContext]); - // Save queue state (paused/interrupted) to storage useEffect(() => { try { @@ -281,9 +268,6 @@ export default function ChatInput({ setValue(initialValue); setDisplayValue(initialValue); - // Reset draft loaded flag when initialValue changes - draftLoadedRef.current = false; - // Use a functional update to get the current pastedImages // and perform cleanup. This avoids needing pastedImages in the deps. setPastedImages((currentPastedImages) => { @@ -313,38 +297,6 @@ export default function ChatInput({ } }, [recipeAccepted, initialPrompt, messages.length]); - // Draft functionality - load draft if no initial value or recipe - useEffect(() => { - // Reset draft loaded flag when context changes - draftLoadedRef.current = false; - }, [chatContext?.contextKey]); - - useEffect(() => { - // Only load draft once and if conditions are met - if (!initialValue && !recipe && !draftLoadedRef.current && chatContext) { - const draftText = chatContext.draft || ''; - - if (draftText) { - setDisplayValue(draftText); - setValue(draftText); - } - - // Always mark as loaded after checking, regardless of whether we found a draft - draftLoadedRef.current = true; - } - }, [chatContext, initialValue, recipe]); - - // Save draft when user types (debounced) - const debouncedSaveDraft = useMemo( - () => - debounce((value: string) => { - if (chatContext && chatContext.setDraft) { - chatContext.setDraft(value); - } - }, 500), // Save draft after 500ms of no typing - [chatContext] - ); - // State to track if the IME is composing (i.e., in the middle of Japanese IME input) const [isComposing, setIsComposing] = useState(false); const [historyIndex, setHistoryIndex] = useState(-1); @@ -608,13 +560,9 @@ export default function ChatInput({ const val = evt.target.value; const cursorPosition = evt.target.selectionStart; - setDisplayValue(val); // Update display immediately - updateValue(val); // Update actual value immediately for better responsiveness - debouncedSaveDraft(val); // Save draft with debounce - // Mark that the user has typed something + setDisplayValue(val); + updateValue(val); setHasUserTyped(true); - - // Check for @ mention checkForMention(val, cursorPosition, evt.target); }; @@ -769,9 +717,8 @@ export default function ChatInput({ useEffect(() => { return () => { debouncedAutosize.cancel?.(); - debouncedSaveDraft.cancel?.(); }; - }, [debouncedAutosize, debouncedSaveDraft]); + }, [debouncedAutosize]); // Handlers for composition events, which are crucial for proper IME behavior const handleCompositionStart = () => { @@ -910,7 +857,6 @@ export default function ChatInput({ const canSubmit = !isLoading && - agentIsReady && (displayValue.trim() || pastedImages.some((img) => img.filePath && !img.error && !img.isLoading) || allDroppedFiles.some((file) => !file.error && !file.isLoading)); @@ -964,11 +910,6 @@ export default function ChatInput({ setIsInGlobalHistory(false); setHasUserTyped(false); - // Clear draft when message is sent - if (chatContext && chatContext.clearDraft) { - chatContext.clearDraft(); - } - // Clear both parent and local dropped files after processing if (onFilesProcessed && droppedFiles.length > 0) { onFilesProcessed(); @@ -980,7 +921,6 @@ export default function ChatInput({ }, [ allDroppedFiles, - chatContext, displayValue, droppedFiles.length, handleSubmit, @@ -1066,7 +1006,6 @@ export default function ChatInput({ e.preventDefault(); const canSubmit = !isLoading && - agentIsReady && (displayValue.trim() || pastedImages.some((img) => img.filePath && !img.error && !img.isLoading) || allDroppedFiles.some((file) => !file.error && !file.isLoading)); @@ -1120,7 +1059,6 @@ export default function ChatInput({ isAnyDroppedFileLoading || isRecording || isTranscribing || - !agentIsReady || isExtensionsLoading; // Queue management functions - no storage persistence, only in-memory @@ -1372,7 +1310,7 @@ export default function ChatInput({ ? 'Recording...' : isTranscribing ? 'Transcribing...' - : (chatContext?.agentWaitingMessage ?? 'Send')} + : 'Send'}

diff --git a/ui/desktop/src/contexts/ChatContext.tsx b/ui/desktop/src/contexts/ChatContext.tsx index eb0537574cef..49ec41495295 100644 --- a/ui/desktop/src/contexts/ChatContext.tsx +++ b/ui/desktop/src/contexts/ChatContext.tsx @@ -1,7 +1,6 @@ import React, { createContext, useContext, ReactNode } from 'react'; import { ChatType } from '../types/chat'; import { Recipe } from '../recipe'; -import { useDraftContext } from './DraftContext'; // TODO(Douwe): We should not need this anymore export const DEFAULT_CHAT_TITLE = 'New Chat'; @@ -13,10 +12,6 @@ interface ChatContextType { hasActiveSession: boolean; setRecipe: (recipe: Recipe | null) => void; clearRecipe: () => void; - // Draft functionality - draft: string; - setDraft: (draft: string) => void; - clearDraft: () => void; // Context identification contextKey: string; // 'hub' or 'pair-{sessionId}' agentWaitingMessage: string | null; @@ -39,19 +34,6 @@ export const ChatProvider: React.FC = ({ agentWaitingMessage, contextKey = 'hub', }) => { - const draftContext = useDraftContext(); - - // Draft functionality using the app-level DraftContext - const draft = draftContext.getDraft(contextKey); - - const setDraft = (newDraft: string) => { - draftContext.setDraft(contextKey, newDraft); - }; - - const clearDraft = () => { - draftContext.clearDraft(contextKey); - }; - const resetChat = () => { setChat({ sessionId: '', @@ -61,7 +43,6 @@ export const ChatProvider: React.FC = ({ recipe: null, recipeParameterValues: null, }); - clearDraft(); }; const setRecipe = (recipe: Recipe | null) => { @@ -88,9 +69,6 @@ export const ChatProvider: React.FC = ({ hasActiveSession, setRecipe, clearRecipe, - draft, - setDraft, - clearDraft, contextKey, agentWaitingMessage, }; diff --git a/ui/desktop/src/contexts/DraftContext.tsx b/ui/desktop/src/contexts/DraftContext.tsx deleted file mode 100644 index 9238f54bfd9f..000000000000 --- a/ui/desktop/src/contexts/DraftContext.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { createContext, useContext, useState, ReactNode } from 'react'; - -interface DraftContextType { - getDraft: (contextKey: string) => string; - setDraft: (contextKey: string, draft: string) => void; - clearDraft: (contextKey: string) => void; -} - -const DraftContext = createContext(undefined); - -export const DraftProvider: React.FC<{ children: ReactNode }> = ({ children }) => { - // Store all drafts by contextKey - const [drafts, setDrafts] = useState>({}); - - const getDraft = (contextKey: string): string => { - return drafts[contextKey] || ''; - }; - - const setDraft = (contextKey: string, draft: string) => { - setDrafts((prev) => ({ ...prev, [contextKey]: draft })); - }; - - const clearDraft = (contextKey: string) => { - setDrafts((prev) => { - const newDrafts = { ...prev }; - delete newDrafts[contextKey]; - return newDrafts; - }); - }; - - return ( - - {children} - - ); -}; - -export const useDraftContext = (): DraftContextType => { - const context = useContext(DraftContext); - if (context === undefined) { - throw new Error('useDraftContext must be used within a DraftProvider'); - } - return context; -}; From c0e8bfcaede17dd74c7d484f3939520068d9e8e6 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Thu, 30 Oct 2025 17:58:44 -0400 Subject: [PATCH 043/121] keep the order of keys in config.yaml (#5468) Signed-off-by: fbalicchia --- Cargo.lock | 38 +++-- crates/goose-cli/src/commands/info.rs | 32 ++-- .../src/routes/config_management.rs | 6 +- crates/goose/Cargo.toml | 1 + crates/goose/src/agents/extension.rs | 14 ++ crates/goose/src/config/base.rs | 144 ++++++++---------- crates/goose/src/config/extensions.rs | 66 +++----- crates/goose/src/providers/bedrock.rs | 4 +- crates/goose/src/providers/sagemaker_tgi.rs | 4 +- 9 files changed, 142 insertions(+), 167 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7044d99416f4..8f8f79596d96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2633,6 +2633,7 @@ dependencies = [ "fs2", "futures", "include_dir", + "indexmap 2.12.0", "indoc", "insta", "jsonschema", @@ -2900,7 +2901,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.1", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -2919,7 +2920,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.2.0", - "indexmap 2.7.1", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -2963,6 +2964,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.8.4" @@ -3511,13 +3518,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -3969,7 +3977,7 @@ dependencies = [ "chrono", "encoding_rs", "flate2", - "indexmap 2.7.1", + "indexmap 2.12.0", "itoa", "log", "md-5", @@ -4872,7 +4880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.7.1", + "indexmap 2.12.0", "quick-xml 0.32.0", "serde", "time", @@ -5025,7 +5033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54" dependencies = [ "futures", - "indexmap 2.7.1", + "indexmap 2.12.0", "nix 0.29.0", "tokio", "tracing", @@ -5992,7 +6000,7 @@ version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.12.0", "itoa", "memchr", "ryu", @@ -6041,7 +6049,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.1", + "indexmap 2.12.0", "serde", "serde_derive", "serde_json", @@ -6067,7 +6075,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.12.0", "itoa", "ryu", "serde", @@ -6314,7 +6322,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.7.1", + "indexmap 2.12.0", "log", "memchr", "once_cell", @@ -7078,7 +7086,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.12.0", "serde", "serde_spanned", "toml_datetime", @@ -7562,7 +7570,7 @@ version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.12.0", "serde", "serde_json", "utoipa-gen", @@ -8679,7 +8687,7 @@ dependencies = [ "crc32fast", "crossbeam-utils", "flate2", - "indexmap 2.7.1", + "indexmap 2.12.0", "memchr", "zopfli", ] diff --git a/crates/goose-cli/src/commands/info.rs b/crates/goose-cli/src/commands/info.rs index 0f0debc1c28a..3bedde5e439a 100644 --- a/crates/goose-cli/src/commands/info.rs +++ b/crates/goose-cli/src/commands/info.rs @@ -40,26 +40,22 @@ pub fn handle_info(verbose: bool) -> Result<()> { // Print verbose info if requested if verbose { println!("\n{}", style("goose Configuration:").cyan().bold()); - match config.load_values() { - Ok(values) => { - if values.is_empty() { - println!(" No configuration values set"); - println!( - " Run '{}' to configure goose", - style("goose configure").cyan() - ); - } else { - let sorted_values: std::collections::BTreeMap<_, _> = - values.iter().map(|(k, v)| (k.clone(), v.clone())).collect(); - - if let Ok(yaml) = serde_yaml::to_string(&sorted_values) { - for line in yaml.lines() { - println!(" {}", line); - } - } + let values = config.all_values()?; + if values.is_empty() { + println!(" No configuration values set"); + println!( + " Run '{}' to configure goose", + style("goose configure").cyan() + ); + } else { + let sorted_values: std::collections::BTreeMap<_, _> = + values.iter().map(|(k, v)| (k.clone(), v.clone())).collect(); + + if let Ok(yaml) = serde_yaml::to_string(&sorted_values) { + for line in yaml.lines() { + println!(" {}", line); } } - Err(e) => println!(" Error loading configuration: {}", e), } } diff --git a/crates/goose-server/src/routes/config_management.rs b/crates/goose-server/src/routes/config_management.rs index 2761fdb7a1a4..f40e86b2f299 100644 --- a/crates/goose-server/src/routes/config_management.rs +++ b/crates/goose-server/src/routes/config_management.rs @@ -272,7 +272,7 @@ pub async fn read_all_config() -> Result, StatusCode> { let config = Config::global(); let values = config - .load_values() + .all_values() .map_err(|_| StatusCode::UNPROCESSABLE_ENTITY)?; Ok(Json(ConfigResponse { config: values })) @@ -509,7 +509,7 @@ pub async fn init_config() -> Result, StatusCode> { // Use the shared function to load init-config.yaml match goose::config::base::load_init_config_from_workspace() { - Ok(init_values) => match config.save_values(init_values) { + Ok(init_values) => match config.initialize_if_empty(init_values) { Ok(_) => Ok(Json("Config initialized successfully".to_string())), Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR), }, @@ -584,7 +584,7 @@ pub async fn recover_config() -> Result, StatusCode> { let config = Config::global(); // Force a reload which will trigger recovery if needed - match config.load_values() { + match config.all_values() { Ok(values) => { let recovered_keys: Vec = values.keys().cloned().collect(); if recovered_keys.is_empty() { diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index f015819b7622..b3617556b037 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -108,6 +108,7 @@ schemars = { version = "1.0.4", default-features = false, features = ["derive"] insta = "1.43.2" paste = "1.0.0" shellexpand = "3.1.1" +indexmap = "2.12.0" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/crates/goose/src/agents/extension.rs b/crates/goose/src/agents/extension.rs index 284a98cf5b7f..9f1daa6cd279 100644 --- a/crates/goose/src/agents/extension.rs +++ b/crates/goose/src/agents/extension.rs @@ -215,6 +215,8 @@ pub enum ExtensionConfig { Sse { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, uri: String, #[serde(default)] @@ -234,6 +236,8 @@ pub enum ExtensionConfig { Stdio { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, cmd: String, args: Vec, @@ -252,6 +256,8 @@ pub enum ExtensionConfig { Builtin { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, display_name: Option, // needed for the UI timeout: Option, @@ -265,6 +271,8 @@ pub enum ExtensionConfig { Platform { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, #[serde(default)] bundled: Option, @@ -276,6 +284,8 @@ pub enum ExtensionConfig { StreamableHttp { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, uri: String, #[serde(default)] @@ -297,6 +307,8 @@ pub enum ExtensionConfig { Frontend { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, /// The tools provided by the frontend tools: Vec, @@ -312,6 +324,8 @@ pub enum ExtensionConfig { InlinePython { /// The name used to identify this extension name: String, + #[serde(default)] + #[schema(required)] description: String, /// The Python code to execute code: String, diff --git a/crates/goose/src/config/base.rs b/crates/goose/src/config/base.rs index 550695120b92..0ad26428d39b 100644 --- a/crates/goose/src/config/base.rs +++ b/crates/goose/src/config/base.rs @@ -5,6 +5,7 @@ use keyring::Entry; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; use serde_json::Value; +use serde_yaml::Mapping; use std::collections::HashMap; use std::env; use std::fs::OpenOptions; @@ -152,6 +153,10 @@ macro_rules! declare_param { }; } +fn parse_yaml_content(content: &str) -> Result { + serde_yaml::from_str(content).map_err(|e| e.into()) +} + impl Config { /// Get the global configuration instance. /// @@ -204,8 +209,7 @@ impl Config { self.config_path.to_string_lossy().to_string() } - // Load current values from the config file - pub fn load_values(&self) -> Result, ConfigError> { + fn load(&self) -> Result { if self.config_path.exists() { self.load_values_with_recovery() } else { @@ -221,19 +225,27 @@ impl Config { tracing::info!("No backup found, creating default configuration"); // Try to load from init-config.yaml if it exists, otherwise use empty config - let default_config = self - .load_init_config_if_exists() - .unwrap_or_else(|_| HashMap::new()); + let default_config = self.load_init_config_if_exists().unwrap_or_default(); self.create_and_save_default_config(default_config) } } + pub fn all_values(&self) -> Result, ConfigError> { + self.load().map(|m| { + HashMap::from_iter(m.into_iter().filter_map(|(k, v)| { + k.as_str() + .map(|k| k.to_string()) + .zip(serde_json::to_value(v).ok()) + })) + }) + } + // Helper method to create and save default config with consistent logging fn create_and_save_default_config( &self, - default_config: HashMap, - ) -> Result, ConfigError> { + default_config: Mapping, + ) -> Result { // Try to write the default config to disk match self.save_values(default_config.clone()) { Ok(_) => { @@ -255,12 +267,10 @@ impl Config { } } - // Load values with automatic recovery from corruption - fn load_values_with_recovery(&self) -> Result, ConfigError> { + fn load_values_with_recovery(&self) -> Result { let file_content = std::fs::read_to_string(&self.config_path)?; - // First attempt: try to parse the current config - match self.parse_yaml_content(&file_content) { + match parse_yaml_content(&file_content) { Ok(values) => Ok(values), Err(parse_error) => { tracing::warn!( @@ -277,40 +287,21 @@ impl Config { // Last resort: create a fresh default config file tracing::error!("Could not recover config file, creating fresh default configuration. Original error: {}", parse_error); - // Try to load from init-config.yaml if it exists, otherwise use empty config - let default_config = self - .load_init_config_if_exists() - .unwrap_or_else(|_| HashMap::new()); + let default_config = self.load_init_config_if_exists().unwrap_or_default(); self.create_and_save_default_config(default_config) } } } - // Parse YAML content into HashMap - fn parse_yaml_content(&self, content: &str) -> Result, ConfigError> { - if content.trim().is_empty() { - return Ok(HashMap::new()); - } - - let yaml_value: serde_yaml::Value = serde_yaml::from_str(content)?; - let json_value: Value = serde_json::to_value(yaml_value)?; - - match json_value { - Value::Object(map) => Ok(map.into_iter().collect()), - _ => Ok(HashMap::new()), - } - } - - // Try to restore from backup file - fn try_restore_from_backup(&self) -> Result, ConfigError> { + fn try_restore_from_backup(&self) -> Result { let backup_paths = self.get_backup_paths(); for backup_path in backup_paths { if backup_path.exists() { match std::fs::read_to_string(&backup_path) { Ok(backup_content) => { - match self.parse_yaml_content(&backup_content) { + match parse_yaml_content(&backup_content) { Ok(values) => { // Successfully parsed backup, restore it as the main config if let Err(e) = self.save_values(values.clone()) { @@ -370,13 +361,11 @@ impl Config { paths } - // Try to load init-config.yaml from workspace root if it exists - fn load_init_config_if_exists(&self) -> Result, ConfigError> { + fn load_init_config_if_exists(&self) -> Result { load_init_config_from_workspace() } - // Save current values to the config file - pub fn save_values(&self, values: HashMap) -> Result<(), ConfigError> { + fn save_values(&self, values: Mapping) -> Result<(), ConfigError> { // Create backup before writing new config self.create_backup_if_needed()?; @@ -416,6 +405,15 @@ impl Config { Ok(()) } + pub fn initialize_if_empty(&self, values: Mapping) -> Result<(), ConfigError> { + let _guard = self.guard.lock().unwrap(); + if !self.exists() { + self.save_values(values) + } else { + Ok(()) + } + } + // Create backup of current config file if it exists and is valid fn create_backup_if_needed(&self) -> Result<(), ConfigError> { if !self.config_path.exists() { @@ -424,7 +422,7 @@ impl Config { // Check if current config is valid before backing it up let current_content = std::fs::read_to_string(&self.config_path)?; - if self.parse_yaml_content(¤t_content).is_err() { + if parse_yaml_content(¤t_content).is_err() { // Don't back up corrupted files return Ok(()); } @@ -483,8 +481,7 @@ impl Config { Ok(()) } - // Load current secrets from the keyring - pub fn load_secrets(&self) -> Result, ConfigError> { + pub fn all_secrets(&self) -> Result, ConfigError> { match &self.secrets { SecretStorage::Keyring { service } => { let entry = Entry::new(service, KEYRING_USERNAME)?; @@ -585,21 +582,17 @@ impl Config { /// - The value cannot be deserialized into the requested type /// - There is an error reading the config file pub fn get_param Deserialize<'de>>(&self, key: &str) -> Result { - // First check environment variables (convert to uppercase) let env_key = key.to_uppercase(); if let Ok(val) = env::var(&env_key) { let value = Self::parse_env_value(&val)?; return Ok(serde_json::from_value(value)?); } - // Load current values from file - let values = self.load_values()?; - - // Then check our stored values + let values = self.load()?; values .get(key) .ok_or_else(|| ConfigError::NotFound(key.to_string())) - .and_then(|v| Ok(serde_json::from_value(v.clone())?)) + .and_then(|v| Ok(serde_yaml::from_value(v.clone())?)) } /// Set a configuration value in the config file (non-secret). @@ -617,8 +610,8 @@ impl Config { /// - There is an error serializing the value pub fn set_param(&self, key: &str, value: V) -> Result<(), ConfigError> { let _guard = self.guard.lock().unwrap(); - let mut values = self.load_values()?; - values.insert(key.to_string(), serde_json::to_value(&value)?); + let mut values = self.load()?; + values.insert(serde_yaml::to_value(key)?, serde_yaml::to_value(value)?); self.save_values(values) } @@ -639,8 +632,8 @@ impl Config { // Lock before reading to prevent race condition. let _guard = self.guard.lock().unwrap(); - let mut values = self.load_values()?; - values.remove(key); + let mut values = self.load()?; + values.shift_remove(key); self.save_values(values) } @@ -670,7 +663,7 @@ impl Config { } // Then check keyring - let values = self.load_secrets()?; + let values = self.all_secrets()?; values .get(key) .ok_or_else(|| ConfigError::NotFound(key.to_string())) @@ -698,7 +691,7 @@ impl Config { // Lock before reading to prevent race condition. let _guard = self.guard.lock().unwrap(); - let mut values = self.load_secrets()?; + let mut values = self.all_secrets()?; values.insert(key.to_string(), serde_json::to_value(value)?); match &self.secrets { @@ -729,7 +722,7 @@ impl Config { // Lock before reading to prevent race condition. let _guard = self.guard.lock().unwrap(); - let mut values = self.load_secrets()?; + let mut values = self.all_secrets()?; values.remove(key); match &self.secrets { @@ -754,7 +747,7 @@ impl Config { /// Load init-config.yaml from workspace root if it exists. /// This function is shared between the config recovery and the init_config endpoint. -pub fn load_init_config_from_workspace() -> Result, ConfigError> { +pub fn load_init_config_from_workspace() -> Result { let workspace_root = match std::env::current_exe() { Ok(mut exe_path) => { while let Some(parent) = exe_path.parent() { @@ -787,23 +780,7 @@ pub fn load_init_config_from_workspace() -> Result, Confi } let init_content = std::fs::read_to_string(&init_config_path)?; - let init_values: HashMap = - match serde_yaml::from_str::(&init_content) { - Ok(yaml_value) => { - let json_value: Value = serde_json::to_value(yaml_value)?; - match json_value { - Value::Object(map) => map.into_iter().collect(), - _ => HashMap::new(), - } - } - Err(e) => { - tracing::warn!("Failed to parse init-config.yaml: {}", e); - return Err(ConfigError::DeserializeError(e.to_string())); - } - }; - - tracing::info!("Loaded init-config.yaml with {} keys", init_values.len()); - Ok(init_values) + parse_yaml_content(&init_content) } #[cfg(test)] @@ -902,7 +879,7 @@ mod tests { config.set_param("another_key", 42)?; config.set_param("third_key", true)?; - let _values = config.load_values()?; + let _values = config.load()?; let result: Result = config.get_param("key"); assert!(matches!(result, Err(ConfigError::NotFound(_)))); @@ -994,11 +971,11 @@ mod tests { let temp_file = NamedTempFile::new().unwrap(); let config = Arc::new(Config::new(temp_file.path(), TEST_KEYRING_SERVICE)?); let barrier = Arc::new(Barrier::new(3)); // For 3 concurrent threads - let values = Arc::new(Mutex::new(HashMap::new())); + let values = Arc::new(Mutex::new(Mapping::new())); let mut handles = vec![]; // Initialize with empty values - config.save_values(HashMap::new())?; + config.save_values(Default::default())?; // Spawn 3 threads that will try to write simultaneously for i in 0..3 { @@ -1011,7 +988,10 @@ mod tests { // Get the lock and update values let mut values = values.lock().unwrap(); - values.insert(format!("key{}", i), Value::String(format!("value{}", i))); + values.insert( + serde_yaml::to_value(format!("key{}", i)).unwrap(), + serde_yaml::to_value(format!("value{}", i)).unwrap(), + ); // Write all values config.save_values(values.clone())?; @@ -1026,7 +1006,7 @@ mod tests { } // Verify all values were written correctly - let final_values = config.load_values()?; + let final_values = config.all_values()?; // Print the final values for debugging println!("Final values: {:?}", final_values); @@ -1088,7 +1068,7 @@ mod tests { std::fs::write(temp_file.path(), "invalid: yaml: content: [unclosed")?; // Try to load values - should recover from backup - let recovered_values = config.load_values()?; + let recovered_values = config.all_values()?; println!("Recovered values: {:?}", recovered_values); // Should have recovered the data @@ -1109,7 +1089,7 @@ mod tests { std::fs::write(temp_file.path(), "invalid: yaml: content: [unclosed")?; // Try to load values - should create a fresh default config - let recovered_values = config.load_values()?; + let recovered_values = config.all_values()?; // Should return empty config assert_eq!(recovered_values.len(), 0); @@ -1122,7 +1102,7 @@ mod tests { assert!(parsed.is_mapping()); // Should be able to load it again without issues - let reloaded_values = config.load_values()?; + let reloaded_values = config.all_values()?; assert_eq!(reloaded_values.len(), 0); Ok(()) @@ -1140,7 +1120,7 @@ mod tests { let config = Config::new(config_path, TEST_KEYRING_SERVICE)?; // Try to load values - should create a fresh default config file - let values = config.load_values()?; + let values = config.all_values()?; // Should return empty config assert_eq!(values.len(), 0); @@ -1154,7 +1134,7 @@ mod tests { assert!(parsed.is_mapping()); // Should be able to load it again without issues - let reloaded_values = config.load_values()?; + let reloaded_values = config.all_values()?; assert_eq!(reloaded_values.len(), 0); Ok(()) @@ -1183,7 +1163,7 @@ mod tests { assert!(!config_path.exists()); // Try to load values - should recover from backup - let recovered_values = config.load_values()?; + let recovered_values = config.all_values()?; // Should have recovered the data from backup assert!( diff --git a/crates/goose/src/config/extensions.rs b/crates/goose/src/config/extensions.rs index fac3d6f23c67..4ad4e84de300 100644 --- a/crates/goose/src/config/extensions.rs +++ b/crates/goose/src/config/extensions.rs @@ -1,9 +1,9 @@ use super::base::Config; use crate::agents::extension::PLATFORM_EXTENSIONS; use crate::agents::ExtensionConfig; +use indexmap::IndexMap; use serde::{Deserialize, Serialize}; -use serde_json::Value; -use std::collections::HashMap; +use serde_yaml::Mapping; use tracing::warn; use utoipa::ToSchema; @@ -27,56 +27,32 @@ pub fn name_to_key(name: &str) -> String { .to_lowercase() } -fn get_extensions_map() -> HashMap { - let raw: Value = Config::global() - .get_param::(EXTENSIONS_CONFIG_KEY) +fn get_extensions_map() -> IndexMap { + let raw: Mapping = Config::global() + .get_param(EXTENSIONS_CONFIG_KEY) .unwrap_or_else(|err| { warn!( "Failed to load {}: {err}. Falling back to empty object.", EXTENSIONS_CONFIG_KEY ); - Value::Object(serde_json::Map::new()) + Default::default() }); - let mut extensions_map: HashMap = match raw { - Value::Object(obj) => { - let mut m = HashMap::with_capacity(obj.len()); - for (k, mut v) in obj { - if let Value::Object(ref mut inner) = v { - match inner.get("description") { - Some(Value::Null) | None => { - inner.insert("description".to_string(), Value::String(String::new())); - } - _ => {} - } - } - match serde_json::from_value::(v.clone()) { - Ok(entry) => { - m.insert(k, entry); - } - Err(err) => { - let bad_json = serde_json::to_string(&v).unwrap_or_else(|e| { - format!("") - }); - warn!( - extension = %k, - error = %err, - bad_json = %bad_json, - "Skipping malformed extension" - ); - } - } + let mut extensions_map = IndexMap::with_capacity(raw.len()); + for (k, v) in raw { + match (k, serde_yaml::from_value::(v)) { + (serde_yaml::Value::String(s), Ok(entry)) => { + extensions_map.insert(s, entry); + } + (k, v) => { + warn!( + key = ?k, + value = ?v, + "Skipping malformed extension config entry" + ); } - m - } - other => { - warn!( - "Expected object for {}, got {}. Using empty map.", - EXTENSIONS_CONFIG_KEY, other - ); - HashMap::new() } - }; + } if !extensions_map.is_empty() { for (name, def) in PLATFORM_EXTENSIONS.iter() { @@ -99,7 +75,7 @@ fn get_extensions_map() -> HashMap { extensions_map } -fn save_extensions_map(extensions: HashMap) { +fn save_extensions_map(extensions: IndexMap) { let config = Config::global(); if let Err(e) = config.set_param(EXTENSIONS_CONFIG_KEY, &extensions) { // TODO(jack) why is this just a debug statement? @@ -124,7 +100,7 @@ pub fn set_extension(entry: ExtensionEntry) { pub fn remove_extension(key: &str) { let mut extensions = get_extensions_map(); - extensions.remove(key); + extensions.shift_remove(key); save_extensions_map(extensions); } diff --git a/crates/goose/src/providers/bedrock.rs b/crates/goose/src/providers/bedrock.rs index e69934bd53cc..49277c324a25 100644 --- a/crates/goose/src/providers/bedrock.rs +++ b/crates/goose/src/providers/bedrock.rs @@ -59,8 +59,8 @@ impl BedrockProvider { } }; - set_aws_env_vars(config.load_values()); - set_aws_env_vars(config.load_secrets()); + set_aws_env_vars(config.all_values()); + set_aws_env_vars(config.all_secrets()); // Use load_defaults() which supports AWS SSO, profiles, and environment variables let mut loader = aws_config::defaults(aws_config::BehaviorVersion::latest()); diff --git a/crates/goose/src/providers/sagemaker_tgi.rs b/crates/goose/src/providers/sagemaker_tgi.rs index e26c08eaf7b8..a5210b5b91fa 100644 --- a/crates/goose/src/providers/sagemaker_tgi.rs +++ b/crates/goose/src/providers/sagemaker_tgi.rs @@ -53,8 +53,8 @@ impl SageMakerTgiProvider { } }; - set_aws_env_vars(config.load_values()); - set_aws_env_vars(config.load_secrets()); + set_aws_env_vars(config.all_values()); + set_aws_env_vars(config.all_secrets()); let aws_config = aws_config::load_from_env().await; From 0db91a2879b992077a156aa64a9221340fa99704 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Thu, 30 Oct 2025 17:59:11 -0400 Subject: [PATCH 044/121] don't start the default provider (#5351) Signed-off-by: fbalicchia --- crates/goose/src/execution/manager.rs | 269 ++++++++++++++++++++++---- crates/goose/tests/execution_tests.rs | 256 ------------------------ 2 files changed, 229 insertions(+), 296 deletions(-) delete mode 100644 crates/goose/tests/execution_tests.rs diff --git a/crates/goose/src/execution/manager.rs b/crates/goose/src/execution/manager.rs index 3d86ff092b29..615f7943213f 100644 --- a/crates/goose/src/execution/manager.rs +++ b/crates/goose/src/execution/manager.rs @@ -1,8 +1,6 @@ use crate::agents::extension::PlatformExtensionContext; use crate::agents::Agent; use crate::config::paths::Paths; -use crate::model::ModelConfig; -use crate::providers::create; use crate::scheduler_factory::SchedulerFactory; use crate::scheduler_trait::SchedulerTrait; use anyhow::Result; @@ -10,7 +8,7 @@ use lru::LruCache; use std::num::NonZeroUsize; use std::sync::Arc; use tokio::sync::{OnceCell, RwLock}; -use tracing::{debug, info, warn}; +use tracing::{debug, info}; const DEFAULT_MAX_SESSION: usize = 100; @@ -23,7 +21,7 @@ pub struct AgentManager { } impl AgentManager { - /// Reset the global singleton - ONLY for testing + #[cfg(test)] pub fn reset_for_test() { unsafe { // Cast away the const to get mutable access @@ -34,7 +32,6 @@ impl AgentManager { } } - // Private constructor - prevents direct instantiation in production async fn new(max_sessions: Option) -> Result { let schedule_file_path = Paths::data_dir().join("schedule.json"); @@ -49,8 +46,6 @@ impl AgentManager { default_provider: Arc::new(RwLock::new(None)), }; - let _ = manager.configure_default_provider().await; - Ok(manager) } @@ -73,39 +68,6 @@ impl AgentManager { *self.default_provider.write().await = Some(provider); } - pub async fn configure_default_provider(&self) -> Result<()> { - let provider_name = std::env::var("GOOSE_DEFAULT_PROVIDER") - .or_else(|_| std::env::var("GOOSE_PROVIDER__TYPE")) - .ok(); - - let model_name = std::env::var("GOOSE_DEFAULT_MODEL") - .or_else(|_| std::env::var("GOOSE_PROVIDER__MODEL")) - .ok(); - - if provider_name.is_none() || model_name.is_none() { - return Ok(()); - } - - if let (Some(provider_name), Some(model_name)) = (provider_name, model_name) { - match ModelConfig::new(&model_name) { - Ok(model_config) => match create(&provider_name, model_config).await { - Ok(provider) => { - self.set_default_provider(provider).await; - info!( - "Configured default provider: {} with model: {}", - provider_name, model_name - ); - } - Err(e) => { - warn!("Failed to create default provider {}: {}", provider_name, e) - } - }, - Err(e) => warn!("Failed to create model config for {}: {}", model_name, e), - } - } - Ok(()) - } - pub async fn get_or_create_agent(&self, session_id: String) -> Result> { { let mut sessions = self.sessions.write().await; @@ -154,3 +116,230 @@ impl AgentManager { self.sessions.read().await.len() } } + +#[cfg(test)] +mod tests { + use serial_test::serial; + use std::sync::Arc; + + use crate::execution::{manager::AgentManager, SessionExecutionMode}; + + #[test] + fn test_execution_mode_constructors() { + assert_eq!( + SessionExecutionMode::chat(), + SessionExecutionMode::Interactive + ); + assert_eq!( + SessionExecutionMode::scheduled(), + SessionExecutionMode::Background + ); + + let parent = "parent-123".to_string(); + assert_eq!( + SessionExecutionMode::task(parent.clone()), + SessionExecutionMode::SubTask { + parent_session: parent + } + ); + } + + #[tokio::test] + #[serial] + async fn test_session_isolation() { + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + + let session1 = uuid::Uuid::new_v4().to_string(); + let session2 = uuid::Uuid::new_v4().to_string(); + + let agent1 = manager.get_or_create_agent(session1.clone()).await.unwrap(); + + let agent2 = manager.get_or_create_agent(session2.clone()).await.unwrap(); + + // Different sessions should have different agents + assert!(!Arc::ptr_eq(&agent1, &agent2)); + + // Getting the same session should return the same agent + let agent1_again = manager.get_or_create_agent(session1).await.unwrap(); + + assert!(Arc::ptr_eq(&agent1, &agent1_again)); + + AgentManager::reset_for_test(); + } + + #[tokio::test] + #[serial] + async fn test_session_limit() { + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + + let sessions: Vec<_> = (0..100).map(|i| format!("session-{}", i)).collect(); + + for session in &sessions { + manager.get_or_create_agent(session.clone()).await.unwrap(); + } + + // Create a new session after cleanup + let new_session = "new-session".to_string(); + let _new_agent = manager.get_or_create_agent(new_session).await.unwrap(); + + assert_eq!(manager.session_count().await, 100); + } + + #[tokio::test] + #[serial] + async fn test_remove_session() { + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + let session = String::from("remove-test"); + + manager.get_or_create_agent(session.clone()).await.unwrap(); + assert!(manager.has_session(&session).await); + + manager.remove_session(&session).await.unwrap(); + assert!(!manager.has_session(&session).await); + + assert!(manager.remove_session(&session).await.is_err()); + } + + #[tokio::test] + #[serial] + async fn test_concurrent_access() { + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + let session = String::from("concurrent-test"); + + let mut handles = vec![]; + for _ in 0..10 { + let mgr = Arc::clone(&manager); + let sess = session.clone(); + handles.push(tokio::spawn(async move { + mgr.get_or_create_agent(sess).await.unwrap() + })); + } + + let agents: Vec<_> = futures::future::join_all(handles) + .await + .into_iter() + .map(|r| r.unwrap()) + .collect(); + + for agent in &agents[1..] { + assert!(Arc::ptr_eq(&agents[0], agent)); + } + + assert_eq!(manager.session_count().await, 1); + } + + #[tokio::test] + #[serial] + async fn test_concurrent_session_creation_race_condition() { + // Test that concurrent attempts to create the same new session ID + // result in only one agent being created (tests double-check pattern) + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + let session_id = String::from("race-condition-test"); + + // Spawn multiple tasks trying to create the same NEW session simultaneously + let mut handles = vec![]; + for _ in 0..20 { + let sess = session_id.clone(); + let mgr_clone = Arc::clone(&manager); + handles.push(tokio::spawn(async move { + mgr_clone.get_or_create_agent(sess).await.unwrap() + })); + } + + // Collect all agents + let agents: Vec<_> = futures::future::join_all(handles) + .await + .into_iter() + .map(|r| r.unwrap()) + .collect(); + + for agent in &agents[1..] { + assert!( + Arc::ptr_eq(&agents[0], agent), + "All concurrent requests should get the same agent" + ); + } + assert_eq!(manager.session_count().await, 1); + } + + #[tokio::test] + #[serial] + async fn test_set_default_provider() { + use crate::providers::testprovider::TestProvider; + use std::sync::Arc; + + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + + // Create a test provider for replaying (doesn't need inner provider) + let temp_file = format!( + "{}/test_provider_{}.json", + std::env::temp_dir().display(), + std::process::id() + ); + + // Create an empty test provider (will fail on actual use but that's ok for this test) + let test_provider = TestProvider::new_replaying(&temp_file) + .unwrap_or_else(|_| TestProvider::new_replaying("/tmp/dummy.json").unwrap()); + + manager.set_default_provider(Arc::new(test_provider)).await; + + let session = String::from("provider-test"); + let _agent = manager.get_or_create_agent(session.clone()).await.unwrap(); + + assert!(manager.has_session(&session).await); + } + + #[tokio::test] + #[serial] + async fn test_eviction_updates_last_used() { + AgentManager::reset_for_test(); + // Test that accessing a session updates its last_used timestamp + // and affects eviction order + let manager = AgentManager::instance().await.unwrap(); + + let sessions: Vec<_> = (0..100).map(|i| format!("session-{}", i)).collect(); + + for session in &sessions { + manager.get_or_create_agent(session.clone()).await.unwrap(); + // Small delay to ensure different timestamps + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + } + + // Access the first session again to update its last_used + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + manager + .get_or_create_agent(sessions[0].clone()) + .await + .unwrap(); + + // Now create a 101st session - should evict session2 (least recently used) + let session101 = String::from("session-101"); + manager + .get_or_create_agent(session101.clone()) + .await + .unwrap(); + + assert!(manager.has_session(&sessions[0]).await); + assert!(!manager.has_session(&sessions[1]).await); + assert!(manager.has_session(&session101).await); + } + + #[tokio::test] + #[serial] + async fn test_remove_nonexistent_session_error() { + // Test that removing a non-existent session returns an error + AgentManager::reset_for_test(); + let manager = AgentManager::instance().await.unwrap(); + let session = String::from("never-created"); + + let result = manager.remove_session(&session).await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("not found")); + } +} diff --git a/crates/goose/tests/execution_tests.rs b/crates/goose/tests/execution_tests.rs deleted file mode 100644 index 07e8932563b7..000000000000 --- a/crates/goose/tests/execution_tests.rs +++ /dev/null @@ -1,256 +0,0 @@ -mod execution_tests { - use goose::execution::manager::AgentManager; - use goose::execution::SessionExecutionMode; - use serial_test::serial; - use std::sync::Arc; - - #[test] - fn test_execution_mode_constructors() { - assert_eq!( - SessionExecutionMode::chat(), - SessionExecutionMode::Interactive - ); - assert_eq!( - SessionExecutionMode::scheduled(), - SessionExecutionMode::Background - ); - - let parent = "parent-123".to_string(); - assert_eq!( - SessionExecutionMode::task(parent.clone()), - SessionExecutionMode::SubTask { - parent_session: parent - } - ); - } - - #[tokio::test] - #[serial] - async fn test_session_isolation() { - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - - let session1 = uuid::Uuid::new_v4().to_string(); - let session2 = uuid::Uuid::new_v4().to_string(); - - let agent1 = manager.get_or_create_agent(session1.clone()).await.unwrap(); - - let agent2 = manager.get_or_create_agent(session2.clone()).await.unwrap(); - - // Different sessions should have different agents - assert!(!Arc::ptr_eq(&agent1, &agent2)); - - // Getting the same session should return the same agent - let agent1_again = manager.get_or_create_agent(session1).await.unwrap(); - - assert!(Arc::ptr_eq(&agent1, &agent1_again)); - - AgentManager::reset_for_test(); - } - - #[tokio::test] - #[serial] - async fn test_session_limit() { - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - - let sessions: Vec<_> = (0..100).map(|i| format!("session-{}", i)).collect(); - - for session in &sessions { - manager.get_or_create_agent(session.clone()).await.unwrap(); - } - - // Create a new session after cleanup - let new_session = "new-session".to_string(); - let _new_agent = manager.get_or_create_agent(new_session).await.unwrap(); - - assert_eq!(manager.session_count().await, 100); - } - - #[tokio::test] - #[serial] - async fn test_remove_session() { - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - let session = String::from("remove-test"); - - manager.get_or_create_agent(session.clone()).await.unwrap(); - assert!(manager.has_session(&session).await); - - manager.remove_session(&session).await.unwrap(); - assert!(!manager.has_session(&session).await); - - assert!(manager.remove_session(&session).await.is_err()); - } - - #[tokio::test] - #[serial] - async fn test_concurrent_access() { - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - let session = String::from("concurrent-test"); - - let mut handles = vec![]; - for _ in 0..10 { - let mgr = Arc::clone(&manager); - let sess = session.clone(); - handles.push(tokio::spawn(async move { - mgr.get_or_create_agent(sess).await.unwrap() - })); - } - - let agents: Vec<_> = futures::future::join_all(handles) - .await - .into_iter() - .map(|r| r.unwrap()) - .collect(); - - for agent in &agents[1..] { - assert!(Arc::ptr_eq(&agents[0], agent)); - } - - assert_eq!(manager.session_count().await, 1); - } - - #[tokio::test] - #[serial] - async fn test_concurrent_session_creation_race_condition() { - // Test that concurrent attempts to create the same new session ID - // result in only one agent being created (tests double-check pattern) - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - let session_id = String::from("race-condition-test"); - - // Spawn multiple tasks trying to create the same NEW session simultaneously - let mut handles = vec![]; - for _ in 0..20 { - let sess = session_id.clone(); - let mgr_clone = Arc::clone(&manager); - handles.push(tokio::spawn(async move { - mgr_clone.get_or_create_agent(sess).await.unwrap() - })); - } - - // Collect all agents - let agents: Vec<_> = futures::future::join_all(handles) - .await - .into_iter() - .map(|r| r.unwrap()) - .collect(); - - for agent in &agents[1..] { - assert!( - Arc::ptr_eq(&agents[0], agent), - "All concurrent requests should get the same agent" - ); - } - assert_eq!(manager.session_count().await, 1); - } - - #[tokio::test] - #[serial] - async fn test_configure_default_provider() { - use std::env; - - AgentManager::reset_for_test(); - - let original_provider = env::var("GOOSE_DEFAULT_PROVIDER").ok(); - let original_model = env::var("GOOSE_DEFAULT_MODEL").ok(); - - env::set_var("GOOSE_DEFAULT_PROVIDER", "openai"); - env::set_var("GOOSE_DEFAULT_MODEL", "gpt-4o-mini"); - - let manager = AgentManager::instance().await.unwrap(); - let result = manager.configure_default_provider().await; - - assert!(result.is_ok()); - - // Restore original env vars - if let Some(val) = original_provider { - env::set_var("GOOSE_DEFAULT_PROVIDER", val); - } else { - env::remove_var("GOOSE_DEFAULT_PROVIDER"); - } - if let Some(val) = original_model { - env::set_var("GOOSE_DEFAULT_MODEL", val); - } else { - env::remove_var("GOOSE_DEFAULT_MODEL"); - } - } - - #[tokio::test] - #[serial] - async fn test_set_default_provider() { - use goose::providers::testprovider::TestProvider; - use std::sync::Arc; - - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - - // Create a test provider for replaying (doesn't need inner provider) - let temp_file = format!( - "{}/test_provider_{}.json", - std::env::temp_dir().display(), - std::process::id() - ); - - // Create an empty test provider (will fail on actual use but that's ok for this test) - let test_provider = TestProvider::new_replaying(&temp_file) - .unwrap_or_else(|_| TestProvider::new_replaying("/tmp/dummy.json").unwrap()); - - manager.set_default_provider(Arc::new(test_provider)).await; - - let session = String::from("provider-test"); - let _agent = manager.get_or_create_agent(session.clone()).await.unwrap(); - - assert!(manager.has_session(&session).await); - } - - #[tokio::test] - #[serial] - async fn test_eviction_updates_last_used() { - AgentManager::reset_for_test(); - // Test that accessing a session updates its last_used timestamp - // and affects eviction order - let manager = AgentManager::instance().await.unwrap(); - - let sessions: Vec<_> = (0..100).map(|i| format!("session-{}", i)).collect(); - - for session in &sessions { - manager.get_or_create_agent(session.clone()).await.unwrap(); - // Small delay to ensure different timestamps - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - } - - // Access the first session again to update its last_used - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - manager - .get_or_create_agent(sessions[0].clone()) - .await - .unwrap(); - - // Now create a 101st session - should evict session2 (least recently used) - let session101 = String::from("session-101"); - manager - .get_or_create_agent(session101.clone()) - .await - .unwrap(); - - assert!(manager.has_session(&sessions[0]).await); - assert!(!manager.has_session(&sessions[1]).await); - assert!(manager.has_session(&session101).await); - } - - #[tokio::test] - #[serial] - async fn test_remove_nonexistent_session_error() { - // Test that removing a non-existent session returns an error - AgentManager::reset_for_test(); - let manager = AgentManager::instance().await.unwrap(); - let session = String::from("never-created"); - - let result = manager.remove_session(&session).await; - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("not found")); - } -} From bb190b328a99ca9e888cacd5d8f7750820069dc0 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Thu, 30 Oct 2025 18:12:46 -0400 Subject: [PATCH 045/121] Goose recover (#5450) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- ui/desktop/src/components/hub.tsx | 25 +------ ui/desktop/src/components/pair.tsx | 4 +- .../sessions/SessionHistoryView.tsx | 10 +-- .../components/sessions/SessionsInsights.tsx | 6 +- .../settings/extensions/agent-api.ts | 6 ++ ui/desktop/src/hooks/useNavigation.ts | 2 + ui/desktop/src/sessions.ts | 53 +++++++++++---- ui/desktop/src/toasts.tsx | 67 ++++++++++--------- 8 files changed, 95 insertions(+), 78 deletions(-) diff --git a/ui/desktop/src/components/hub.tsx b/ui/desktop/src/components/hub.tsx index 3cae47ba04dc..db4266656b3f 100644 --- a/ui/desktop/src/components/hub.tsx +++ b/ui/desktop/src/components/hub.tsx @@ -19,7 +19,7 @@ import ChatInput from './ChatInput'; import { ChatState } from '../types/chatState'; import 'react-toastify/dist/ReactToastify.css'; import { View, ViewOptions } from '../utils/navigationUtils'; -import { startAgent } from '../api'; +import { startNewSession } from '../sessions'; export default function Hub({ setView, @@ -37,28 +37,7 @@ export default function Hub({ const combinedTextFromInput = customEvent.detail?.value || ''; if (combinedTextFromInput.trim()) { - if (process.env.ALPHA) { - const newAgent = await startAgent({ - body: { - working_dir: window.appConfig.get('GOOSE_WORKING_DIR') as string, - }, - throwOnError: true, - }); - const session = newAgent.data; - setView('pair', { - disableAnimation: true, - initialMessage: combinedTextFromInput, - resumeSessionId: session.id, - }); - } else { - // Navigate to pair page with the message to be submitted - // Pair will handle creating the new chat session - resetChat(); - setView('pair', { - disableAnimation: true, - initialMessage: combinedTextFromInput, - }); - } + await startNewSession(combinedTextFromInput, resetChat, setView); e.preventDefault(); } }; diff --git a/ui/desktop/src/components/pair.tsx b/ui/desktop/src/components/pair.tsx index 44ee659141fe..0aa7353ab55a 100644 --- a/ui/desktop/src/components/pair.tsx +++ b/ui/desktop/src/components/pair.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; -import { View, ViewOptions } from '../utils/navigationUtils'; import BaseChat from './BaseChat'; import { useRecipeManager } from '../hooks/useRecipeManager'; import { useIsMobile } from '../hooks/use-mobile'; @@ -10,6 +9,7 @@ import { cn } from '../utils'; import { ChatType } from '../types/chat'; import { useSearchParams } from 'react-router-dom'; +import type { setViewType } from '../hooks/useNavigation'; export interface PairRouteState { resumeSessionId?: string; @@ -19,7 +19,7 @@ export interface PairRouteState { interface PairProps { chat: ChatType; setChat: (chat: ChatType) => void; - setView: (view: View, viewOptions?: ViewOptions) => void; + setView: setViewType; setIsGoosehintsModalOpen: (isOpen: boolean) => void; setFatalError: (value: ((prevState: string | null) => string | null) | string | null) => void; setAgentWaitingMessage: (msg: string | null) => void; diff --git a/ui/desktop/src/components/sessions/SessionHistoryView.tsx b/ui/desktop/src/components/sessions/SessionHistoryView.tsx index f68eca0410c4..48624ae33022 100644 --- a/ui/desktop/src/components/sessions/SessionHistoryView.tsx +++ b/ui/desktop/src/components/sessions/SessionHistoryView.tsx @@ -31,6 +31,7 @@ import { SearchView } from '../conversation/SearchView'; import BackButton from '../ui/BackButton'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/Tooltip'; import { Message, Session } from '../../api'; +import { useNavigation } from '../../hooks/useNavigation'; // Helper function to determine if a message is a user message (same as useChatEngine) const isUserMessage = (message: Message): boolean => { @@ -150,6 +151,8 @@ const SessionHistoryView: React.FC = ({ const messages = session.conversation || []; + const setView = useNavigation(); + useEffect(() => { const savedSessionConfig = localStorage.getItem('session_sharing_config'); if (savedSessionConfig) { @@ -212,15 +215,14 @@ const SessionHistoryView: React.FC = ({ }); }; - const handleLaunchInNewWindow = () => { + const handleResumeSession = () => { try { - resumeSession(session); + resumeSession(session, setView); } catch (error) { toast.error(`Could not launch session: ${error instanceof Error ? error.message : error}`); } }; - // Define action buttons const actionButtons = showActionButtons ? ( <> @@ -254,7 +256,7 @@ const SessionHistoryView: React.FC = ({ ) : null} - diff --git a/ui/desktop/src/components/sessions/SessionsInsights.tsx b/ui/desktop/src/components/sessions/SessionsInsights.tsx index 713af579558f..15c2ad53578a 100644 --- a/ui/desktop/src/components/sessions/SessionsInsights.tsx +++ b/ui/desktop/src/components/sessions/SessionsInsights.tsx @@ -13,6 +13,7 @@ import { SessionInsights as ApiSessionInsights, } from '../../api'; import { resumeSession } from '../../sessions'; +import { useNavigation } from '../../hooks/useNavigation'; export function SessionInsights() { const [insights, setInsights] = useState(null); @@ -21,6 +22,7 @@ export function SessionInsights() { const [isLoading, setIsLoading] = useState(true); const [isLoadingSessions, setIsLoadingSessions] = useState(true); const navigate = useNavigate(); + const setView = useNavigation(); useEffect(() => { let loadingTimeout: ReturnType; @@ -86,9 +88,7 @@ export function SessionInsights() { const handleSessionClick = async (session: Session) => { try { - resumeSession(session, (sessionId: string) => { - navigate(`/pair?resumeSessionId=${sessionId}`); - }); + resumeSession(session, setView); } catch (error) { console.error('Failed to start session:', error); navigate('/sessions', { diff --git a/ui/desktop/src/components/settings/extensions/agent-api.ts b/ui/desktop/src/components/settings/extensions/agent-api.ts index 01b6463c5a20..d051e289dec0 100644 --- a/ui/desktop/src/components/settings/extensions/agent-api.ts +++ b/ui/desktop/src/components/settings/extensions/agent-api.ts @@ -32,11 +32,17 @@ export async function addToAgent( toastService.dismiss(toastId); } const errMsg = errorMessage(error); + const recoverHints = + `Explain the following error: ${errMsg}. ` + + 'This happened while trying to install an extension. Look out for issues that the ' + + "extension tried to run something faulty, didn't exist or there was trouble with " + + 'the network configuration - VPNs like WARP often cause issues.'; const msg = errMsg.length < 70 ? errMsg : `Failed to add extension`; toastService.error({ title: extensionName, msg: msg, traceback: errMsg, + recoverHints, }); throw error; } diff --git a/ui/desktop/src/hooks/useNavigation.ts b/ui/desktop/src/hooks/useNavigation.ts index 2dfefa3a418b..3a16171b3ea6 100644 --- a/ui/desktop/src/hooks/useNavigation.ts +++ b/ui/desktop/src/hooks/useNavigation.ts @@ -11,3 +11,5 @@ export const useNavigation = () => { const navigate = useNavigate(); return createNavigationHandler(navigate); }; + +export type setViewType = ReturnType; diff --git a/ui/desktop/src/sessions.ts b/ui/desktop/src/sessions.ts index deca3b26da78..ecbcb691b87b 100644 --- a/ui/desktop/src/sessions.ts +++ b/ui/desktop/src/sessions.ts @@ -1,19 +1,17 @@ -import { Session } from './api'; +import { Session, startAgent } from './api'; +import type { setViewType } from './hooks/useNavigation'; -export function resumeSession( - session: Session, - navigateInSameWindow?: (sessionId: string) => void -) { - const workingDir = session.working_dir; - if (!workingDir) { - throw new Error('Cannot resume session: working directory is missing in session'); - } - - // When ALPHA is true and we have a navigation callback, resume in the same window - // Otherwise, open in a new window (old behavior) - if (process.env.ALPHA && navigateInSameWindow) { - navigateInSameWindow(session.id); +export function resumeSession(session: Session, setView: setViewType) { + if (process.env.ALPHA) { + setView('pair', { + disableAnimation: true, + resumeSessionId: session.id, + }); } else { + const workingDir = session.working_dir; + if (!workingDir) { + throw new Error('Cannot resume session: working directory is missing in session'); + } window.electron.createChatWindow( undefined, // query workingDir, @@ -22,3 +20,30 @@ export function resumeSession( ); } } + +export async function startNewSession( + initialText: string | undefined, + resetChat: (() => void) | null, + setView: setViewType +) { + if (!resetChat || process.env.ALPHA) { + const newAgent = await startAgent({ + body: { + working_dir: window.appConfig.get('GOOSE_WORKING_DIR') as string, + }, + throwOnError: true, + }); + const session = newAgent.data; + setView('pair', { + disableAnimation: true, + initialMessage: initialText, + resumeSessionId: session.id, + }); + } else { + resetChat(); + setView('pair', { + disableAnimation: true, + initialMessage: initialText, + }); + } +} diff --git a/ui/desktop/src/toasts.tsx b/ui/desktop/src/toasts.tsx index ba34a652997c..2eb51dcb39c7 100644 --- a/ui/desktop/src/toasts.tsx +++ b/ui/desktop/src/toasts.tsx @@ -1,12 +1,14 @@ import { toast, ToastOptions } from 'react-toastify'; import { Button } from './components/ui/button'; +import { startNewSession } from './sessions'; +import { useNavigation } from './hooks/useNavigation'; export interface ToastServiceOptions { silent?: boolean; shouldThrow?: boolean; } -export default class ToastService { +class ToastService { private silent: boolean = false; private shouldThrow: boolean = false; @@ -30,13 +32,13 @@ export default class ToastService { } } - error({ title, msg, traceback }: { title: string; msg: string; traceback: string }): void { + error(props: ToastErrorProps): void { if (!this.silent) { - toastError({ title, msg, traceback }); + toastError(props); } if (this.shouldThrow) { - throw new Error(msg); + throw new Error(props.msg); } } @@ -68,7 +70,7 @@ export default class ToastService { handleError(title: string, message: string, options: ToastServiceOptions = {}): void { this.configure(options); this.error({ - title: title || 'Error', + title: title, msg: message, traceback: message, }); @@ -88,6 +90,7 @@ const commonToastOptions: ToastOptions = { }; type ToastSuccessProps = { title?: string; msg?: string; toastOptions?: ToastOptions }; + export function toastSuccess({ title, msg, toastOptions = {} }: ToastSuccessProps) { return toast.success(
@@ -99,26 +102,42 @@ export function toastSuccess({ title, msg, toastOptions = {} }: ToastSuccessProp } type ToastErrorProps = { - title?: string; - msg?: string; + title: string; + msg: string; traceback?: string; - toastOptions?: ToastOptions; + recoverHints?: string; }; -export function toastError({ title, msg, traceback, toastOptions }: ToastErrorProps) { - return toast.error( +function ToastErrorContent({ + title, + msg, + traceback, + recoverHints, +}: Omit) { + const setView = useNavigation(); + const showRecovery = recoverHints && setView; + + return (
- {title ? {title} : null} - {msg ?
{msg}
: null} + {title && {title}} + {msg &&
{msg}
}
-
- {traceback ? ( +
+ {showRecovery ? ( + + ) : traceback ? ( ) : null}
-
, - { ...commonToastOptions, autoClose: traceback ? false : 5000, ...toastOptions } +
+ ); +} + +export function toastError({ title, msg, traceback, recoverHints }: ToastErrorProps) { + return toast.error( + , + { ...commonToastOptions, autoClose: traceback ? false : 5000 } ); } @@ -137,19 +156,3 @@ export function toastLoading({ title, msg, toastOptions }: ToastLoadingProps) { { ...commonToastOptions, autoClose: false, ...toastOptions } ); } - -type ToastInfoProps = { - title?: string; - msg?: string; - toastOptions?: ToastOptions; -}; - -export function toastInfo({ title, msg, toastOptions }: ToastInfoProps) { - return toast.info( -
- {title ? {title} : null} - {msg ?
{msg}
: null} -
, - { ...commonToastOptions, ...toastOptions } - ); -} From 1ecece2cbd7c7423f8525e07e8418bc49e2296ee Mon Sep 17 00:00:00 2001 From: Amed Rodriguez Date: Thu, 30 Oct 2025 16:00:25 -0700 Subject: [PATCH 046/121] Change Recipes Test Script (#5457) Signed-off-by: fbalicchia --- .../project_analyzer.yaml | 36 +++++++++ .../project_analyzer_parallel.yaml | 36 +++++++++ .../subrecipes/activity-suggestions.yaml | 23 ------ .../subrecipes/code_patterns.yaml | 62 +++++++++++++++ .../subrecipes/file_stats.yaml | 60 +++++++++++++++ .../subrecipes/weather-data.yaml | 23 ------ .../travel_planner.yaml | 23 ------ .../travel_planner_parallel.yaml | 23 ------ scripts/test_subrecipes.sh | 75 ++++++++++--------- 9 files changed, 235 insertions(+), 126 deletions(-) create mode 100644 scripts/test-subrecipes-examples/project_analyzer.yaml create mode 100644 scripts/test-subrecipes-examples/project_analyzer_parallel.yaml delete mode 100644 scripts/test-subrecipes-examples/subrecipes/activity-suggestions.yaml create mode 100644 scripts/test-subrecipes-examples/subrecipes/code_patterns.yaml create mode 100644 scripts/test-subrecipes-examples/subrecipes/file_stats.yaml delete mode 100644 scripts/test-subrecipes-examples/subrecipes/weather-data.yaml delete mode 100644 scripts/test-subrecipes-examples/travel_planner.yaml delete mode 100644 scripts/test-subrecipes-examples/travel_planner_parallel.yaml diff --git a/scripts/test-subrecipes-examples/project_analyzer.yaml b/scripts/test-subrecipes-examples/project_analyzer.yaml new file mode 100644 index 000000000000..dae395347b0e --- /dev/null +++ b/scripts/test-subrecipes-examples/project_analyzer.yaml @@ -0,0 +1,36 @@ +version: 1.0.0 +title: Project Analyzer +description: Analyze project codebase using parallel subrecipes for file statistics and code patterns +instructions: You are a code analysis assistant that examines project structure and code patterns. +parameters: + - key: target_directory + input_type: string + requirement: optional + default: "." + description: "Directory to analyze" + - key: include_tests + input_type: string + requirement: optional + default: "true" + description: "Whether to include test files in analysis" +prompt: | + Run two subrecipes sequentially: + - use file_stats subrecipe to gather file statistics for {{ target_directory }} + - use code_patterns subrecipe to analyze code patterns in {{ target_directory }} +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true +sub_recipes: + - name: file_stats + path: "./subrecipes/file_stats.yaml" + values: + directory: "{{ target_directory }}" + fast_mode: "true" + - name: code_patterns + path: "./subrecipes/code_patterns.yaml" + values: + directory: "{{ target_directory }}" + include_tests: "{{ include_tests }}" + fast_mode: "true" diff --git a/scripts/test-subrecipes-examples/project_analyzer_parallel.yaml b/scripts/test-subrecipes-examples/project_analyzer_parallel.yaml new file mode 100644 index 000000000000..7ea4c3a27ae5 --- /dev/null +++ b/scripts/test-subrecipes-examples/project_analyzer_parallel.yaml @@ -0,0 +1,36 @@ +version: 1.0.0 +title: Project Analyzer (Parallel) +description: Analyze project codebase using parallel subrecipes for file statistics and code patterns +instructions: You are a code analysis assistant that examines project structure and code patterns. +parameters: + - key: target_directory + input_type: string + requirement: optional + default: "." + description: "Directory to analyze" + - key: include_tests + input_type: string + requirement: optional + default: "true" + description: "Whether to include test files in analysis" +prompt: | + Run two subrecipes in parallel: + - use file_stats subrecipe to gather file statistics for {{ target_directory }} + - use code_patterns subrecipe to analyze code patterns in {{ target_directory }} +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true +sub_recipes: + - name: file_stats + path: "./subrecipes/file_stats.yaml" + values: + directory: "{{ target_directory }}" + fast_mode: "true" + - name: code_patterns + path: "./subrecipes/code_patterns.yaml" + values: + directory: "{{ target_directory }}" + include_tests: "{{ include_tests }}" + fast_mode: "true" diff --git a/scripts/test-subrecipes-examples/subrecipes/activity-suggestions.yaml b/scripts/test-subrecipes-examples/subrecipes/activity-suggestions.yaml deleted file mode 100644 index 9a92b1a1a715..000000000000 --- a/scripts/test-subrecipes-examples/subrecipes/activity-suggestions.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "1.0.0" -title: "Activity Recommender" -description: "Suggest activities based on weather conditions" -instructions: | - You are a travel expert. Recommend appropriate activities and attractions - based on current weather conditions. - -parameters: - - key: weather_conditions - input_type: string - requirement: required - description: "Current weather conditions to base recommendations on" - -extensions: - - type: builtin - name: developer - timeout: 300 - bundled: true - -prompt: | - Based on these weather conditions: {{ weather_conditions }}, - suggest appropriate activities, attractions, and travel tips. - Include both indoor and outdoor options as relevant. diff --git a/scripts/test-subrecipes-examples/subrecipes/code_patterns.yaml b/scripts/test-subrecipes-examples/subrecipes/code_patterns.yaml new file mode 100644 index 000000000000..8c961def34f3 --- /dev/null +++ b/scripts/test-subrecipes-examples/subrecipes/code_patterns.yaml @@ -0,0 +1,62 @@ +version: 1.0.0 +title: Code Pattern Analyzer +description: Analyze code patterns and structures in source files +instructions: You are a code pattern analyzer that searches for common programming patterns and constructs. +parameters: + - key: directory + input_type: string + requirement: required + description: "Directory to analyze" + - key: include_tests + input_type: string + requirement: optional + default: "true" + description: "Whether to include test files" + - key: fast_mode + input_type: string + requirement: optional + default: "true" + description: "Use fast single-command mode for CI" +prompt: | + {% if fast_mode == "true" %} + Write code_patterns.json with a single shell command: + + cat > code_patterns.json << 'JSON' + {"todos":[{"file":"README.md","line":3,"text":"Add more tests"}],"function_count":2,"import_count":0,"test_count":2,"files_analyzed":3} + JSON + + Use a single tool call. Do not scan the filesystem. + {% else %} + Analyze source code files in {{ directory }} and identify patterns: + + 1. Find all TODO/FIXME comments + 2. Count function/method definitions (look for 'fn ', 'def ', 'function ') + 3. Find import/use statements + 4. Identify test functions (names containing 'test') + + Write your findings to a file named code_patterns.json with this structure: + ```json + { + "todos": [ + {"file": "", "line": , "text": ""} + ], + "function_count": , + "import_count": , + "test_count": , + "files_analyzed": + } + ``` + + Use grep and other shell tools to find these patterns efficiently. + Only analyze source code files (.rs, .py, .js, .go, etc.), skip binaries and build artifacts. + {% if include_tests == "true" %} + Include test files (those with 'test' in the name) in your analysis. + {% else %} + Exclude test files from your analysis. + {% endif %} + {% endif %} +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true diff --git a/scripts/test-subrecipes-examples/subrecipes/file_stats.yaml b/scripts/test-subrecipes-examples/subrecipes/file_stats.yaml new file mode 100644 index 000000000000..d5633c71ae16 --- /dev/null +++ b/scripts/test-subrecipes-examples/subrecipes/file_stats.yaml @@ -0,0 +1,60 @@ +version: 1.0.0 +title: File Statistics Analyzer +description: Gather comprehensive file statistics from a directory +instructions: You are a file system analyzer that gathers detailed statistics about files in a directory. +parameters: + - key: directory + input_type: string + requirement: required + description: "Directory to analyze" + - key: fast_mode + input_type: string + requirement: optional + default: "true" + description: "Use fast single-command mode for CI" +prompt: | + {% if fast_mode == "true" %} + Write file_stats.json with a single shell command: + + cat > file_stats.json << 'JSON' + {"total_files":3,"files_by_extension":{".rs":1,".py":1,".md":1},"total_lines":50,"total_size_bytes":1500,"largest_file":{"path":"sample.rs","size_bytes":600},"smallest_file":{"path":"README.md","size_bytes":200}} + JSON + + Use a single tool call. Do not scan the filesystem. + {% else %} + Analyze {{ directory }} and generate file statistics: + + 1. Count total files by extension (.rs, .yaml, .md, .toml, etc.) + 2. Calculate total lines of code across all text files + 3. Determine total file sizes + 4. Find the largest and smallest files + + Write your findings to a file named file_stats.json with this structure: + ```json + { + "total_files": , + "files_by_extension": { + ".rs": , + ".yaml": , + ... + }, + "total_lines": , + "total_size_bytes": , + "largest_file": { + "path": "", + "size_bytes": + }, + "smallest_file": { + "path": "", + "size_bytes": + } + } + ``` + + Use shell commands like find, wc, and du to gather this data efficiently. + {% endif %} +extensions: + - type: builtin + name: developer + timeout: 300 + bundled: true diff --git a/scripts/test-subrecipes-examples/subrecipes/weather-data.yaml b/scripts/test-subrecipes-examples/subrecipes/weather-data.yaml deleted file mode 100644 index 6efb9ce510c7..000000000000 --- a/scripts/test-subrecipes-examples/subrecipes/weather-data.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "1.0.0" -title: "Weather Data Collector" -description: "Fetch current weather conditions for a location" -instructions: | - You are a weather data specialist. Gather current weather information - including temperature, conditions, and seasonal context. - -parameters: - - key: location - input_type: string - requirement: required - description: "City or location to get weather data for" - -extensions: - - type: builtin - name: developer - timeout: 300 - bundled: true - -prompt: | - Get the current weather conditions for {{ location }}. - Include temperature, weather conditions (sunny, rainy, etc.), - and any relevant seasonal information. diff --git a/scripts/test-subrecipes-examples/travel_planner.yaml b/scripts/test-subrecipes-examples/travel_planner.yaml deleted file mode 100644 index 1f48b11878f4..000000000000 --- a/scripts/test-subrecipes-examples/travel_planner.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "1.0.0" -title: "Travel Activity Planner" -description: "Get weather data and suggest appropriate activities" -instructions: | - Plan activities by first getting weather data, then suggesting activities based on conditions. - -prompt: | - Plan activities for Sydney by first getting weather data, then suggesting activities based on the weather conditions we receive. - -sub_recipes: - - name: weather_data - path: "{{ recipe_dir }}/subrecipes/weather-data.yaml" - # No values - location parameter comes from prompt context - - - name: activity_suggestions - path: "{{ recipe_dir }}/subrecipes/activity-suggestions.yaml" - # weather_conditions parameter comes from conversation context - -extensions: - - type: builtin - name: developer - timeout: 300 - bundled: true diff --git a/scripts/test-subrecipes-examples/travel_planner_parallel.yaml b/scripts/test-subrecipes-examples/travel_planner_parallel.yaml deleted file mode 100644 index bb1ee1a03717..000000000000 --- a/scripts/test-subrecipes-examples/travel_planner_parallel.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "1.0.0" -title: "Travel Activity Planner (Parallel)" -description: "Get weather data and suggest activities in parallel" -instructions: | - Plan activities by getting weather data and activity suggestions in parallel to save time. - -prompt: | - Run the following subrecipes in parallel to plan activities for Sydney: - - use weather_data subrecipe to get the weather for Sydney - - use activity_suggestions subrecipe to suggest activities for overcast, cool weather - -sub_recipes: - - name: weather_data - path: "{{ recipe_dir }}/subrecipes/weather-data.yaml" - - - name: activity_suggestions - path: "{{ recipe_dir }}/subrecipes/activity-suggestions.yaml" - -extensions: - - type: builtin - name: developer - timeout: 300 - bundled: true diff --git a/scripts/test_subrecipes.sh b/scripts/test_subrecipes.sh index 29920f2e2c0c..02505565da4f 100755 --- a/scripts/test_subrecipes.sh +++ b/scripts/test_subrecipes.sh @@ -20,8 +20,9 @@ SCRIPT_DIR=$(pwd) export PATH="$SCRIPT_DIR/target/release:$PATH" # Set default provider and model if not already set +# Use fast model for CI to speed up tests export GOOSE_PROVIDER="${GOOSE_PROVIDER:-anthropic}" -export GOOSE_MODEL="${GOOSE_MODEL:-claude-sonnet-4-5-20250929}" +export GOOSE_MODEL="${GOOSE_MODEL:-claude-3-5-haiku-20241022}" echo "Using provider: $GOOSE_PROVIDER" echo "Using model: $GOOSE_MODEL" @@ -35,7 +36,39 @@ echo "Copied test recipes from scripts/test-subrecipes-examples" echo "" echo "=== Testing Subrecipe Workflow ===" -echo "Recipe: $TESTDIR/travel_planner.yaml" +echo "Recipe: $TESTDIR/project_analyzer.yaml" +echo "" + +# Create sample code files for analysis +echo "Creating sample code files for testing..." +cat > "$TESTDIR/sample.rs" << 'EOF' +// TODO: Add error handling +fn calculate(x: i32, y: i32) -> i32 { + x + y +} + +#[test] +fn test_calculate() { + assert_eq!(calculate(2, 2), 4); +} +EOF + +cat > "$TESTDIR/sample.py" << 'EOF' +# FIXME: Optimize this function +def process_data(items): + """Process a list of items""" + return [item * 2 for item in items] + +def test_process_data(): + assert process_data([1, 2, 3]) == [2, 4, 6] +EOF + +cat > "$TESTDIR/README.md" << 'EOF' +# Sample Project +This is a test project for analyzing code patterns. +## TODO +- Add more tests +EOF echo "" RESULTS=() @@ -52,8 +85,8 @@ check_recipe_output() { RESULTS+=("✗ Subrecipe tool invocation ($mode)") fi - if grep -q "weather_data" "$tmpfile" && grep -q "activity_suggestions" "$tmpfile"; then - echo "✓ SUCCESS: Both subrecipes (weather_data, activity_suggestions) found in output" + if grep -q "file_stats" "$tmpfile" && grep -q "code_patterns" "$tmpfile"; then + echo "✓ SUCCESS: Both subrecipes (file_stats, code_patterns) found in output" RESULTS+=("✓ Both subrecipes present ($mode)") else echo "✗ FAILED: Not all subrecipes found in output" @@ -69,37 +102,11 @@ check_recipe_output() { fi } -echo "Test 1: Running recipe with session..." -TMPFILE=$(mktemp) -if (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --recipe travel_planner.yaml 2>&1) | tee "$TMPFILE"; then - echo "✓ SUCCESS: Recipe completed successfully" - RESULTS+=("✓ Recipe exit code (with session)") - check_recipe_output "$TMPFILE" "with session" -else - echo "✗ FAILED: Recipe execution failed" - RESULTS+=("✗ Recipe exit code (with session)") -fi -rm "$TMPFILE" -echo "" - -echo "Test 2: Running recipe in --no-session mode..." -TMPFILE=$(mktemp) -if (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --recipe travel_planner.yaml --no-session 2>&1) | tee "$TMPFILE"; then - echo "✓ SUCCESS: Recipe completed successfully" - RESULTS+=("✓ Recipe exit code (--no-session)") - check_recipe_output "$TMPFILE" "--no-session" -else - echo "✗ FAILED: Recipe execution failed" - RESULTS+=("✗ Recipe exit code (--no-session)") -fi -rm "$TMPFILE" -echo "" - -echo "Test 3: Running recipe with parallel subrecipes..." +echo "Running recipe with parallel subrecipes..." TMPFILE=$(mktemp) -if (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --recipe travel_planner_parallel.yaml 2>&1) | tee "$TMPFILE"; then +if (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --recipe project_analyzer_parallel.yaml --no-session 2>&1) | tee "$TMPFILE"; then echo "✓ SUCCESS: Recipe completed successfully" - RESULTS+=("✓ Recipe exit code (parallel)") + RESULTS+=("✓ Recipe exit code") check_recipe_output "$TMPFILE" "parallel" if grep -q "execution_mode: parallel" "$TMPFILE"; then @@ -111,7 +118,7 @@ if (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --recipe travel_plan fi else echo "✗ FAILED: Recipe execution failed" - RESULTS+=("✗ Recipe exit code (parallel)") + RESULTS+=("✗ Recipe exit code") fi rm "$TMPFILE" echo "" From 544271772d105f3e71b7da48bb1b27c5f4d3537c Mon Sep 17 00:00:00 2001 From: BestCodes <106822363+The-Best-Codes@users.noreply.github.com> Date: Fri, 31 Oct 2025 03:01:52 -0500 Subject: [PATCH 047/121] feat: YT Short for Canva MCP + goose (#5495) Signed-off-by: fbalicchia --- .../pages/community/data/community-content.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 67a91b81a2e3..691a63d3a9fe 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -194,6 +194,18 @@ "tags": ["hacktoberfest"], "hacktoberfest": true }, + { + "title": "Goose with Canva MCP", + "author": { + "name": "BestCodes", + "handle": "the-best-codes" + }, + "type": "video", + "url": "https://www.youtube.com/shorts/xBGTa8XenVc", + "submittedDate": "2025-10-30", + "tags": ["hacktoberfest"], + "hacktoberfest": true + }, { "title": "goose with Apify MCP", "author": { @@ -206,7 +218,7 @@ "tags": ["hacktoberfest"], "hacktoberfest": true }, - { + { "title": "Building Custom Tools and Extensions for goose: A Developer's Guide", "author": { "name": "Anudhyan Datta", @@ -232,4 +244,4 @@ "hacktoberfest": true } ] -} \ No newline at end of file +} From eb810c3e6de03393f24c9a8f567d349250f10f80 Mon Sep 17 00:00:00 2001 From: Adrian Cole <64215+codefromthecrypt@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:18:20 +0800 Subject: [PATCH 048/121] Propagate session ID in LLM and MCP requests (#5165) Signed-off-by: fbalicchia --- crates/goose/src/agents/agent.rs | 8 +- crates/goose/src/agents/mcp_client.rs | 128 ++++++++++++++- crates/goose/src/agents/subagent_handler.rs | 13 +- crates/goose/src/lib.rs | 1 + crates/goose/src/providers/api_client.rs | 57 +++++++ crates/goose/src/providers/mod.rs | 2 +- crates/goose/src/providers/openai.rs | 14 ++ crates/goose/src/scheduler.rs | 10 +- crates/goose/src/session_context.rs | 80 +++++++++ .../tests/session_id_propagation_test.rs | 155 ++++++++++++++++++ 10 files changed, 449 insertions(+), 19 deletions(-) create mode 100644 crates/goose/src/session_context.rs create mode 100644 crates/goose/tests/session_id_propagation_test.rs diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index dd44f28850dd..444c7666f13a 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -825,11 +825,9 @@ impl Agent { } } Err(e) => { - yield AgentEvent::Message( - Message::assistant().with_text( - format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") - ) - ); + yield AgentEvent::Message(Message::assistant().with_text( + format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") + )); } } })) diff --git a/crates/goose/src/agents/mcp_client.rs b/crates/goose/src/agents/mcp_client.rs index 88c017a2e402..d42d62488d9b 100644 --- a/crates/goose/src/agents/mcp_client.rs +++ b/crates/goose/src/agents/mcp_client.rs @@ -1,4 +1,5 @@ use crate::agents::types::SharedProvider; +use crate::session_context::SESSION_ID_HEADER; use rmcp::model::{Content, ErrorCode, JsonObject}; /// MCP client implementation for Goose use rmcp::{ @@ -334,7 +335,7 @@ impl McpClientTrait for McpClient { ClientRequest::ListResourcesRequest(ListResourcesRequest { params: Some(PaginatedRequestParam { cursor }), method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -358,7 +359,7 @@ impl McpClientTrait for McpClient { uri: uri.to_string(), }, method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -380,7 +381,7 @@ impl McpClientTrait for McpClient { ClientRequest::ListToolsRequest(ListToolsRequest { params: Some(PaginatedRequestParam { cursor }), method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -406,7 +407,7 @@ impl McpClientTrait for McpClient { arguments, }, method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -428,7 +429,7 @@ impl McpClientTrait for McpClient { ClientRequest::ListPromptsRequest(ListPromptsRequest { params: Some(PaginatedRequestParam { cursor }), method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -458,7 +459,7 @@ impl McpClientTrait for McpClient { arguments, }, method: Default::default(), - extensions: Default::default(), + extensions: inject_session_into_extensions(Default::default()), }), cancel_token, ) @@ -476,3 +477,118 @@ impl McpClientTrait for McpClient { rx } } + +/// Replaces session ID, case-insensitively, in Extensions._meta. +fn inject_session_into_extensions( + mut extensions: rmcp::model::Extensions, +) -> rmcp::model::Extensions { + use rmcp::model::Meta; + + if let Some(session_id) = crate::session_context::current_session_id() { + let mut meta_map = extensions + .get::() + .map(|meta| meta.0.clone()) + .unwrap_or_default(); + + // JsonObject is case-sensitive, so we use retain for case-insensitive removal + meta_map.retain(|k, _| !k.eq_ignore_ascii_case(SESSION_ID_HEADER)); + + meta_map.insert(SESSION_ID_HEADER.to_string(), Value::String(session_id)); + + extensions.insert(Meta(meta_map)); + } + + extensions +} + +#[cfg(test)] +mod tests { + use super::*; + use rmcp::model::Meta; + + #[tokio::test] + async fn test_session_id_in_mcp_meta() { + use serde_json::json; + + let session_id = "test-session-789"; + crate::session_context::with_session_id(Some(session_id.to_string()), async { + let extensions = inject_session_into_extensions(Default::default()); + let meta = extensions.get::().unwrap(); + + assert_eq!( + &meta.0, + json!({ + SESSION_ID_HEADER: session_id + }) + .as_object() + .unwrap() + ); + }) + .await; + } + + #[tokio::test] + async fn test_no_session_id_in_mcp_when_absent() { + let extensions = inject_session_into_extensions(Default::default()); + let meta = extensions.get::(); + + assert!(meta.is_none()); + } + + #[tokio::test] + async fn test_all_mcp_operations_include_session() { + use serde_json::json; + + let session_id = "consistent-session-id"; + crate::session_context::with_session_id(Some(session_id.to_string()), async { + let ext1 = inject_session_into_extensions(Default::default()); + let ext2 = inject_session_into_extensions(Default::default()); + let ext3 = inject_session_into_extensions(Default::default()); + + for ext in [&ext1, &ext2, &ext3] { + assert_eq!( + &ext.get::().unwrap().0, + json!({ + SESSION_ID_HEADER: session_id + }) + .as_object() + .unwrap() + ); + } + }) + .await; + } + + #[tokio::test] + async fn test_session_id_case_insensitive_replacement() { + use rmcp::model::{Extensions, Meta}; + use serde_json::{from_value, json}; + + let session_id = "new-session-id"; + crate::session_context::with_session_id(Some(session_id.to_string()), async { + let mut extensions = Extensions::new(); + extensions.insert( + from_value::(json!({ + "GOOSE-SESSION-ID": "old-session-1", + "Goose-Session-Id": "old-session-2", + "other-key": "preserve-me" + })) + .unwrap(), + ); + + let extensions = inject_session_into_extensions(extensions); + let meta = extensions.get::().unwrap(); + + assert_eq!( + &meta.0, + json!({ + SESSION_ID_HEADER: session_id, + "other-key": "preserve-me" + }) + .as_object() + .unwrap() + ); + }) + .await; + } +} diff --git a/crates/goose/src/agents/subagent_handler.rs b/crates/goose/src/agents/subagent_handler.rs index 5359573fe248..47ee99d08879 100644 --- a/crates/goose/src/agents/subagent_handler.rs +++ b/crates/goose/src/agents/subagent_handler.rs @@ -164,10 +164,15 @@ fn get_agent_messages( } else { None }; - let mut stream = agent - .reply(conversation.clone(), session_config, None) - .await - .map_err(|e| anyhow!("Failed to get reply from agent: {}", e))?; + + let session_id = session_config.as_ref().map(|s| s.id.clone()); + let mut stream = crate::session_context::with_session_id(session_id, async { + agent + .reply(conversation.clone(), session_config, None) + .await + }) + .await + .map_err(|e| anyhow!("Failed to get reply from agent: {}", e))?; while let Some(message_result) = stream.next().await { match message_result { Ok(AgentEvent::Message(msg)) => conversation.push(msg), diff --git a/crates/goose/src/lib.rs b/crates/goose/src/lib.rs index 9e8fdad19002..f5383c8be583 100644 --- a/crates/goose/src/lib.rs +++ b/crates/goose/src/lib.rs @@ -17,6 +17,7 @@ pub mod scheduler_factory; pub mod scheduler_trait; pub mod security; pub mod session; +pub mod session_context; pub mod token_counter; pub mod tool_inspection; pub mod tool_monitor; diff --git a/crates/goose/src/providers/api_client.rs b/crates/goose/src/providers/api_client.rs index 821148bae757..449a74e2086c 100644 --- a/crates/goose/src/providers/api_client.rs +++ b/crates/goose/src/providers/api_client.rs @@ -1,3 +1,4 @@ +use crate::session_context::SESSION_ID_HEADER; use anyhow::Result; use async_trait::async_trait; use reqwest::{ @@ -369,6 +370,10 @@ impl<'a> ApiRequestBuilder<'a> { let mut request = request_builder(url, &self.client.client); request = request.headers(self.headers.clone()); + if let Some(session_id) = crate::session_context::current_session_id() { + request = request.header(SESSION_ID_HEADER, session_id); + } + request = match &self.client.auth { AuthMethod::BearerToken(token) => { request.header("Authorization", format!("Bearer {}", token)) @@ -398,3 +403,55 @@ impl fmt::Debug for ApiClient { .finish_non_exhaustive() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_session_id_header_injection() { + let client = ApiClient::new( + "http://localhost:8080".to_string(), + AuthMethod::BearerToken("test-token".to_string()), + ) + .unwrap(); + + // Execute request within session context + crate::session_context::with_session_id(Some("test-session-456".to_string()), async { + let builder = client.request("/test"); + let request = builder + .send_request(|url, client| client.get(url)) + .await + .unwrap(); + + let headers = request.build().unwrap().headers().clone(); + + assert!(headers.contains_key(SESSION_ID_HEADER)); + assert_eq!( + headers.get(SESSION_ID_HEADER).unwrap().to_str().unwrap(), + "test-session-456" + ); + }) + .await; + } + + #[tokio::test] + async fn test_no_session_id_header_when_absent() { + let client = ApiClient::new( + "http://localhost:8080".to_string(), + AuthMethod::BearerToken("test-token".to_string()), + ) + .unwrap(); + + // Build a request without session context + let builder = client.request("/test"); + let request = builder + .send_request(|url, client| client.get(url)) + .await + .unwrap(); + + let headers = request.build().unwrap().headers().clone(); + + assert!(!headers.contains_key(SESSION_ID_HEADER)); + } +} diff --git a/crates/goose/src/providers/mod.rs b/crates/goose/src/providers/mod.rs index d50502a42b92..5658bdaff854 100644 --- a/crates/goose/src/providers/mod.rs +++ b/crates/goose/src/providers/mod.rs @@ -1,5 +1,5 @@ pub mod anthropic; -mod api_client; +pub mod api_client; pub mod azure; pub mod azureauth; pub mod base; diff --git a/crates/goose/src/providers/openai.rs b/crates/goose/src/providers/openai.rs index d869d48d2eb4..8bb9f1a9e780 100644 --- a/crates/goose/src/providers/openai.rs +++ b/crates/goose/src/providers/openai.rs @@ -112,6 +112,20 @@ impl OpenAiProvider { }) } + #[doc(hidden)] + pub fn new(api_client: ApiClient, model: ModelConfig) -> Self { + Self { + api_client, + base_path: "v1/chat/completions".to_string(), + organization: None, + project: None, + model, + custom_headers: None, + supports_streaming: true, + name: Self::metadata().name, + } + } + pub fn from_custom_config( model: ModelConfig, config: DeclarativeProviderConfig, diff --git a/crates/goose/src/scheduler.rs b/crates/goose/src/scheduler.rs index 0fd040817e1b..45eaeb13fa3b 100644 --- a/crates/goose/src/scheduler.rs +++ b/crates/goose/src/scheduler.rs @@ -1216,9 +1216,13 @@ async fn run_scheduled_job_internal( retry_config: None, }; - match agent - .reply(conversation.clone(), Some(session_config.clone()), None) - .await + let session_id = Some(session_config.id.clone()); + match crate::session_context::with_session_id(session_id, async { + agent + .reply(conversation.clone(), Some(session_config.clone()), None) + .await + }) + .await { Ok(mut stream) => { use futures::StreamExt; diff --git a/crates/goose/src/session_context.rs b/crates/goose/src/session_context.rs new file mode 100644 index 000000000000..7379e348df62 --- /dev/null +++ b/crates/goose/src/session_context.rs @@ -0,0 +1,80 @@ +use tokio::task_local; + +pub const SESSION_ID_HEADER: &str = "goose-session-id"; + +task_local! { + pub static SESSION_ID: Option; +} + +pub async fn with_session_id(session_id: Option, f: F) -> F::Output +where + F: std::future::Future, +{ + if let Some(id) = session_id { + SESSION_ID.scope(Some(id), f).await + } else { + f.await + } +} + +pub fn current_session_id() -> Option { + SESSION_ID.try_with(|id| id.clone()).ok().flatten() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_session_id_available_when_set() { + with_session_id(Some("test-session-123".to_string()), async { + assert_eq!(current_session_id(), Some("test-session-123".to_string())); + }) + .await; + } + + #[tokio::test] + async fn test_session_id_none_when_not_set() { + let id = current_session_id(); + assert_eq!(id, None); + } + + #[tokio::test] + async fn test_session_id_none_when_explicitly_none() { + with_session_id(None, async { + assert_eq!(current_session_id(), None); + }) + .await; + } + + #[tokio::test] + async fn test_session_id_scoped_correctly() { + assert_eq!(current_session_id(), None); + + with_session_id(Some("outer-session".to_string()), async { + assert_eq!(current_session_id(), Some("outer-session".to_string())); + + with_session_id(Some("inner-session".to_string()), async { + assert_eq!(current_session_id(), Some("inner-session".to_string())); + }) + .await; + + assert_eq!(current_session_id(), Some("outer-session".to_string())); + }) + .await; + + assert_eq!(current_session_id(), None); + } + + #[tokio::test] + async fn test_session_id_across_await_points() { + with_session_id(Some("persistent-session".to_string()), async { + assert_eq!(current_session_id(), Some("persistent-session".to_string())); + + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + + assert_eq!(current_session_id(), Some("persistent-session".to_string())); + }) + .await; + } +} diff --git a/crates/goose/tests/session_id_propagation_test.rs b/crates/goose/tests/session_id_propagation_test.rs new file mode 100644 index 000000000000..10a83a6261f3 --- /dev/null +++ b/crates/goose/tests/session_id_propagation_test.rs @@ -0,0 +1,155 @@ +use goose::conversation::message::Message; +use goose::model::ModelConfig; +use goose::providers::api_client::{ApiClient, AuthMethod}; +use goose::providers::base::Provider; +use goose::providers::openai::OpenAiProvider; +use goose::session_context; +use goose::session_context::SESSION_ID_HEADER; +use serde_json::json; +use std::sync::Arc; +use std::sync::Mutex; +use wiremock::matchers::{method, path}; +use wiremock::{Mock, MockServer, Request, ResponseTemplate}; + +#[derive(Clone, Default)] +struct HeaderCapture { + captured_headers: Arc>>>, +} + +impl HeaderCapture { + fn new() -> Self { + Self { + captured_headers: Arc::new(Mutex::new(Vec::new())), + } + } + + fn capture_session_header(&self, req: &Request) { + let session_id = req + .headers + .get(SESSION_ID_HEADER) + .map(|v| v.to_str().unwrap().to_string()); + self.captured_headers.lock().unwrap().push(session_id); + } + + fn get_captured(&self) -> Vec> { + self.captured_headers.lock().unwrap().clone() + } +} + +fn create_test_provider(mock_server_url: &str) -> Box { + let api_client = ApiClient::new( + mock_server_url.to_string(), + AuthMethod::BearerToken("test-key".to_string()), + ) + .unwrap(); + let model = ModelConfig::new_or_fail("gpt-5-nano"); + Box::new(OpenAiProvider::new(api_client, model)) +} + +async fn setup_mock_server() -> (MockServer, HeaderCapture, Box) { + let mock_server = MockServer::start().await; + let capture = HeaderCapture::new(); + let capture_clone = capture.clone(); + + Mock::given(method("POST")) + .and(path("/v1/chat/completions")) + .respond_with(move |req: &Request| { + capture_clone.capture_session_header(req); + ResponseTemplate::new(200).set_body_json(json!({ + "choices": [{ + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Hi there! How can I help you today?", + "role": "assistant" + } + }], + "created": 1755133833, + "id": "chatcmpl-test", + "model": "gpt-5-nano", + "usage": { + "completion_tokens": 10, + "prompt_tokens": 8, + "total_tokens": 18 + } + })) + }) + .mount(&mock_server) + .await; + + let provider = create_test_provider(&mock_server.uri()); + (mock_server, capture, provider) +} + +async fn make_request(provider: &dyn Provider, session_id: Option<&str>) { + let message = Message::user().with_text("test message"); + let request_fn = async { + provider + .complete("You are a helpful assistant.", &[message], &[]) + .await + .unwrap() + }; + + match session_id { + Some(id) => { + session_context::with_session_id(Some(id.to_string()), request_fn).await; + } + None => { + request_fn.await; + } + } +} + +#[tokio::test] +async fn test_session_id_propagation_to_llm() { + let (_, capture, provider) = setup_mock_server().await; + + make_request(provider.as_ref(), Some("integration-test-session-123")).await; + + assert_eq!( + capture.get_captured(), + vec![Some("integration-test-session-123".to_string())] + ); +} + +#[tokio::test] +async fn test_no_session_id_when_absent() { + let (_, capture, provider) = setup_mock_server().await; + + make_request(provider.as_ref(), None).await; + + assert_eq!(capture.get_captured(), vec![None]); +} + +#[tokio::test] +async fn test_session_id_matches_across_calls() { + let (_, capture, provider) = setup_mock_server().await; + + let test_session_id = "consistent-session-456"; + make_request(provider.as_ref(), Some(test_session_id)).await; + make_request(provider.as_ref(), Some(test_session_id)).await; + make_request(provider.as_ref(), Some(test_session_id)).await; + + assert_eq!( + capture.get_captured(), + vec![Some(test_session_id.to_string()); 3] + ); +} + +#[tokio::test] +async fn test_different_sessions_have_different_ids() { + let (_, capture, provider) = setup_mock_server().await; + + let session_id_1 = "session-one"; + let session_id_2 = "session-two"; + make_request(provider.as_ref(), Some(session_id_1)).await; + make_request(provider.as_ref(), Some(session_id_2)).await; + + assert_eq!( + capture.get_captured(), + vec![ + Some(session_id_1.to_string()), + Some(session_id_2.to_string()) + ] + ); +} From 2fdc6e26110a5f516e7357d1d271a05ce28db04e Mon Sep 17 00:00:00 2001 From: Carine Bruyndoncx Date: Fri, 31 Oct 2025 14:49:11 +0100 Subject: [PATCH 049/121] FIX: prefer linux in WSL and add INSTALL_OS override for CLI (#5215) Signed-off-by: Carine Bruyndoncx Signed-off-by: fbalicchia --- download_cli.sh | 50 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/download_cli.sh b/download_cli.sh index 2693f0409b19..572563ded58a 100755 --- a/download_cli.sh +++ b/download_cli.sh @@ -88,26 +88,52 @@ else fi # --- 3) Detect OS/Architecture --- -# Better OS detection for Windows environments -if [[ "${WINDIR:-}" ]] || [[ "${windir:-}" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then - OS="windows" -elif [[ -f "/proc/version" ]] && grep -q "Microsoft\|WSL" /proc/version 2>/dev/null; then - # WSL detection +# Allow explicit override for automation or when auto-detection is wrong: +# INSTALL_OS=linux|windows|darwin +if [ -n "${INSTALL_OS:-}" ]; then + case "${INSTALL_OS}" in + linux|windows|darwin) OS="${INSTALL_OS}" ;; + *) echo "[error]: unsupported INSTALL_OS='${INSTALL_OS}' (expected: linux|windows|darwin)"; exit 1 ;; + esac +else + # Better OS detection for Windows environments, with safer WSL handling. + # If explicit Windows-like shells/variables are present (MSYS/Cygwin), treat as windows. + if [[ "${WINDIR:-}" ]] || [[ "${windir:-}" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then OS="windows" -elif [[ "$PWD" =~ ^/mnt/[a-zA-Z]/ ]]; then - # WSL mount point detection (like /mnt/c/) + elif [[ -f "/proc/version" ]] && grep -q "Microsoft\|WSL" /proc/version 2>/dev/null; then + # WSL detected. Prefer Linux unless there are clear signs we should install the Windows build: + # - running on a Windows-mounted path like /mnt/c/... OR + # - Windows executables are available AND we're on a Windows mount + if [[ "$PWD" =~ ^/mnt/[a-zA-Z]/ ]]; then + OS="windows" + else + # If powershell/cmd exist, only treat as Windows when in a Windows mount + if command -v powershell.exe >/dev/null 2>&1 || command -v cmd.exe >/dev/null 2>&1; then + if [[ "$PWD" =~ ^/mnt/[a-zA-Z]/ ]] || [[ -d "/c" || -d "/d" || -d "/e" ]]; then + OS="windows" + else + OS="linux" + fi + else + # No strong Windows interop present — install Linux build inside WSL by default + OS="linux" + fi + fi + elif [[ "$PWD" =~ ^/mnt/[a-zA-Z]/ ]]; then + # WSL mount point detection (like /mnt/c/) outside of /proc/version check OS="windows" -elif [[ "$OSTYPE" == "darwin"* ]]; then + elif [[ "$OSTYPE" == "darwin"* ]]; then OS="darwin" -elif command -v powershell.exe >/dev/null 2>&1 || command -v cmd.exe >/dev/null 2>&1; then - # Check if Windows executables are available (another Windows indicator) + elif command -v powershell.exe >/dev/null 2>&1 || command -v cmd.exe >/dev/null 2>&1; then + # Presence of Windows executables (likely a Windows environment) OS="windows" -elif [[ "$PWD" =~ ^/[a-zA-Z]/ ]] && [[ -d "/c" || -d "/d" || -d "/e" ]]; then + elif [[ "$PWD" =~ ^/[a-zA-Z]/ ]] && [[ -d "/c" || -d "/d" || -d "/e" ]]; then # Check for Windows-style mount points (like in Git Bash) OS="windows" -else + else # Fallback to uname for other systems OS=$(uname -s | tr '[:upper:]' '[:lower:]') + fi fi ARCH=$(uname -m) From 007fbb8b3ec41c355bd0cc30306eda689bff9c77 Mon Sep 17 00:00:00 2001 From: Emma Youndtsmith <90283317+emma-squared@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:08:52 -0500 Subject: [PATCH 050/121] Improve subagents docs (#5484) Signed-off-by: fbalicchia --- .../docs/guides/environment-variables.md | 4 ++ documentation/docs/guides/subagents.mdx | 68 ++++++++++++++----- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/documentation/docs/guides/environment-variables.md b/documentation/docs/guides/environment-variables.md index 40c5b02d6f70..392c90f57d89 100644 --- a/documentation/docs/guides/environment-variables.md +++ b/documentation/docs/guides/environment-variables.md @@ -152,6 +152,7 @@ These variables control how goose manages conversation sessions and context. |----------|---------|---------|---------| | `GOOSE_CONTEXT_STRATEGY` | Controls how goose handles context limit exceeded situations | "summarize", "truncate", "clear", "prompt" | "prompt" (interactive), "summarize" (headless) | | `GOOSE_MAX_TURNS` | [Maximum number of turns](/docs/guides/sessions/smart-context-management#maximum-turns) allowed without user input | Integer (e.g., 10, 50, 100) | 1000 | +| `GOOSE_SUBAGENT_MAX_TURNS` | Sets the maximum turns allowed for a [subagent](/docs/guides/subagents) to complete before timeout | Integer (e.g., 25) | 25 | | `CONTEXT_FILE_NAMES` | Specifies custom filenames for [hint/context files](/docs/guides/using-goosehints#custom-context-files) | JSON array of strings (e.g., `["CLAUDE.md", ".goosehints"]`) | `[".goosehints"]` | | `GOOSE_CLI_THEME` | [Theme](/docs/guides/goose-cli-commands#themes) for CLI response markdown | "light", "dark", "ansi" | "dark" | | `GOOSE_RANDOM_THINKING_MESSAGES` | Controls whether to show amusing random messages during processing | "true", "false" | "true" | @@ -176,6 +177,9 @@ export GOOSE_MAX_TURNS=25 # Set a reasonable limit for production export GOOSE_MAX_TURNS=100 +# Customize subagent turn limit +export GOOSE_SUBAGENT_MAX_TURNS=50 + # Use multiple context files export CONTEXT_FILE_NAMES='["CLAUDE.md", ".goosehints", ".cursorrules", "project_rules.txt"]' diff --git a/documentation/docs/guides/subagents.mdx b/documentation/docs/guides/subagents.mdx index 776a51236704..29d46d08343c 100644 --- a/documentation/docs/guides/subagents.mdx +++ b/documentation/docs/guides/subagents.mdx @@ -20,12 +20,17 @@ Subagents are independent instances that execute tasks while keeping your main c ## How to Use Subagents -To use subagents, ask Goose to delegate tasks using natural language. Goose automatically decides when to spawn subagents and handles their lifecycle. You can: +:::tip Autonomous Subagent Creation +goose can autonomously decide to use subagents when it determines they would be beneficial for your task - you don't always need to explicitly request them. This happens automatically in autonomous mode (the default). Subagents are disabled in chat-only mode. +::: + +To use subagents, ask goose to delegate tasks using natural language. goose automatically decides when to spawn subagents and handles their lifecycle. You can: 1. **Request specialized help**: "Use a code reviewer to analyze this function for security issues" 2. **Reference specific recipes**: "Use the 'security-auditor' recipe to scan this endpoint" 3. **Run parallel tasks**: "Create three HTML templates simultaneously" 4. **Delegate complex work**: "Research quantum computing developments and summarize findings" +5. **Control extension access**: "Create a subagent with only the developer extension to refactor the code" You can run multiple subagents sequentially or in parallel. @@ -40,7 +45,7 @@ If a subagent fails or times out (5-minute default), you will receive no output ## Internal Subagents -Internal subagents spawn Goose instances to handle tasks using your current session's context and extensions. There are two ways to configure and execute internal subagents: +Internal subagents spawn goose instances to handle tasks using your current session's context and extensions. There are two ways to configure and execute internal subagents: 1. **Direct Prompts** - Quick, one-off tasks using natural language instructions 2. **Recipes** - Reusable, structured configurations for specialized subagent behavior @@ -48,7 +53,7 @@ Internal subagents spawn Goose instances to handle tasks using your current sess ### Direct Prompts Direct prompts provided for one-off tasks using natural language prompts. The main agent automatically configures the subagent based on your request. -**Goose Prompt:** +**goose Prompt:** ``` "Use 2 subagents to create hello.html with 'Hello World' content and goodbye.html with 'Goodbye World' content in parallel" ``` @@ -116,16 +121,16 @@ prompt: | Provide specific, actionable feedback with examples. ``` -**Place your recipe file where Goose can find it** +**Place your recipe file where goose can find it** - Set [`GOOSE_RECIPE_PATH`](/docs/guides/recipes/recipe-reference#recipe-location) environment variable to your recipe directory - Or place it in your current working directory -**Goose Prompt** +**goose Prompt** ``` Use the "code-reviewer" recipe to analyze the authentication feature I implemented ``` -**Goose Output** +**goose Output** ``` I'll use your code-reviewer recipe to create a specialized subagent for this analysis. @@ -148,9 +153,9 @@ I'll use your code-reviewer recipe to create a specialized subagent for this ana ## External Subagents -External subagents let you bring in AI agents from other providers and platforms, enabling Goose to coordinate and integrate your workflow with the broader ecosystem. In the below example, we use Codex as a subagent by running it as an MCP server: +External subagents let you bring in AI agents from other providers and platforms, enabling goose to coordinate and integrate your workflow with the broader ecosystem. In the below example, we use Codex as a subagent by running it as an MCP server: -**[Goose Configuration File](/docs/guides/config-files)** (`.~/.config/goose/config.yaml `): +**[goose Configuration File](/docs/guides/config-files)** (`.~/.config/goose/config.yaml `): ```yaml subagent: args: @@ -180,12 +185,12 @@ approval_policy = "never" mode = "workspace-write" ``` -**Goose Prompt:** +**goose Prompt:** ``` "Use the codex subagent to analyze my codebase structure and identify the main components" ``` -**Goose Output:** +**goose Output:** ```md Based on my analysis of your codebase, here are the main components: @@ -233,26 +238,55 @@ Subagents are temporary instances that exist only for task execution. After the ## Configuration -Subagents are automatically have the following pre-configured settings, but you can override any defaults using natural language in your prompts. +Subagents use the following pre-configured settings, but you can override any defaults using natural language in your prompts. ### Default Settings -| Parameter | Default | Source | -|-----------|---------|--------| -| **Max Turns** | 10 | Built-in default | -| **Timeout** | 5 minutes | Built-in default | +| Parameter | Default | How to Customize | +|-----------|---------|------------------| +| **Max Turns** | 25 | Use natural language or set `GOOSE_SUBAGENT_MAX_TURNS` | +| **Timeout** | 5 minutes | Request longer timeout in your prompt | +| **Extensions** | Inherited from parent | Specify which extensions to use in your prompt | +| **Return Mode** | All subagent information provided in main session | Specify how much detail you want in your prompt | ### Customizing Settings in Prompts You can override any default by including the setting in your natural language request: **Examples:** +``` +"Use subagents to analyze code, limit each to 5 turns" +``` + +``` +"Use a research subagent with 30 turns and 20-minute timeout to investigate quantum computing trends" +``` + +**Environment variable:** Set `GOOSE_SUBAGENT_MAX_TURNS` to change the default max turns for all subagents. + +### Extension Control + +Control which tools and capabilities subagents can access. By default, subagents inherit all extensions from your main session, but you can restrict access for security, focus or performance. + +**Examples:** +``` +"Create a subagent to write a summary, but don't give it file access" +``` + +``` +"Use a subagent with only code editing tools to refactor main.py" +``` + +### Return Mode Control +Choose how much information goose provides from its subagents in your main session. +**Full Details (Default):** See all tool executions and reasoning steps ``` -"Use subagents to write a test and documentation, but make them timeout after 7 minutes" +"Create a subagent to debug this issue - I want to see the full investigation process" ``` +**Summary Only:** Get just the final result to keep your conversation clean ``` -""Use subagents to analyze code, limit each to 5 turns"" +"Use a subagent to research this topic and summarize the key findings" ``` ## Security Constraints From 44371a6dec1ecfc4b3d07813e57250a8f895eab2 Mon Sep 17 00:00:00 2001 From: Andrew Harvard Date: Fri, 31 Oct 2025 13:11:08 -0400 Subject: [PATCH 051/121] [Autovisualiser] remove unnecessary content from mermaid HTML template (#5505) Signed-off-by: fbalicchia --- .../src/autovisualiser/templates/mermaid_template.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/goose-mcp/src/autovisualiser/templates/mermaid_template.html b/crates/goose-mcp/src/autovisualiser/templates/mermaid_template.html index 69823495a58f..11e70d85d9d3 100644 --- a/crates/goose-mcp/src/autovisualiser/templates/mermaid_template.html +++ b/crates/goose-mcp/src/autovisualiser/templates/mermaid_template.html @@ -169,5 +169,4 @@

Mermaid Diagram

}; - -c:\Users\ARYA SINGH\Dropbox\PC\Desktop\goose\crates\goose-mcp\src\autovisualiser\templates\mermaid_template.html \ No newline at end of file + From 41128f035a92ada7cc923363c645d749eeb694f4 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:13:08 -0700 Subject: [PATCH 052/121] Improve system theme detection and fallback (#5427) Signed-off-by: fbalicchia --- ui/desktop/eslint.config.js | 1 + ui/desktop/src/App.tsx | 41 +++++++++ .../components/GooseSidebar/ThemeSelector.tsx | 92 ++++++++++++------- ui/desktop/src/main.ts | 11 +++ ui/desktop/src/preload.ts | 8 ++ ui/desktop/src/utils/ollamaDetection.test.ts | 2 +- 6 files changed, 120 insertions(+), 35 deletions(-) diff --git a/ui/desktop/eslint.config.js b/ui/desktop/eslint.config.js index 2241702d0e63..391d45a90ffa 100644 --- a/ui/desktop/eslint.config.js +++ b/ui/desktop/eslint.config.js @@ -85,6 +85,7 @@ module.exports = [ HeadersInit: 'readonly', KeyboardEvent: 'readonly', MouseEvent: 'readonly', // Add MouseEvent + Event: 'readonly', // Add Event Node: 'readonly', // Add Node React: 'readonly', handleAction: 'readonly', diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index 90199c4dd45b..d74e1dd8dd85 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -523,6 +523,47 @@ export function AppInner() { }; }, []); + useEffect(() => { + if (!window.electron) return; + + const handleThemeChanged = (_event: unknown, ...args: unknown[]) => { + const themeData = args[0] as { mode: string; useSystemTheme: boolean; theme: string }; + + if (themeData.useSystemTheme) { + localStorage.setItem('use_system_theme', 'true'); + } else { + localStorage.setItem('use_system_theme', 'false'); + localStorage.setItem('theme', themeData.theme); + } + + const isDark = themeData.useSystemTheme + ? window.matchMedia('(prefers-color-scheme: dark)').matches + : themeData.mode === 'dark'; + + if (isDark) { + document.documentElement.classList.add('dark'); + document.documentElement.classList.remove('light'); + } else { + document.documentElement.classList.remove('dark'); + document.documentElement.classList.add('light'); + } + + const storageEvent = new Event('storage') as Event & { + key: string | null; + newValue: string | null; + }; + storageEvent.key = themeData.useSystemTheme ? 'use_system_theme' : 'theme'; + storageEvent.newValue = themeData.useSystemTheme ? 'true' : themeData.theme; + window.dispatchEvent(storageEvent); + }; + + window.electron.on('theme-changed', handleThemeChanged); + + return () => { + window.electron.off('theme-changed', handleThemeChanged); + }; + }, []); + if (fatalError) { return ; } diff --git a/ui/desktop/src/components/GooseSidebar/ThemeSelector.tsx b/ui/desktop/src/components/GooseSidebar/ThemeSelector.tsx index f9499fb59916..7fd1d438f9f3 100644 --- a/ui/desktop/src/components/GooseSidebar/ThemeSelector.tsx +++ b/ui/desktop/src/components/GooseSidebar/ThemeSelector.tsx @@ -8,37 +8,67 @@ interface ThemeSelectorProps { horizontal?: boolean; } +const getIsDarkMode = (mode: 'light' | 'dark' | 'system'): boolean => { + if (mode === 'system') { + return window.matchMedia('(prefers-color-scheme: dark)').matches; + } + return mode === 'dark'; +}; + +const getThemeMode = (): 'light' | 'dark' | 'system' => { + const savedUseSystemTheme = localStorage.getItem('use_system_theme'); + if (savedUseSystemTheme === 'true') { + return 'system'; + } + + const savedTheme = localStorage.getItem('theme'); + if (savedTheme) { + return savedTheme === 'dark' ? 'dark' : 'light'; + } + + return getIsDarkMode('system') ? 'dark' : 'light'; +}; + +const setThemeModeStorage = (mode: 'light' | 'dark' | 'system') => { + if (mode === 'system') { + localStorage.setItem('use_system_theme', 'true'); + } else { + localStorage.setItem('use_system_theme', 'false'); + localStorage.setItem('theme', mode); + } + + const themeData = { + mode, + useSystemTheme: mode === 'system', + theme: mode === 'system' ? '' : mode, + }; + + window.electron?.broadcastThemeChange(themeData); +}; + const ThemeSelector: React.FC = ({ className = '', hideTitle = false, horizontal = false, }) => { - const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>(() => { - const savedUseSystemTheme = localStorage.getItem('use_system_theme') === 'true'; - if (savedUseSystemTheme) { - return 'system'; - } - const savedTheme = localStorage.getItem('theme'); - return savedTheme === 'dark' ? 'dark' : 'light'; - }); - - const [isDarkMode, setDarkMode] = useState(() => { - // First check localStorage to determine the intended theme - const savedUseSystemTheme = localStorage.getItem('use_system_theme') === 'true'; - const savedTheme = localStorage.getItem('theme'); - - if (savedUseSystemTheme) { - // Use system preference - const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - return systemPrefersDark; - } else if (savedTheme) { - // Use saved theme preference - return savedTheme === 'dark'; - } else { - // Fallback: check current DOM state to maintain consistency - return document.documentElement.classList.contains('dark'); - } - }); + const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>(getThemeMode); + const [isDarkMode, setDarkMode] = useState(() => getIsDarkMode(getThemeMode())); + + useEffect(() => { + const handleStorageChange = (e: { key: string | null; newValue: string | null }) => { + if (e.key === 'use_system_theme' || e.key === 'theme') { + const newThemeMode = getThemeMode(); + setThemeMode(newThemeMode); + setDarkMode(getIsDarkMode(newThemeMode)); + } + }; + + window.addEventListener('storage', handleStorageChange); + + return () => { + window.removeEventListener('storage', handleStorageChange); + }; + }, []); useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); @@ -51,14 +81,8 @@ const ThemeSelector: React.FC = ({ mediaQuery.addEventListener('change', handleThemeChange); - if (themeMode === 'system') { - setDarkMode(mediaQuery.matches); - localStorage.setItem('use_system_theme', 'true'); - } else { - setDarkMode(themeMode === 'dark'); - localStorage.setItem('use_system_theme', 'false'); - localStorage.setItem('theme', themeMode); - } + setThemeModeStorage(themeMode); + setDarkMode(getIsDarkMode(themeMode)); return () => mediaQuery.removeEventListener('change', handleThemeChange); }, [themeMode]); diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index da16344af096..0bbac7a99020 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -2051,6 +2051,17 @@ async function appMain() { } }); + ipcMain.on('broadcast-theme-change', (event, themeData) => { + const senderWindow = BrowserWindow.fromWebContents(event.sender); + const allWindows = BrowserWindow.getAllWindows(); + + allWindows.forEach((window) => { + if (window.id !== senderWindow?.id) { + window.webContents.send('theme-changed', themeData); + } + }); + }); + ipcMain.on('reload-app', (event) => { // Get the window that sent the event const window = BrowserWindow.fromWebContents(event.sender); diff --git a/ui/desktop/src/preload.ts b/ui/desktop/src/preload.ts index 58f1b6c5b794..654c558412fa 100644 --- a/ui/desktop/src/preload.ts +++ b/ui/desktop/src/preload.ts @@ -95,6 +95,11 @@ type ElectronAPI = { callback: (event: Electron.IpcRendererEvent, ...args: unknown[]) => void ) => void; emit: (channel: string, ...args: unknown[]) => void; + broadcastThemeChange: (themeData: { + mode: string; + useSystemTheme: boolean; + theme: string; + }) => void; // Functions for image pasting saveDataUrlToTemp: (dataUrl: string, uniqueId: string) => Promise; deleteTempFile: (filePath: string) => void; @@ -209,6 +214,9 @@ const electronAPI: ElectronAPI = { emit: (channel: string, ...args: unknown[]) => { ipcRenderer.emit(channel, ...args); }, + broadcastThemeChange: (themeData: { mode: string; useSystemTheme: boolean; theme: string }) => { + ipcRenderer.send('broadcast-theme-change', themeData); + }, saveDataUrlToTemp: (dataUrl: string, uniqueId: string): Promise => { return ipcRenderer.invoke('save-data-url-to-temp', dataUrl, uniqueId); }, diff --git a/ui/desktop/src/utils/ollamaDetection.test.ts b/ui/desktop/src/utils/ollamaDetection.test.ts index 8048b20187c0..07da6071b074 100644 --- a/ui/desktop/src/utils/ollamaDetection.test.ts +++ b/ui/desktop/src/utils/ollamaDetection.test.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* global AbortSignal, TextEncoder, Event, EventListener */ +/* global AbortSignal, TextEncoder, EventListener */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { From ceab7ab20197983416959a6360afcad2d7194168 Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:14:43 -0700 Subject: [PATCH 053/121] docs: recipe buttons (#5507) Signed-off-by: fbalicchia --- .../docs/guides/recipes/session-recipes.md | 80 ++++++++++++------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/documentation/docs/guides/recipes/session-recipes.md b/documentation/docs/guides/recipes/session-recipes.md index 1b48459a6735..714dd1c79c56 100644 --- a/documentation/docs/guides/recipes/session-recipes.md +++ b/documentation/docs/guides/recipes/session-recipes.md @@ -6,7 +6,7 @@ description: "Share a goose session setup (including tools, goals, and instructi import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -import { PanelLeft, Bot } from 'lucide-react'; +import { PanelLeft, Bot, SquarePen, Link, Calendar } from 'lucide-react'; Sometimes you finish a task in goose and realize, "Hey, this setup could be useful again." Maybe you have curated a great combination of tools, defined a clear goal, and want to preserve that flow. Or maybe you're trying to help someone else replicate what you just did without walking them through it step by step. @@ -170,17 +170,17 @@ You can turn your current goose session into a reusable recipe that includes the Use the online [Recipe Generator](https://block.github.io/goose/recipe-generator) tool to create a recipe. First choose your preferred format: - - **URL Format**: Generates a shareable link that opens a session in the Goose Desktop app - - **YAML Format**: Generates YAML content that you can save to file and then run in the Goose CLI app + - **URL Format**: Generates a shareable link that opens a session in goose Desktop + - **YAML Format**: Generates YAML content that you can save to file and then run in goose CLI Then fill out the recipe form by providing: - A **title** for the recipe - A **description** - A set of **instructions** for the recipe. - An optional initial **prompt**: - - In the Desktop app, the prompt displays in the chat box. - - In the CLI app, the prompt provides the initial message to run. Note that a prompt is required to run the recipe in headless (non-interactive) mode. - - A set of optional **activities** to display in the Desktop app. + - In the Desktop, the prompt displays in the chat box. + - In the CLI, the prompt provides the initial message to run. Note that a prompt is required to run the recipe in headless (non-interactive) mode. + - A set of optional **activities** to display in the Desktop. - YAML format only: Optional **author** contact information and **extensions** the recipe uses. @@ -190,9 +190,10 @@ You can turn your current goose session into a reusable recipe that includes the - 1. While in the session that's using the recipe, click the button at the bottom of the app - 2. Click `View/Edit Recipe` - 3. Edit any of the following: + 1. Click the button in the top-left to open the sidebar + 2. Click `Recipes` + 3. Find the recipe you want to edit and click the button + 4. In the dialog that appears, edit any of the following: - Title - Description - Instructions @@ -203,6 +204,10 @@ You can turn your current goose session into a reusable recipe that includes the - Click `Save Recipe` to [save the recipe](/docs/guides/recipes/storing-recipes) locally - Click `Create Schedule` to [schedule the recipe](#schedule-recipe) + :::tip + You can also access the edit dialog while using a recipe in a session: Just click the button at the bottom of the app and select `View/Edit Recipe`. + ::: + @@ -469,8 +474,7 @@ You can share a recipe with Desktop users via a recipe link. Copy the deeplink from your Recipe Library to share with others: 1. Click the button in the top-left to open the sidebar 2. Click `Recipes` in the sidebar - 3. Click `Preview` next to the recipe you want to share - 4. Under `Deeplink`, click `Copy` + 3. Find the recipe you want to share and click the button to copy the link @@ -481,7 +485,7 @@ You can share a recipe with Desktop users via a recipe link. -When someone clicks the link, it will open Goose Desktop with your recipe configuration. They can also use your recipe link to [import a recipe](/docs/guides/recipes/storing-recipes#importing-recipes) for future use. +When someone clicks the link, it will open goose Desktop with your recipe configuration. They can also use your recipe link to [import a recipe](/docs/guides/recipes/storing-recipes#importing-recipes) for future use. ### Share via Recipe File You can share a recipe with Desktop or CLI users by sending the recipe file directly. @@ -492,28 +496,42 @@ You can share a recipe with Desktop or CLI users by sending the recipe file dire ## Schedule Recipe -Automate Goose recipes by running them on a schedule. +Automate goose recipes by running them on a schedule. When creating a schedule, you'll configure: +- **Name**: A descriptive name for the schedule +- **Source**: The recipe to run +- **Execution mode**: Whether the recipe runs in the background (no window, results saved) or foreground (opens window if goose Desktop is running, otherwise runs in background) +- **Frequency and time**: When to run the recipe (e.g. every 20 minutes, weekly at 10 AM on Friday). Your selection is converted into a [cron expression](https://en.wikipedia.org/wiki/Cron#Cron_expression) used by goose. + +**Schedule from Recipe Library:** + + 1. Click the button in the top-left to open the sidebar + 2. Click `Recipes` + 3. Find the recipe you want to schedule and click the button + 4. Click `Create Schedule` + 5. In the dialog that appears, configure the schedule. For **Source**, your recipe link is already provided. + 6. Click `Create Schedule` + +**Schedule from Scheduler View:** 1. Click the button in the top-left to open the sidebar 2. Click `Scheduler` 3. Click `Create Schedule` - 3. In the dialog that appears: - - Provide a **name** for the schedule - - Select the **source** of your recipe. This can be either a `yaml` file or link generated by Goose Desktop. - - Select whether you want your recipe to run in the background or foreground **execution mode**. Recipes run in the background don't open a window, but the session results are saved. Recipes run in the foreground will open a window if the Goose Desktop app is running. Otherwise, the recipe runs in the background. - - Choose the **frequency** and **time** to run your recipe. Your selected frequency (e.g. every 20 minutes, weekly at 10 AM on Friday) is converted into a [cron expression](https://en.wikipedia.org/wiki/Cron#Cron_expression) used by Goose. - - Click `Create Schedule` + 4. In the dialog that appears, configure the schedule. For **Source**, select a `.yaml` or `.yml` file or provide a [recipe link](#share-recipe). + 5. Click `Create Schedule` + +**Manage Scheduled Recipes** - Your new scheduled recipe is listed in the `Scheduler` page. Click on the schedule to view details, see when it was last run, and perform actions with the scheduled recipe: - - `Run Schedule Now` to trigger the recipe manually - - `Edit Schedule` to change the scheduled frequency - - `Pause Schedule` to stop the recipe from running automatically. +Your scheduled recipes are listed in the `Scheduler` page. +Click on a schedule to view details, see when it was last run, and perform actions with the scheduled recipe: +- `Run Schedule Now` to trigger the recipe manually +- `Edit Schedule` to change the scheduled frequency +- `Pause Schedule` to stop the recipe from running automatically - At the bottom of the `Schedule Details` page you can view the list of sessions created by the scheduled recipe and open or restore each session. +At the bottom of the `Schedule Details` page you can view the list of sessions created by the scheduled recipe and open or restore each session. - Automate Goose recipes by scheduling them to run with a [cron expression](https://en.wikipedia.org/wiki/Cron#Cron_expression). + Automate goose recipes by scheduling them to run with a [cron expression](https://en.wikipedia.org/wiki/Cron#Cron_expression). ```bash # Add a new scheduled recipe which runs every day at 9 AM @@ -620,9 +638,9 @@ response: **How it works:** 1. Recipe runs normally with provided instructions -2. Goose calls a `final_output` tool with JSON matching your schema +2. goose calls a `final_output` tool with JSON matching your schema 3. Output is validated against the JSON schema -4. If validation fails, Goose receives error details and must correct the output +4. If validation fails, goose receives error details and must correct the output 5. Final validated JSON appears as the last line of output for easy extraction **Example automation usage:** @@ -635,7 +653,7 @@ echo "Issues Found: $(echo $RESULT | jq -r '.tests_failed')" ``` :::info -Structured output is supported in recipes run in both the Goose CLI and Goose Desktop. However, creating and editing the `json_schema` configuration must be done manually in the recipe file. +Structured output is supported in recipes run in both the goose CLI and goose Desktop. However, creating and editing the `json_schema` configuration must be done manually in the recipe file. ::: ## What's Included @@ -651,14 +669,14 @@ A recipe captures: - Retry logic and success validation configuration (if configured) -To protect your privacy and system integrity, Goose excludes: +To protect your privacy and system integrity, goose excludes: - Global and local memory - API keys and personal credentials -- System-level Goose settings +- System-level goose settings This means others may need to supply their own credentials or memory context if the recipe depends on those elements. ## Learn More -Check out the [Goose Recipes](/docs/guides/recipes) guide for more docs, tools, and resources to help you master Goose recipes. \ No newline at end of file +Check out the [Recipes](/docs/guides/recipes) guide for more docs, tools, and resources to help you master goose recipes. \ No newline at end of file From 5a3db4798bb065f4a848273ac2405fd5abfe05f0 Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:16:14 -0700 Subject: [PATCH 054/121] Docs/json recipe support (#5492) Signed-off-by: fbalicchia --- .../docs/guides/codebase-analysis.md | 2 +- .../docs/guides/environment-variables.md | 2 +- .../docs/guides/recipes/recipe-reference.md | 214 ++++++++++++++++-- .../docs/guides/recipes/session-recipes.md | 8 +- .../docs/guides/recipes/storing-recipes.md | 52 ++--- 5 files changed, 228 insertions(+), 50 deletions(-) diff --git a/documentation/docs/guides/codebase-analysis.md b/documentation/docs/guides/codebase-analysis.md index a2299070963c..dd896eedfa11 100644 --- a/documentation/docs/guides/codebase-analysis.md +++ b/documentation/docs/guides/codebase-analysis.md @@ -41,7 +41,7 @@ This shows that `authenticate` is a central function in your authentication flow ## Analysis Modes -The `analyze` tool operates in three modes—Structure, Semantic, and Focus—depending on whether you’re analyzing directories, files, or symbols. Invoke it through natural language or direct commands with [parameters](#parameters). +The `analyze` tool operates in three modes—Structure, Semantic, and Focus—depending on whether you’re analyzing directories, files, or symbols. Invoke it through natural language or direct commands with [parameters](#common-parameters). ### Understanding Project Organization diff --git a/documentation/docs/guides/environment-variables.md b/documentation/docs/guides/environment-variables.md index 392c90f57d89..0b19b03a45fd 100644 --- a/documentation/docs/guides/environment-variables.md +++ b/documentation/docs/guides/environment-variables.md @@ -313,7 +313,7 @@ OTLP is the standard protocol for sending telemetry collected by [OpenTelemetry] | `OTEL_EXPORTER_OTLP_TIMEOUT` | Export timeout in milliseconds | Integer (ms) | `10000` | **When to use OTLP:** -- Diagnosing slow tool execution or LLM response times when goose +- Diagnosing slow tool execution or LLM response times - Understanding intermittent failures across multiple sessions - Monitoring goose performance in production or CI/CD environments - Tracking usage patterns, costs, and resource consumption over time diff --git a/documentation/docs/guides/recipes/recipe-reference.md b/documentation/docs/guides/recipes/recipe-reference.md index d7f1bad2b0e8..f5f622cd8ea6 100644 --- a/documentation/docs/guides/recipes/recipe-reference.md +++ b/documentation/docs/guides/recipes/recipe-reference.md @@ -1,9 +1,12 @@ --- sidebar_position: 2 title: Recipe Reference Guide -description: Complete technical reference for creating and customizing recipes in goose via the CLI. +description: Complete technical reference for creating and customizing recipes in goose --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Recipes are reusable goose configurations that package up a specific setup so it can be easily shared and launched by others. ## Recipe File Format @@ -12,11 +15,7 @@ Recipes can be defined in either: - `.yaml` files (recommended) - `.json` files -Files should be named either: -- `recipe.yaml`/`recipe.json` -- `.yaml`/`.json` - -After creating recipe files, you can use the [`goose recipe` subcommands](/docs/guides/goose-cli-commands#recipe) to validate, share, and open your recipes. +See [Shareable Recipes](/docs/guides/recipes/session-recipes) to learn how to create, use, and manage recipes. ### CLI and Desktop Formats @@ -25,12 +24,18 @@ goose recipes use two formats: - **CLI Format**: Recipe fields (like `title`, `description`, `instructions`) are at the root level of the YAML/JSON file. This format is used when recipes are created via the CLI `/recipe` command and [Recipe Generator](/recipe-generator) YAML option. - **Desktop Format**: Recipe fields are nested inside a `recipe` object, with additional metadata fields at the root level. This format is used when recipes are created from goose Desktop. -The CLI automatically detects and handles both formats when running `goose run --recipe ` and `goose recipe` commands. The Desktop can [import](/docs/guides/recipes/storing-recipes#importing-recipes) and use YAML recipes (or deeplinks) in either CLI or Desktop format. +The CLI automatically detects and handles both formats for `.yaml` and `.json` recipe files when running `goose run --recipe ` and `goose recipe` commands. The Desktop can [import](/docs/guides/recipes/storing-recipes#importing-recipes) `.yaml`, `.yml`, and `.json` recipe files (or deeplinks) in either CLI or Desktop format.
Format Examples -**CLI Format:** +Recipes can be written in either YAML or JSON format. Both formats follow the same schema structure. + +### CLI Format + + + + ```yaml version: "1.0.0" title: "Code Review Assistant" @@ -40,7 +45,28 @@ prompt: "Review the code in this repository" extensions: [] ``` -**Desktop Format:** + + + +```json +{ + "version": "1.0.0", + "title": "Code Review Assistant", + "description": "Automated code review with best practices", + "instructions": "You are a code reviewer...", + "prompt": "Review the code in this repository", + "extensions": [] +} +``` + + + + +### Desktop Format + + + + ```yaml name: "Code Review Assistant" recipe: @@ -55,6 +81,29 @@ lastModified: 2025-07-02T03:46:46.778Z isArchived: false ``` + + + +```json +{ + "name": "Code Review Assistant", + "recipe": { + "version": "1.0.0", + "title": "Code Review Assistant", + "description": "Automated code review with best practices", + "instructions": "You are a code reviewer...", + "prompt": "Review the code in this repository", + "extensions": [] + }, + "isGlobal": true, + "lastModified": "2025-07-02T03:46:46.778Z", + "isArchived": false +} +``` + + + + :::note goose automatically adds metadata fields to recipes saved from the Desktop app. ::: @@ -238,6 +287,9 @@ The `extensions` field allows you to specify which Model Context Protocol (MCP) ### Example Extension Configuration + + + ```yaml extensions: - type: stdio @@ -268,6 +320,45 @@ extensions: description: "GitHub MCP extension for repository operations" ``` + + + +```json +{ + "extensions": [ + { + "type": "stdio", + "name": "codesearch", + "cmd": "uvx", + "args": ["mcp_codesearch@latest"], + "timeout": 300, + "bundled": true, + "description": "Query https://codesearch.sqprod.co/ directly from goose" + }, + { + "type": "stdio", + "name": "presidio", + "timeout": 300, + "cmd": "uvx", + "args": ["mcp_presidio@latest"], + "available_tools": ["query_logs"] + }, + { + "type": "stdio", + "name": "github-mcp", + "cmd": "github-mcp-server", + "args": [], + "env_keys": ["GITHUB_PERSONAL_ACCESS_TOKEN"], + "timeout": 60, + "description": "GitHub MCP extension for repository operations" + } + ] +} +``` + + + + ### Extension Secrets This feature is only available through the CLI. @@ -516,12 +607,15 @@ sub_recipes: ## Complete Recipe Example + + + ```yaml version: "1.0.0" title: "Example Recipe" description: "A sample recipe demonstrating the format" instructions: "Follow these steps with {{ required_param }} and {{ optional_param }}" -prompt: "Your task is to use {{ required_param }}" +prompt: "Your task is to use {{ required_param }} with {{ interactive_param }}" parameters: - key: required_param input_type: string @@ -576,9 +670,92 @@ response: description: "Additional details of steps taken" required: - result - - status + - details ``` + + + +```json +{ + "version": "1.0.0", + "title": "Example Recipe", + "description": "A sample recipe demonstrating the format", + "instructions": "Follow these steps with {{ required_param }} and {{ optional_param }}", + "prompt": "Your task is to use {{ required_param }} with {{ interactive_param }}", + "parameters": [ + { + "key": "required_param", + "input_type": "string", + "requirement": "required", + "description": "A required parameter example" + }, + { + "key": "optional_param", + "input_type": "string", + "requirement": "optional", + "default": "default value", + "description": "An optional parameter example" + }, + { + "key": "interactive_param", + "input_type": "string", + "requirement": "user_prompt", + "description": "Will prompt user if not provided" + } + ], + "extensions": [ + { + "type": "stdio", + "name": "codesearch", + "cmd": "uvx", + "args": ["mcp_codesearch@latest"], + "timeout": 300, + "bundled": true, + "description": "Query codesearch directly from goose" + } + ], + "settings": { + "goose_provider": "anthropic", + "goose_model": "claude-sonnet-4-20250514", + "temperature": 0.7 + }, + "retry": { + "max_retries": 3, + "timeout_seconds": 30, + "checks": [ + { + "type": "shell", + "command": "echo 'Task validation check passed'" + } + ], + "on_failure": "echo 'Retry attempt failed, cleaning up...'" + }, + "response": { + "json_schema": { + "type": "object", + "properties": { + "result": { + "type": "string", + "description": "The main result of the task" + }, + "details": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Additional details of steps taken" + } + }, + "required": ["result", "details"] + } + } +} +``` + + + + ## Template Inheritance Parent recipe (`parent.yaml`): @@ -614,13 +791,16 @@ Recipes can be loaded from: ## Validation Rules -The following rules are enforced when loading recipes: +Recipe files must be valid YAML or JSON. In addition, the following [validation rules](https://github.com/block/goose/blob/main/crates/goose/src/recipe/validate_recipe.rs) are enforced when loading recipes and are also checked by the [`goose recipe validate` subcommand](/docs/guides/goose-cli-commands#recipe): -1. All template variables must have corresponding parameter definitions -2. Optional parameters must have default values -3. Parameter keys must be unique -4. Recipe files must be valid YAML or JSON -5. Required fields (version, title, description) must be present +- Required `title` and `description` fields must be present +- At least one of `instructions` or `prompt` must be present +- All template variables must have corresponding parameter definitions +- Parameter keys must be unique (not enforced, but required for proper functionality) +- All defined parameters must be used in template variables (no unused parameters) +- Optional parameters must have default values +- File parameters cannot have default values (prevents importing sensitive files) +- `response.json_schema` must be a valid JSON schema if specified ## Error Handling diff --git a/documentation/docs/guides/recipes/session-recipes.md b/documentation/docs/guides/recipes/session-recipes.md index 714dd1c79c56..51f811bfd06e 100644 --- a/documentation/docs/guides/recipes/session-recipes.md +++ b/documentation/docs/guides/recipes/session-recipes.md @@ -199,9 +199,11 @@ You can turn your current goose session into a reusable recipe that includes the - Instructions - Initial prompt - Activities + - Parameters + - Response schema 4. When you're finished, you can: - Copy the recipe link to share the recipe with others - - Click `Save Recipe` to [save the recipe](/docs/guides/recipes/storing-recipes) locally + - Click `Save Recipe` to save your changes - Click `Create Schedule` to [schedule the recipe](#schedule-recipe) :::tip @@ -250,10 +252,6 @@ You can turn your current goose session into a reusable recipe that includes the 4. To run the recipe, click an activity bubble or send the prompt. - :::info Parameter Creation In Goose CLI Only - You can enter parameter values to use in a recipe, but you cannot add parameters to a recipe in Goose Desktop. Parameters can only be defined in recipes created via the CLI. - ::: - :::info Privacy & Isolation - Each person gets their own private session - No data is shared between users diff --git a/documentation/docs/guides/recipes/storing-recipes.md b/documentation/docs/guides/recipes/storing-recipes.md index e7e140cadafa..16ae9ae55cfa 100644 --- a/documentation/docs/guides/recipes/storing-recipes.md +++ b/documentation/docs/guides/recipes/storing-recipes.md @@ -8,11 +8,11 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import { PanelLeft, Bot } from 'lucide-react'; -This guide covers storing, organizing, and finding Goose recipes when you need to access them again later. +This guide covers storing, organizing, and finding goose recipes when you need to access them again later. :::info Desktop UI vs CLI -- **Goose Desktop** has a visual Recipe Library for browsing and managing saved recipes -- **Goose CLI** stores recipes as files that you find using file paths or environment variables +- **goose Desktop** has a visual Recipe Library for browsing and managing saved recipes +- **goose CLI** stores recipes as files that you find using file paths or environment variables ::: ## Understanding Recipe Storage @@ -45,15 +45,15 @@ Before saving recipes, it's important to understand where they can be stored and **Save New Recipe:** 1. To create a recipe from your chat session, see: [Create Recipe](/docs/guides/recipes/session-recipes#create-recipe) -2. Once in the Recipe Editor, click **Save Recipe** to save it to your Recipe Library +2. Once in the Recipe Editor, click `Save Recipe` to save it to your Recipe Library **Save Modified Recipe:** If you're already using a recipe and want to save a modified version: 1. Click the button with your current model at the bottom of the window -2. Click **View Recipe** +2. Click `View Recipe` 3. Make any desired edits to the description, instructions, or initial prompts -5. Click **Save Recipe** +5. Click `Save Recipe` :::info When you modify and save a recipe with a new name, a new recipe and new link are generated. You can still run the original recipe from the recipe library, or using the original link. If you edit a recipe without changing its name, the version in the recipe library is updated, but you can still run the original recipe via link. @@ -68,6 +68,10 @@ When you modify and save a recipe with a new name, a new recipe and new link are * Any path you specify: `/recipe /path/to/my-recipe.yaml` * Local project recipes: `/recipe .goose/recipes/my-recipe.yaml` + :::note + The CLI saves recipes as `.yaml` files. While the CLI can run recipes in `.json` format, it does not provide an option to save recipes as JSON. + ::: + @@ -75,29 +79,25 @@ When you modify and save a recipe with a new name, a new recipe and new link are - Import a recipe using its deeplink or YAML file: + Import a recipe using its deeplink or recipe file: - **Import via Recipe Link:** 1. Click the button in the top-left to open the sidebar 2. Click `Recipes` in the sidebar - 3. Click **Import Recipe** - 4. Under **Recipe Deeplink**, paste in the [recipe link](/docs/guides/recipes/session-recipes#share-via-recipe-link) - 5. Add a name and choose the [storage location](#recipe-storage-locations) - 6. Click **Import Recipe** + 3. Click `Import Recipe` + 4. Choose your import method: + - To import via a link: Under `Recipe Deeplink`, paste in the [recipe link](/docs/guides/recipes/session-recipes#share-via-recipe-link) + - To import via a file: Under `Recipe File`, click `Choose File`, select a recipe file, and click `Open` + 5. Click `Import Recipe` to save a copy of the recipe to your Recipe Library - **Import via Recipe File:** - 1. Click the button in the top-left to open the sidebar - 2. Click `Recipes` in the sidebar - 3. Click **Import Recipe** - 4. Under **Recipe YAML File**, click **Choose File**, select the YAML recipe file, and click `Open` - 5. Add a name and choose the [storage location](#recipe-storage-locations) - 6. Click **Import Recipe** + :::warning Recipe File Format + goose Desktop accepts `.yaml`, `.yml`, and `.json` files, but **the CLI only supports `.yaml` and `.json`**. For full compatibility across both interfaces, avoid `.yml` extensions. - Importing JSON recipe files isn't currently supported. + All recipe formats follow the same [schema structure](/docs/guides/recipes/recipe-reference#recipe-structure). + ::: - Recipe import is only available in Goose Desktop. + Recipe import is only available in goose Desktop. @@ -138,7 +138,7 @@ goose recipe list --format json **Recipe Discovery Process** -Goose searches for recipes in the following locations (in order): +goose searches for recipes in the following locations (in order): 1. **Current directory**: `.` (looks for `*.yaml` and `*.json` files) 2. **Custom paths**: Directories specified in [`GOOSE_RECIPE_PATH`](/docs/guides/environment-variables#recipe-configuration) environment variable @@ -162,7 +162,7 @@ job-finder - Find software engineering positions - local: ~/.config/goose/recipe $ goose recipe list --verbose Available recipes: goose-self-test - A comprehensive meta-testing recipe - local: ./goose-self-test.yaml - Title: Goose Self-Testing Integration Suite + Title: goose Self-Testing Integration Suite Path: ./goose-self-test.yaml hello-world - A sample recipe demonstrating basic usage - local: ~/.config/goose/recipes/hello-world.yaml Title: Hello World Recipe @@ -176,7 +176,7 @@ Available recipes: "name": "goose-self-test", "source": "Local", "path": "./goose-self-test.yaml", - "title": "Goose Self-Testing Integration Suite", + "title": "goose Self-Testing Integration Suite", "description": "A comprehensive meta-testing recipe" }, { @@ -242,10 +242,10 @@ The `goose recipe list` command is the recommended way to find recipes as it aut -Once you've located your recipe file, [run the recipe](/docs/guides/recipes/session-recipes#run-a-recipe) or [open it in goose desktop](/docs/guides/goose-cli-commands#recipe). +Once you've located your recipe file, [run the recipe](/docs/guides/recipes/session-recipes#run-a-recipe) or [open it in goose Desktop](/docs/guides/goose-cli-commands#recipe). :::tip Format Compatibility -The CLI can run recipes saved from Goose Desktop without any conversion. Both CLI-created and Desktop-saved recipes work with all recipe commands. +The CLI can run recipes saved from goose Desktop without any conversion. Both CLI-created and Desktop-saved recipes work with all recipe commands. ::: From a7d8ad4e11f75a9e06049d4beab6623df7867502 Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:16:26 -0700 Subject: [PATCH 055/121] docs: extensions directory minor updates (#5466) Signed-off-by: fbalicchia --- .../docs/mcp/{i-ching.md => i-ching-mcp.md} | 0 documentation/src/components/server-card.tsx | 2 +- documentation/src/pages/extensions/detail.tsx | 2 +- documentation/static/servers.json | 22 +++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) rename documentation/docs/mcp/{i-ching.md => i-ching-mcp.md} (100%) diff --git a/documentation/docs/mcp/i-ching.md b/documentation/docs/mcp/i-ching-mcp.md similarity index 100% rename from documentation/docs/mcp/i-ching.md rename to documentation/docs/mcp/i-ching-mcp.md diff --git a/documentation/src/components/server-card.tsx b/documentation/src/components/server-card.tsx index d7416e090281..09245f097cb5 100644 --- a/documentation/src/components/server-card.tsx +++ b/documentation/src/components/server-card.tsx @@ -80,7 +80,7 @@ export function ServerCard({ server }: { server: MCPServer }) { style={{ fontSize: "12px" }} className="text-textSubtle leading-normal" > - Can be enabled on the Extensions page in Goose + Can be enabled on the Extensions page in goose
)} diff --git a/documentation/src/pages/extensions/detail.tsx b/documentation/src/pages/extensions/detail.tsx index 3378dd4c02b5..d16e79c539d4 100644 --- a/documentation/src/pages/extensions/detail.tsx +++ b/documentation/src/pages/extensions/detail.tsx @@ -100,7 +100,7 @@ const getDocumentationPath = (serverId: string): string => {
- Can be enabled on the Extensions page in Goose + Can be enabled on the Extensions page in goose
) : server.show_install_command !== false ? ( diff --git a/documentation/static/servers.json b/documentation/static/servers.json index 44ae07233622..9b17485d730c 100644 --- a/documentation/static/servers.json +++ b/documentation/static/servers.json @@ -34,7 +34,7 @@ ] }, { - "id": "apify-mcp-server", + "id": "apify", "name": "Apify", "description": "Extract data from any website with thousands of scrapers, crawlers, and automations on Apify Store ⚡", "command": "npx -y @apify/actors-mcp-server", @@ -73,7 +73,7 @@ "description": "Automatic data visualisation via MCP-UI", "command": "", "link": "https://github.com/block/goose/tree/main/crates/goose-mcp/src/autovisualiser", - "installation_notes": "This is a built-in extension that comes with Goose and can be enabled on the Extensions page.", + "installation_notes": "This is a built-in extension that comes with goose. No installation required.", "is_builtin": true, "endorsed": true, "environmentVariables": [] @@ -168,7 +168,7 @@ "description": "Built-in computer controls for webscraping, file caching, and automations", "command": "", "link": "https://github.com/block/goose/tree/main/crates/goose-mcp/src/computercontroller", - "installation_notes": "This is a built-in extension that comes with Goose and can be enabled on the Extensions page.", + "installation_notes": "This is a built-in extension that comes with goose. No installation required.", "is_builtin": true, "endorsed": true, "environmentVariables": [] @@ -176,7 +176,7 @@ { "id": "container-use", "name": "Container Use", - "description": "Integrate container workflows with Goose using the Container-Use MCP", + "description": "Integrate container workflows with goose using the Container-Use MCP", "command": "npx -y mcp-remote https://container-use.com/mcp", "link": "https://container-use.com", "installation_notes": "Requires Node.js and Docker.", @@ -201,7 +201,7 @@ "description": "Built-in developer tools for file editing and shell command execution", "command": "", "link": "https://github.com/block/goose/tree/main/crates/goose-mcp/src/developer", - "installation_notes": "This is a built-in extension that comes with Goose by default. No installation required.", + "installation_notes": "This is a built-in extension that comes with goose and is enabled by default. No installation required.", "is_builtin": true, "endorsed": true, "environmentVariables": [] @@ -300,8 +300,8 @@ }, { "id": "goose-docs", - "name": "Goose Docs", - "description": "GitMCP for Goose documentation", + "name": "goose Docs", + "description": "GitMCP for goose documentation", "command": "npx mcp-remote https://block.gitmcp.io/goose/", "link": "https://github.com/idosal/git-mcp", "is_builtin": false, @@ -376,7 +376,7 @@ "description": "Built-in memory system for persistent context and information storage", "command": "", "link": "https://github.com/block/goose/tree/main/crates/goose-mcp/src/memory", - "installation_notes": "This is a built-in extension that comes with Goose and can be enabled on the Extensions page.", + "installation_notes": "This is a built-in extension that comes with goose. No installation required.", "is_builtin": true, "endorsed": true, "environmentVariables": [] @@ -542,7 +542,7 @@ { "id": "speech_mcp", "name": "Speech Interface", - "description": "Voice interaction with audio visualization for Goose - enables real-time voice interaction, audio/video transcription, text-to-speech conversion, and multi-speaker audio generation", + "description": "Voice interaction with audio visualization for goose - enables real-time voice interaction, audio/video transcription, text-to-speech conversion, and multi-speaker audio generation", "command": "uvx -p 3.10.14 speech-mcp@latest", "link": "https://github.com/Kvadratni/speech-mcp", "installation_notes": "Install using uvx package manager. Requires PortAudio to be installed on your system for PyAudio to capture audio from your microphone.", @@ -594,8 +594,8 @@ "name": "Tutorial", "description": "Built-in tutorial and learning management system", "command": "", - "link": "https://github.com/tutorial/tutorial-mcp", - "installation_notes": "This is a built-in extension that comes with Goose and can be enabled on the Extensions page.", + "link": "https://github.com/block/goose/tree/main/crates/goose-mcp/src/tutorial", + "installation_notes": "This is a built-in extension that comes with goose. No installation required.", "is_builtin": true, "endorsed": false, "environmentVariables": [] From f5c347714b772da535139ab2067bef75595200de Mon Sep 17 00:00:00 2001 From: Matt Yaple Date: Sat, 1 Nov 2025 12:04:23 +0000 Subject: [PATCH 056/121] fix: adds ProviderRetry to openai provider (#5518) Signed-off-by: Matt Yaple Signed-off-by: fbalicchia --- crates/goose/src/providers/openai.rs | 83 ++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/crates/goose/src/providers/openai.rs b/crates/goose/src/providers/openai.rs index 8bb9f1a9e780..dca3c0c6bdd7 100644 --- a/crates/goose/src/providers/openai.rs +++ b/crates/goose/src/providers/openai.rs @@ -16,6 +16,7 @@ use super::base::{ConfigKey, ModelInfo, Provider, ProviderMetadata, ProviderUsag use super::embedding::{EmbeddingCapable, EmbeddingRequest, EmbeddingResponse}; use super::errors::ProviderError; use super::formats::openai::{create_request, get_usage, response_to_message}; +use super::retry::ProviderRetry; use super::utils::{ get_model, handle_response_openai_compat, handle_status_openai_compat, ImageFormat, }; @@ -240,9 +241,15 @@ impl Provider for OpenAiProvider { let payload = create_request(model_config, system, messages, tools, &ImageFormat::OpenAi)?; let mut log = RequestLog::start(&self.model, &payload)?; - let json_response = self.post(&payload).await.inspect_err(|e| { - let _ = log.error(e); - })?; + let json_response = self + .with_retry(|| async { + let payload_clone = payload.clone(); + self.post(&payload_clone).await + }) + .await + .inspect_err(|e| { + let _ = log.error(e); + })?; let message = response_to_message(&json_response)?; let usage = json_response @@ -260,19 +267,30 @@ impl Provider for OpenAiProvider { async fn fetch_supported_models(&self) -> Result>, ProviderError> { let models_path = self.base_path.replace("v1/chat/completions", "v1/models"); - let response = self.api_client.response_get(&models_path).await?; - let json = handle_response_openai_compat(response).await?; - if let Some(err_obj) = json.get("error") { - let msg = err_obj - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or("unknown error"); - return Err(ProviderError::Authentication(msg.to_string())); - } + let response = self + .with_retry(|| async { + let response = self.api_client.response_get(&models_path).await?; + let json = handle_response_openai_compat(response).await?; + if let Some(err_obj) = json.get("error") { + let msg = err_obj + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or("unknown error"); + return Err(ProviderError::Authentication(msg.to_string())); + } + Ok(json) + }) + .await + .inspect_err(|e| { + tracing::warn!("Failed to fetch supported models from OpenAI: {:?}", e); + })?; - let data = json.get("data").and_then(|v| v.as_array()).ok_or_else(|| { - ProviderError::UsageError("Missing data field in JSON response".into()) - })?; + let data = response + .get("data") + .and_then(|v| v.as_array()) + .ok_or_else(|| { + ProviderError::UsageError("Missing data field in JSON response".into()) + })?; let mut models: Vec = data .iter() .filter_map(|m| m.get("id").and_then(|v| v.as_str()).map(str::to_string)) @@ -310,17 +328,24 @@ impl Provider for OpenAiProvider { let mut log = RequestLog::start(&self.model, &payload)?; let response = self - .api_client - .response_post(&self.base_path, &payload) - .await - .inspect_err(|e| { - let _ = log.error(e); - })?; - let response = handle_status_openai_compat(response) + .with_retry(|| async { + let resp = self + .api_client + .response_post(&self.base_path, &payload) + .await?; + let status = resp.status(); + if !status.is_success() { + return Err(super::utils::map_http_error_to_provider_error( + status, None, // We'll let handle_status_openai_compat parse the error + )); + } + Ok(resp) + }) .await .inspect_err(|e| { let _ = log.error(e); })?; + let response = handle_status_openai_compat(response).await?; let stream = response.bytes_stream().map_err(io::Error::other); @@ -366,8 +391,18 @@ impl EmbeddingCapable for OpenAiProvider { }; let response = self - .api_client - .api_post("v1/embeddings", &serde_json::to_value(request)?) + .with_retry(|| async { + let request_clone = EmbeddingRequest { + input: request.input.clone(), + model: request.model.clone(), + }; + let request_value = serde_json::to_value(request_clone) + .map_err(|e| ProviderError::ExecutionError(e.to_string()))?; + self.api_client + .api_post("v1/embeddings", &request_value) + .await + .map_err(|e| ProviderError::ExecutionError(e.to_string())) + }) .await?; if response.status != StatusCode::OK { From 7110637ee5baf33125b7bfeae61fee556b493b1d Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Sun, 2 Nov 2025 10:10:42 -0800 Subject: [PATCH 057/121] docs: remove speech-mcp (#5514) Signed-off-by: fbalicchia --- documentation/docs/mcp/speech-mcp.md | 3 +++ documentation/static/servers.json | 11 ----------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/documentation/docs/mcp/speech-mcp.md b/documentation/docs/mcp/speech-mcp.md index f74e364a5143..4b88487f19e4 100644 --- a/documentation/docs/mcp/speech-mcp.md +++ b/documentation/docs/mcp/speech-mcp.md @@ -1,8 +1,11 @@ --- title: Speech Extension description: Add Speech MCP Server as a Goose Extension +unlisted: true --- +Unlist per https://github.com/block/goose/issues/5431 + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import YouTubeShortEmbed from '@site/src/components/YouTubeShortEmbed'; diff --git a/documentation/static/servers.json b/documentation/static/servers.json index 9b17485d730c..f6c567dca6bb 100644 --- a/documentation/static/servers.json +++ b/documentation/static/servers.json @@ -539,17 +539,6 @@ "endorsed": false, "environmentVariables": [] }, - { - "id": "speech_mcp", - "name": "Speech Interface", - "description": "Voice interaction with audio visualization for goose - enables real-time voice interaction, audio/video transcription, text-to-speech conversion, and multi-speaker audio generation", - "command": "uvx -p 3.10.14 speech-mcp@latest", - "link": "https://github.com/Kvadratni/speech-mcp", - "installation_notes": "Install using uvx package manager. Requires PortAudio to be installed on your system for PyAudio to capture audio from your microphone.", - "is_builtin": false, - "endorsed": true, - "environmentVariables": [] - }, { "id": "square-mcp", "name": "Square", From 2f4d1e185818cc578cce919b0e6de35da1aed081 Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Sun, 2 Nov 2025 13:19:31 -0600 Subject: [PATCH 058/121] fix link to Ollama FAQ (#5531) Signed-off-by: fbalicchia --- documentation/blog/2025-03-31-goose-benchmark/index.md | 2 +- documentation/docs/getting-started/providers.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/blog/2025-03-31-goose-benchmark/index.md b/documentation/blog/2025-03-31-goose-benchmark/index.md index 2e30c4ba6a6e..0378619712bd 100644 --- a/documentation/blog/2025-03-31-goose-benchmark/index.md +++ b/documentation/blog/2025-03-31-goose-benchmark/index.md @@ -23,7 +23,7 @@ These community evals aren't the rigorous, peer-reviewed benchmarks that researc In this spirit, we're introducing our **Goose Vibe Check** leaderboard. -Thank you to the Ollama team for their help and support in our experimentation contributing to this blog! We used Ollama’s [structured outputs](https://ollama.com/blog/structured-outputs) feature to enable our [toolshim implementation](https://block.github.io/goose/docs/experimental/ollama) (more below) and their recently released [context length parameter override](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size) to enable testing on longer contexts. +Thank you to the Ollama team for their help and support in our experimentation contributing to this blog! We used Ollama’s [structured outputs](https://ollama.com/blog/structured-outputs) feature to enable our [toolshim implementation](https://block.github.io/goose/docs/experimental/ollama) (more below) and their recently released [context length parameter override](https://github.com/ollama/ollama/blob/main/docs/faq.mdx#how-can-i-specify-the-context-window-size) to enable testing on longer contexts. ## Leaderboard diff --git a/documentation/docs/getting-started/providers.md b/documentation/docs/getting-started/providers.md index 05bbc01896e6..5f3378dd4d91 100644 --- a/documentation/docs/getting-started/providers.md +++ b/documentation/docs/getting-started/providers.md @@ -668,7 +668,7 @@ Here are some local providers we support: ``` :::tip Context Length - If you notice that goose is having trouble using extensions or is ignoring [.goosehints](/docs/guides/using-goosehints), it is likely that the model's default context length of 4096 tokens is too low. Set the `OLLAMA_CONTEXT_LENGTH` environment variable to a [higher value](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-specify-the-context-window-size). + If you notice that goose is having trouble using extensions or is ignoring [.goosehints](/docs/guides/using-goosehints), it is likely that the model's default context length of 4096 tokens is too low. Set the `OLLAMA_CONTEXT_LENGTH` environment variable to a [higher value](https://github.com/ollama/ollama/blob/main/docs/faq.mdx#how-can-i-specify-the-context-window-size). ::: From 90babcefc18382b67defbfcbd78f76a4c642bffd Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Sun, 2 Nov 2025 14:19:47 -0500 Subject: [PATCH 059/121] Troubleshooting diagnostics doc (#5526) Signed-off-by: fbalicchia --- CONTRIBUTING.md | 46 +----- README.md | 19 +-- .../docs/getting-started/installation.md | 2 +- .../docs/getting-started/using-extensions.md | 4 +- .../docs/guides/goose-cli-commands.md | 39 +++++ .../security/prompt-injection-detection.md | 2 +- .../guides/sessions/session-management.md | 2 +- documentation/docs/guides/tips.md | 2 +- .../docs/troubleshooting/_category_.json | 5 + .../diagnostics-and-reporting.md | 149 ++++++++++++++++++ documentation/docs/troubleshooting/index.mdx | 50 ++++++ .../known-issues.md} | 24 +-- 12 files changed, 268 insertions(+), 76 deletions(-) create mode 100644 documentation/docs/troubleshooting/_category_.json create mode 100644 documentation/docs/troubleshooting/diagnostics-and-reporting.md create mode 100644 documentation/docs/troubleshooting/index.mdx rename documentation/docs/{troubleshooting.md => troubleshooting/known-issues.md} (95%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3def3d362790..bf2074baadb0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,23 +9,7 @@ We welcome pull requests for general contributions! If you have a larger new fea --- -## 🎉 Hacktoberfest 2025 🎉 - -`goose` is a participating in Hacktoberfest 2025! We’re so excited for your contributions, and have created a wide variety of issues so that anyone can contribute. Whether you're a seasoned developer or a first-time open source contributor, there's something for everyone. - -### Here's how you can get started: - -1. Read the [code of conduct](https://github.com/block/.github/blob/main/CODE_OF_CONDUCT.md). -2. Skim the quick AI contribution tips below (and see the [full Responsible AI-Assisted Coding Guide](./ai-assisted-coding-guide.md) for details). -3. Choose a task from this project's Hacktoberfest issues in our [Project Hub](https://github.com/block/goose/issues/4705). Each issue has the 🏷️ `hacktoberfest` label. -4. Comment ".take" on the corresponding issue to get assigned the task. -5. Fork the repository and create a new branch for your work. -6. Make your changes and submit a pull request. -7. Wait for review and address any feedback. - ---- - -### 🤖 Quick Responsible AI Tips +## 🤖 Quick Responsible AI Tips If you use Goose, Copilot, Claude, or other AI tools to help with your PRs: @@ -55,34 +39,6 @@ If you use Goose, Copilot, Claude, or other AI tools to help with your PRs: --- -### 🏆 Leaderboard & Prizes - -Every hacktoberfest PR and contribution will earn you points on our [leaderboard](https://github.com/block/goose/issues/4775). Those who end up in the top 20 participants with the most points by the end of October will earn exclusive swag and LLM credits! As you have issues merged, here is a brief explanation on how our automatic points system works. - -#### Point System - -| Weight | Points Awarded | Description | -|---------|-------------|-------------| -| 🐭 **Small** | 5 points | For smaller tasks that take limited time to complete and/or don't require any product knowledge. | -| 🐰 **Medium** | 10 points | For average tasks that take additional time to complete and/or require some product knowledge. | -| 🐂 **Large** | 15 points | For heavy tasks that takes lots of time to complete and/or possibly require deep product knowledge. | - -#### Prizes You Can Win - -- **Top 5**: $100 gift card to our [brand new goose swag shop](https://www.gooseswag.xyz/) and $100 of LLM credits! -- **Top 6-10**: $50 gift cards for goose swag shop and $50 of LLM credits! -- **Top 11-20**: $25 of LLM credits! - -Keep an eye on your progress via our [Leaderboard](https://github.com/block/goose/issues/4775). - -### 👩‍ Need help? - -Need help or have questions? Feel free to reach out by connecting with us in our [Discord community](https://discord.gg/goose-oss) to get direct help from our team in the `#hacktoberfest` project channel. - -Happy contributing! - ---- - ## Prerequisites goose includes rust binaries alongside an electron app for the GUI. To work diff --git a/README.md b/README.md index db7b7f55dd14..df5c911c338c 100644 --- a/README.md +++ b/README.md @@ -17,20 +17,6 @@ _a local, extensible, open source AI agent that automates engineering tasks_

-## 🎉 Hacktoberfest 2025 🎉 - -`goose` is a participating project in Hacktoberfest 2025! We’re so excited for your contributions, and have created a wide variety of issues so that anyone can contribute. Whether you're a seasoned developer or a first-time open source contributor, there's something for everyone. - -### To get started: -1. Read the [contributing guide](https://github.com/block/goose/blob/main/CONTRIBUTING.md). -2. Read the [code of conduct](https://github.com/block/.github/blob/main/CODE_OF_CONDUCT.md). -3. Read the [full Responsible AI-Assisted Coding Guide](./ai-assisted-coding-guide.md). -4. Choose a task from this project's Hacktoberfest issues in our [Project Hub](https://github.com/block/goose/issues/4705) and follow the instructions. Each issue has the 🏷️ `hacktoberfest` label. - -Have questions? Connecting with us in our [Discord community](https://discord.gg/goose-oss) in the `#hacktoberfest` project channel. - ---- - goose is your on-machine AI agent, capable of automating complex development tasks from start to finish. More than just code suggestions, goose can build entire projects from scratch, write and execute code, debug failures, orchestrate workflows, and interact with external APIs - _autonomously_. Whether you're prototyping an idea, refining existing code, or managing intricate engineering pipelines, goose adapts to your workflow and executes tasks with precision. @@ -44,8 +30,13 @@ Designed for maximum flexibility, goose works with any LLM and supports multi-mo - [Installation](https://block.github.io/goose/docs/getting-started/installation) - [Tutorials](https://block.github.io/goose/docs/category/tutorials) - [Documentation](https://block.github.io/goose/docs/category/getting-started) +- [Responsible AI-Assisted Coding Guide](https://github.com/block/goose/blob/main/ai-assisted-coding-guide.md) - [Governance](https://github.com/block/goose/blob/main/GOVERNANCE.md) +## Need Help? +- [Diagnostics & Reporting](https://block.github.io/goose/docs/troubleshooting/diagnostics-and-reporting) +- [Known Issues](https://block.github.io/goose/docs/troubleshooting/known-issues) + # a little goose humor 🦢 > Why did the developer choose goose as their AI agent? diff --git a/documentation/docs/getting-started/installation.md b/documentation/docs/getting-started/installation.md index 93392be7a137..0b521acacff5 100644 --- a/documentation/docs/getting-started/installation.md +++ b/documentation/docs/getting-started/installation.md @@ -44,7 +44,7 @@ import { PanelLeft } from 'lucide-react'; Ensure the `~/.config` directory has read and write access. - Goose needs this access to create the log directory and file. Once permissions are granted, the app should load correctly. For steps on how to do this, refer to the [Troubleshooting Guide](/docs/troubleshooting.md#macos-permission-issues) + Goose needs this access to create the log directory and file. Once permissions are granted, the app should load correctly. For steps on how to do this, refer to the [Known Issues Guide](/docs/troubleshooting/known-issues#macos-permission-issues) ::: diff --git a/documentation/docs/getting-started/using-extensions.md b/documentation/docs/getting-started/using-extensions.md index 763f6193f138..3606498446cc 100644 --- a/documentation/docs/getting-started/using-extensions.md +++ b/documentation/docs/getting-started/using-extensions.md @@ -12,7 +12,7 @@ Extensions are add-ons that provide a way to extend the functionality of Goose b Extensions are based on the [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol), so you can connect Goose to a wide ecosystem of capabilities. -Goose automatically checks external extensions for known malware before activation. If a malicious package is detected, the [extension will be blocked](/docs/troubleshooting#malicious-package-detected) with a clear error message. +Goose automatically checks external extensions for known malware before activation. If a malicious package is detected, the [extension will be blocked](/docs/troubleshooting/known-issues#malicious-package-detected) with a clear error message. :::tip Tutorials Check out the [step-by-step tutorials](/docs/category/mcp-servers) for adding and using several Goose Extensions @@ -108,7 +108,7 @@ You can also add any other [MCP Server](#mcp-servers) as a Goose extension, even Extensions can be installed directly via the [extensions directory][extensions-directory], CLI, or UI. :::warning Airgapped Environments -If you're in a corporate or airgapped environment and extensions fail to activate, see [Airgapped/Offline Environments](/docs/troubleshooting#airgappedoffline-environment-issues) for workarounds. +If you're in a corporate or airgapped environment and extensions fail to activate, see [Airgapped/Offline Environments](/docs/troubleshooting/known-issues#airgappedoffline-environment-issues) for workarounds. ::: ### MCP Servers diff --git a/documentation/docs/guides/goose-cli-commands.md b/documentation/docs/guides/goose-cli-commands.md index e137fdc99b05..f1d28e03eea2 100644 --- a/documentation/docs/guides/goose-cli-commands.md +++ b/documentation/docs/guides/goose-cli-commands.md @@ -207,6 +207,45 @@ goose session export --path ./my-session.jsonl --output exported.md --- +#### session diagnostics [options] +Generate a comprehensive diagnostics bundle for troubleshooting issues with a specific session. + +**Options:** +- **`-i, --id `**: Generate diagnostics for a specific session by ID +- **`-n, --name `**: Generate diagnostics for a specific session by name +- **`-o, --output `**: Save diagnostics bundle to a specific file path (default: `diagnostics_{session_id}.zip`) + +**What's included:** +- **System Information**: App version, operating system, architecture, and timestamp +- **Session Data**: Complete conversation messages and history for the specified session +- **Configuration Files**: Your [configuration files](/docs/guides/config-files) (if they exist) +- **Log Files**: Recent application logs for debugging + +**Usage:** +```bash +# Generate diagnostics for a specific session by ID +goose session diagnostics --id 20250305_113223 + +# Generate diagnostics for a session by name +goose session diagnostics --name my-project-session + +# Save diagnostics to a custom location +goose session diagnostics --id 20250305_113223 --output /path/to/my-diagnostics.zip + +# Interactive selection (prompts you to choose a session) +goose session diagnostics +``` + +:::warning Privacy Notice +Diagnostics bundles contain your session messages and system information. If your session includes sensitive data (API keys, personal information, proprietary code), review the contents before sharing publicly. +::: + +:::tip +Generate diagnostics before reporting bugs to provide technical details that help with faster resolution. The ZIP file can be attached to GitHub issues or shared with support. +::: + +--- + ### Task Execution #### run [options] diff --git a/documentation/docs/guides/security/prompt-injection-detection.md b/documentation/docs/guides/security/prompt-injection-detection.md index 9d82f57887a5..35d565cd530a 100644 --- a/documentation/docs/guides/security/prompt-injection-detection.md +++ b/documentation/docs/guides/security/prompt-injection-detection.md @@ -78,7 +78,7 @@ When in doubt, deny. Beyond prompt injection detection, goose automatically: - Warns you before running new or updated recipes - Warns you when importing recipes that contain invisible Unicode Tag Block characters -- [Checks for known malware](/docs/troubleshooting#malicious-package-detected) when installing extensions for locally-run MCP servers +- [Checks for known malware](/docs/troubleshooting/known-issues#malicious-package-detected) when installing extensions for locally-run MCP servers ::: ### Configuring Detection Threshold diff --git a/documentation/docs/guides/sessions/session-management.md b/documentation/docs/guides/sessions/session-management.md index a2bd8cffea27..1e261d0e12b3 100644 --- a/documentation/docs/guides/sessions/session-management.md +++ b/documentation/docs/guides/sessions/session-management.md @@ -263,7 +263,7 @@ Search allows you to find specific content within sessions or find specific sess ``` :::tip - While you can resume sessions using the commands above, we recommend creating new sessions for new tasks to reduce the chance of [doom spiraling](/docs/troubleshooting#stuck-in-a-loop-or-unresponsive). + While you can resume sessions using the commands above, we recommend creating new sessions for new tasks to reduce the chance of [doom spiraling](/docs/troubleshooting/known-issues#stuck-in-a-loop-or-unresponsive). ::: diff --git a/documentation/docs/guides/tips.md b/documentation/docs/guides/tips.md index 22622f05291e..7b1b29c0a5a4 100644 --- a/documentation/docs/guides/tips.md +++ b/documentation/docs/guides/tips.md @@ -54,4 +54,4 @@ Use [lead/worker model](/docs/tutorials/lead-worker/) to have goose use a "lead" Write [recipes](/docs/guides/recipes/session-recipes) that check your current state before acting, so they can be run multiple times without causing any errors or duplication. ### Add Logging to Recipes -Inlcude informative log messages in your recipes for each major step to make debugging and troubleshooting easier should something fail. +Include informative log messages in your recipes for each major step to make debugging and troubleshooting easier should something fail. diff --git a/documentation/docs/troubleshooting/_category_.json b/documentation/docs/troubleshooting/_category_.json new file mode 100644 index 000000000000..3b23b8df446d --- /dev/null +++ b/documentation/docs/troubleshooting/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Troubleshooting", + "position": 40, + "description": "Get help, report issues, and troubleshoot common problems with goose." +} diff --git a/documentation/docs/troubleshooting/diagnostics-and-reporting.md b/documentation/docs/troubleshooting/diagnostics-and-reporting.md new file mode 100644 index 000000000000..5b36565d90fd --- /dev/null +++ b/documentation/docs/troubleshooting/diagnostics-and-reporting.md @@ -0,0 +1,149 @@ +--- +title: Diagnostics and Reporting +sidebar_label: Diagnostics and Reporting +description: Use built-in diagnostics, report bugs, and request new features with goose's integrated support tools. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import { PanelLeft, Bug, MessageSquarePlus, Download } from 'lucide-react'; + +goose provides several built-in features to help you get support, report issues, and request new functionality. This guide covers the diagnostics system, bug reporting, and feature request tools. + +| Feature | Purpose | Location | Output | +|---------|---------|----------|---------| +| **Diagnostics** | Generate troubleshooting data | Chat input toolbar | ZIP file with system info, logs, and session data | +| **Report a Bug** | Submit bug reports | Settings → Help & feedback | Opens GitHub issue template | +| **Request a Feature** | Suggest new features | Settings → Help & feedback | Opens GitHub issue template | + +## Diagnostics System + +The diagnostics feature creates a comprehensive troubleshooting bundle that includes system information, session data, configuration files, and recent logs. This is invaluable for debugging issues or getting technical support. + +### Generating Diagnostics + + + + 1. In an active chat session, look for the icon in the bottom toolbar + 2. Click the diagnostics button + 3. Review the information in the modal about what data will be collected + 4. Click `Download` to generate and save the diagnostics bundle + 5. The ZIP file will be saved as `diagnostics_{session_id}.zip` + + :::tip + The diagnostics button is only available when you have an active session, as it needs a session ID to generate the bundle. + ::: + + + Use the session diagnostics command to generate a troubleshooting bundle. For complete details and all available options, see the [CLI Commands guide](/docs/guides/goose-cli-commands#session-diagnostics-options). + + ```sh + # Generate diagnostics for a specific session + goose session diagnostics --id + + # Interactive selection (prompts you to choose a session) + goose session diagnostics + + # Save to a custom location + goose session diagnostics --id --output /path/to/diagnostics.zip + ``` + + To find your session ID, first list available sessions: + + ```sh + goose session list + ``` + + Example output: + ``` + Available sessions: + abc123def - My coding session - 2024-01-15 14:30:22 + xyz789ghi - Documentation work - 2024-01-15 10:15:45 + ``` + + + +### Using Diagnostics Data + +The diagnostics ZIP file contains several folders: + +``` +diagnostics_abc123def.zip +├── logs/ +│ ├── goose-2024-01-15.jsonl +│ ├── goose-2024-01-14.jsonl +│ └── ... +├── session.json # Your session messages +├── config.yaml # Configuration files (if they exist) +└── system.txt # System information +``` + +**When to generate diagnostics:** +- Experiencing crashes or unexpected behavior +- Getting error messages you don't understand +- Performance issues or slow responses +- Before reporting bugs to include technical details + +**What's included in diagnostics:** +- **System Information**: App version, operating system, architecture, and timestamp +- **Session Data**: Your current conversation messages and history +- **Configuration Files**: Your [configuration files](/docs/guides/config-files) (if they exist) +- **Log Files**: Recent application logs for debugging + +:::warning Privacy Notice +Diagnostics bundles contain your session messages and system information. If your session includes sensitive data (API keys, personal information, proprietary code), review the contents before sharing publicly. +::: + +## Bug Reports + +The bug report feature opens a structured GitHub issue template to help you provide all necessary information for effective bug reporting. + +### Creating Bug Reports + + + + 1. Click the button in the top-left to open the sidebar + 2. Click `Settings` in the sidebar + 3. Scroll down to the `Help & feedback` section + 4. Click `Report a Bug` + 5. This opens GitHub in your browser with a pre-filled bug report template + + + For CLI users, navigate directly to the GitHub repository: + + ``` + https://github.com/block/goose/issues/new?template=bug_report.md + ``` + + + +## Feature Requests + +The feature request system helps you suggest improvements and new functionality for goose. + +### Submitting Feature Requests + + + + 1. Click the button in the top-left to open the sidebar + 2. Click `Settings` in the sidebar + 3. Scroll down to the `Help & feedback` section + 4. Click `Request a Feature` + 5. This opens GitHub in your browser with a feature request template + + + Navigate directly to the GitHub repository: + + ``` + https://github.com/block/goose/issues/new?template=feature_request.md + ``` + + + +## Additional Debugging + +For issues not resolved by diagnostics: + +- **[Session and System Logs](/docs/guides/logs)**: View detailed logs for debugging individual sessions +- **[Telemetry Export](/docs/guides/environment-variables#observability)**: Configure telemetry for performance analysis and production monitoring + diff --git a/documentation/docs/troubleshooting/index.mdx b/documentation/docs/troubleshooting/index.mdx new file mode 100644 index 000000000000..533defbe3275 --- /dev/null +++ b/documentation/docs/troubleshooting/index.mdx @@ -0,0 +1,50 @@ +--- +title: Troubleshooting +hide_title: true +description: Get help, report issues, and troubleshoot common problems with goose. +--- + +import Card from '@site/src/components/Card'; +import styles from '@site/src/components/Card/styles.module.css'; + +

Troubleshooting

+

+ Get help when you need it, report bugs, request features, and find solutions to common issues. goose provides built-in diagnostics and direct links to our support channels. +

+ +
+

🛠️ Getting Help

+
+ + + +
+
+ +
+

💬 Community Support

+
+ + +
+
diff --git a/documentation/docs/troubleshooting.md b/documentation/docs/troubleshooting/known-issues.md similarity index 95% rename from documentation/docs/troubleshooting.md rename to documentation/docs/troubleshooting/known-issues.md index 65452b810c7b..8bb34e0370d1 100644 --- a/documentation/docs/troubleshooting.md +++ b/documentation/docs/troubleshooting/known-issues.md @@ -1,11 +1,15 @@ --- -title: Troubleshooting +title: Known Issues +sidebar_label: Known Issues +description: Comprehensive troubleshooting guide for common goose problems with step-by-step solutions. --- -# Troubleshooting - goose, like any system, may run into occasional issues. This guide provides solutions for common problems. +:::tip Need help with an issue not listed here? +Our [Discord community](https://discord.gg/goose-oss) is here to help! For the fastest support, consider generating a [diagnostic report](/docs/troubleshooting/diagnostics-and-reporting) - it helps us understand your setup quickly. +::: + ### goose Edits Files goose can and will edit files as part of its workflow. To avoid losing personal changes, use version control to stage your personal edits. Leave goose edits unstaged until reviewed. Consider separate commits for goose's edits so you can easily revert them if needed. @@ -38,14 +42,7 @@ You can prevent these issues by customizing your shell to handle these commands --- -### Debugging and Diagnostics - -To help with troubleshooting issues, you can: - -- View [session and system logs](/docs/guides/logs) for debugging individual sessions -- Configure [telemetry export](/docs/guides/environment-variables#observability) for performance analysis, trend monitoring, or production/CI debugging ---- ### Context Length Exceeded Error @@ -466,7 +463,12 @@ goose Desktop uses **"shims"** (packaged versions of `npx` and `uvx`) that autom --- ### Need Further Help? -If you have questions, run into issues, or just need to brainstorm ideas join the [Discord Community][discord]! + +Still running into issues? We're here to help! Join our [Discord Community][discord] where the goose team and community members are happy to assist. + +:::tip +If you can share a [diagnostic report](/docs/troubleshooting/diagnostics-and-reporting#diagnostics-system) along with your question, it helps us understand your setup and provide more targeted solutions. +::: From dd8f094c762dad628a9a05e1edcc888107df4f21 Mon Sep 17 00:00:00 2001 From: Paul Silvis Date: Sun, 2 Nov 2025 11:49:36 -0800 Subject: [PATCH 060/121] Fixes Gemini API parse issue by converting nullable type arrays to single types in tool schemas (#5530) Signed-off-by: Paul Silvis Signed-off-by: fbalicchia --- crates/goose/src/providers/formats/google.rs | 34 +++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/providers/formats/google.rs b/crates/goose/src/providers/formats/google.rs index 7fd1dd075197..786762328b15 100644 --- a/crates/goose/src/providers/formats/google.rs +++ b/crates/goose/src/providers/formats/google.rs @@ -238,7 +238,7 @@ pub fn process_map(map: &Map, parent_key: Option<&str>) -> Value value.clone() } } - _ => value.clone(), + _ => process_value(value, Some(key.as_str())), }; Some((key.clone(), processed_value)) @@ -858,4 +858,36 @@ mod tests { assert_eq!(payload, expected_payload); } + + #[test] + fn test_tools_with_nullable_types_converted_to_single_type() { + // Test that type arrays like ["string", "null"] are converted to single types + let params = object!({ + "properties": { + "nullable_field": { + "type": ["string", "null"], + "description": "A nullable string field" + }, + "regular_field": { + "type": "number", + "description": "A regular number field" + } + } + }); + let tools = vec![Tool::new("test_tool", "test description", params)]; + let result = format_tools(&tools); + + assert_eq!(result.len(), 1); + assert_eq!(result[0]["name"], "test_tool"); + + // Verify that the type array was converted to a single string type + let nullable_field = &result[0]["parameters"]["properties"]["nullable_field"]; + assert_eq!(nullable_field["type"], "string"); + assert_eq!(nullable_field["description"], "A nullable string field"); + + // Verify that regular types are unchanged + let regular_field = &result[0]["parameters"]["properties"]["regular_field"]; + assert_eq!(regular_field["type"], "number"); + assert_eq!(regular_field["description"], "A regular number field"); + } } From d42c605fd83069ea04cdd71ac14b79bac7eefd8d Mon Sep 17 00:00:00 2001 From: Viet Bui <48315468+vietbui1999ru@users.noreply.github.com> Date: Mon, 3 Nov 2025 03:00:37 -0500 Subject: [PATCH 061/121] added configuration content, also added signoff, fix merging issue with another commit by creating a clean branch. removed and closed commits that caused signoff issues. (#5519) Signed-off-by: vietbui99 Signed-off-by: fbalicchia --- .../community/data/community-content.json | 94 +++++++++++++++---- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/documentation/src/pages/community/data/community-content.json b/documentation/src/pages/community/data/community-content.json index 691a63d3a9fe..61d516226c00 100644 --- a/documentation/src/pages/community/data/community-content.json +++ b/documentation/src/pages/community/data/community-content.json @@ -15,7 +15,10 @@ "url": "https://block.github.io/goose/blog/2025/09/26/hacktoberfest-2025", "thumbnail": "https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-09-26", - "tags": ["hacktoberfest", "open-source"], + "tags": [ + "hacktoberfest", + "open-source" + ], "hacktoberfest": true }, { @@ -28,7 +31,9 @@ "url": "https://dev.to/agasta/running-goose-in-containers-without-losing-your-mind-3m8", "thumbnail": "https://images.unsplash.com/photo-1759560397953-8221761119ec?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-10-04", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -40,7 +45,9 @@ "type": "video", "url": "https://www.youtube.com/shorts/Qidl20e-HOc", "submittedDate": "2025-10-13", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -52,7 +59,10 @@ "type": "blog", "url": "https://anudhyan.hashnode.dev/best-practices-for-using-goose-in-enterprise-environments", "submittedDate": "2025-10-15", - "tags": ["hacktoberfest", "enterprise"], + "tags": [ + "hacktoberfest", + "enterprise" + ], "hacktoberfest": true }, { @@ -65,7 +75,9 @@ "url": "https://dev.to/lymah/getting-started-with-goose-on-windows-30bh", "thumbnail": "https://i.imgur.com/WEZXcBD.png", "submittedDate": "2025-10-14", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -78,7 +90,9 @@ "url": "https://dev.to/lymah/best-practices-for-prompt-engineering-with-goose-3m6h", "thumbnail": "https://i.imgur.com/Shsi56O.png", "submittedDate": "2025-10-16", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -91,7 +105,9 @@ "url": "https://dev.to/lymah/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl", "thumbnail": "https://i.imgur.com/uim8eHi.png", "submittedDate": "2025-10-21", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -104,7 +120,9 @@ "url": "https://dev.to/lymah/configuring-goose-for-team-environments-and-shared-workflows-5ehn", "thumbnail": "https://i.imgur.com/pltI1bv.jpeg", "submittedDate": "2025-10-26", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -116,7 +134,9 @@ "type": "blog", "url": "https://goose123.hashnode.dev/adopting-goose-in-the-enterprise-a-guide-to-security-scalability-and-governance", "submittedDate": "2025-10-26", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -129,7 +149,9 @@ "url": "https://medium.com/@shreyanshrewa/creating-and-sharing-effective-goose-recipes-abf9767d5128", "thumbnail": "https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=400&h=225&fit=crop&crop=entropy&auto=format", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -141,7 +163,9 @@ "type": "video", "url": "https://www.youtube.com/shorts/EmLcx5gKHsE", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -153,7 +177,9 @@ "type": "blog", "url": "https://anudhyan.hashnode.dev/stop-chasing-stale-docs-creating-automated-documentation-workflows-with-goose", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -166,7 +192,9 @@ "url": "https://dev.to/lymah/building-effective-prompts-and-workflows-for-code-review-with-goose-51m1", "thumbnail": "https://i.imgur.com/2cRXct5.png", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -179,7 +207,9 @@ "url": "https://dev.to/mohammed_thaha/boosting-goose-performance-on-windows-real-benchmarks-power-tweaks-and-results-54gf", "thumbnail": "https://media2.dev.to/dynamic/image/width=400,height=225,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxdtne8rxn4l2nctajv1.png", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -191,7 +221,9 @@ "type": "video", "url": "https://www.youtube.com/shorts/IxUPo2QDg_8", "submittedDate": "2025-10-29", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -203,7 +235,9 @@ "type": "video", "url": "https://www.youtube.com/shorts/xBGTa8XenVc", "submittedDate": "2025-10-30", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -215,7 +249,9 @@ "type": "video", "url": "https://youtube.com/shorts/XhA2YqjNF7M", "submittedDate": "2025-10-30", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true }, { @@ -227,7 +263,10 @@ "type": "blog", "url": "https://anudhyan.hashnode.dev/building-custom-tools-and-extensions-for-goose-a-developers-guide", "submittedDate": "2025-10-30", - "tags": ["hacktoberfest", "mcp"], + "tags": [ + "hacktoberfest", + "mcp" + ], "hacktoberfest": true }, { @@ -240,7 +279,24 @@ "url": "https://dev.to/lymah/managing-goose-configurations-across-multiple-projects-58i3", "thumbnail": "https://i.imgur.com/VvM8sMR.png", "submittedDate": "2025-10-30", - "tags": ["hacktoberfest"], + "tags": [ + "hacktoberfest" + ], + "hacktoberfest": true + }, + { + "title": "Managing Goose Configurations Across Multiple Projects: A Practical Guide", + "author": { + "name": "Viet Bui", + "handle": "vietbui1999ru" + }, + "type": "blog", + "url": "https://dev.to/vietbui1999ru/managing-goose-configurations-across-multiple-projects-a-practical-guide-48ei", + "thumbnail": "https://imgur.com/a/ubyYbVJ", + "submittedDate": "2025-10-31", + "tags": [ + "hacktoberfest" + ], "hacktoberfest": true } ] From 191c2cae6bd609075ac9f7c97a0972a2f91e32b8 Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Mon, 3 Nov 2025 02:25:51 -0600 Subject: [PATCH 062/121] docs: adding HOWTOAI.md (#5533) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: fbalicchia --- CONTRIBUTING.md | 2 +- HOWTOAI.md | 317 ++++++++++++++++++ ai-assisted-coding-guide.md | 91 ----- .../2025-09-26-hacktoberfest-2025/index.md | 2 +- 4 files changed, 319 insertions(+), 93 deletions(-) create mode 100644 HOWTOAI.md delete mode 100644 ai-assisted-coding-guide.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf2074baadb0..7ec7a08c8268 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ If you use Goose, Copilot, Claude, or other AI tools to help with your PRs: - Document your changes - Ask for review if security or core code is involved -👉 Full guide here: [Responsible AI-Assisted Coding Guide](./ai-assisted-coding-guide.md) +👉 Full guide here: [Responsible AI-Assisted Coding Guide](./HOWTOAI.md) --- diff --git a/HOWTOAI.md b/HOWTOAI.md new file mode 100644 index 000000000000..32efe2cb71d1 --- /dev/null +++ b/HOWTOAI.md @@ -0,0 +1,317 @@ +# How to Use AI with goose +_A practical guide for contributing to goose using AI coding assistants_ + +goose benefits from thoughtful AI-assisted development, but contributors must maintain high standards for code quality, security, and collaboration. Whether you use goose itself, GitHub Copilot, Cursor, Claude, or other AI tools, this guide will help you contribute effectively. + +--- + +## Core Principles + +- **Human Oversight**: You are accountable for all code you submit. Never commit code you don’t understand or can’t maintain. +- **Quality Standards**: AI code must meet the same standards as human written code—tests, docs, and patterns included. +- **Transparency**: Be open about significant AI usage in PRs and explain how you validated it. + +--- + +## Best Practices + +**✅ Recommended Uses** + +- Generating boilerplate code and common patterns +- Creating comprehensive test suites +- Writing documentation and comments +- Refactoring existing code for clarity +- Generating utility functions and helpers +- Explaining existing code patterns + +**❌ Avoid AI For** + +- Complex business logic without thorough review +- Security critical authentication/authorization code +- Code you don’t fully understand +- Large architectural changes +- Database migrations or schema changes + +**Workflow Tips** + +- Start small and validate often. Build, lint, and test incrementally +- Study existing patterns before generating new code +- Always ask: "Is this secure? Does it follow project patterns? What edge cases need testing?" + +**Security Considerations** + +- Extra review required for MCP servers, network code, file system ops, user input, and credential handling +- Never expose secrets in prompts +- Sanitize inputs/outputs and follow goose’s security patterns + +--- + +## Testing & Review + +Before submitting AI assisted code, confirm that: +- You understand every line +- All tests pass locally (happy path + error cases) +- Docs are updated and accurate +- Code follows existing patterns + +**Always get human review** for: + +- Security sensitive code +- Core architecture changes +- Async/concurrency logic +- MCP protocol implementations +- Large refactors or anything you’re unsure about + +--- + +## Using goose for goose development + +- Protect sensitive files with `.gooseignore` (e.g., `.env*`, `*.key`, `target/`, `.git/`) +- Guide goose with `.goosehints` (patterns, error handling, formatting, tests, docs) +- Use `/plan` to structure work, and choose modes wisely: + - **Chat** for understanding + - **Smart Approval** for most dev work + - **Approval** for critical areas + - **Autonomous** only with safety nets + +--- + +## Community & Collaboration + +- In PRs, note significant AI use and how you validated results +- Share prompting tips, patterns, and pitfalls +- Be responsive to feedback and help improve this guide + +--- + +## Remember + +AI is a powerful assistant, not a replacement for your judgment. Use it to speed up development; while keeping your brain engaged, your standards high, and goose secure. + +Questions? Join our [Discord](https://discord.gg/goose-oss) or [GitHub Discussions](https://github.com/block/goose/discussions) to talk more about responsible AI development. + +--- + +## Getting Started with AI Tools + +### Quick Setup + +**Using goose (meta!):** +```bash +# Install goose +curl -fsSL https://github.com/block/goose/releases/latest/download/install.sh | bash + +# Navigate to your goose clone +cd /path/to/goose + +# Start goose in the repo +goose +``` + +**Using GitHub Copilot:** +- Install the [GitHub Copilot extension](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) for VS Code +- Enable Copilot for Rust files in your settings +- Recommended: Also install [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) for better code intelligence + +**Using Cursor:** +- Download [Cursor](https://cursor.sh/) (VS Code fork with built-in AI) +- Open the goose repository +- Use Cmd/Ctrl+K for inline AI editing, Cmd/Ctrl+L for chat + +**Using Claude or ChatGPT:** +- Copy relevant code sections into the chat interface +- Provide context about the goose architecture (see below) +- Always test generated code locally before committing + +### Rust-Specific Configuration + +If you're new to Rust, configure your AI tool to help you learn: + +**VS Code settings.json:** +```json +{ + "rust-analyzer.checkOnSave.command": "clippy", + "github.copilot.enable": { + "rust": true + } +} +``` + +**Cursor Rules (.cursorrules in repo root):** +``` +This is a Rust project using cargo workspaces. +- Follow existing error handling patterns using anyhow::Result +- Use async/await for I/O operations +- Follow the project's clippy lints (see clippy-baselines/) +- Run cargo fmt before committing +``` + +--- + +## Understanding goose's Architecture + +New to AI agents? Here are key questions to ask your AI tool: + +### Essential Concepts + +**"Explain the goose crate structure"** +``` +Ask: "I'm looking at the goose repository. Can you explain the purpose of each crate +in the crates/ directory and how they relate to each other?" + +Key insight: goose uses a workspace with specialized crates: +- goose: Core agent logic +- goose-cli: Command-line interface +- goose-server: Backend for desktop app (goosed) +- goose-mcp: MCP server implementations +``` + +**"How does the MCP protocol work in goose?"** +``` +Ask: "What is the Model Context Protocol (MCP) and how does goose implement it? +Show me an example from crates/goose-mcp/" + +Key insight: MCP allows goose to connect to external tools and data sources. +Each MCP server provides specific capabilities (developer tools, file access, etc.) +``` + +**"What's the agent execution flow?"** +``` +Ask: "Walk me through what happens when a user sends a message to goose. +Start from crates/goose-cli/src/main.rs" + +Key insight: Message → Agent → Provider (LLM) → Tool execution → Response +``` + +### Navigating the Codebase with AI + +**Finding the right file:** +``` +# Use ripgrep with AI assistance +Ask: "I want to add a new shell command tool. Where should I look?" +AI might suggest: rg "shell" crates/goose-mcp/ -l + +Then ask: "Explain the structure of crates/goose-mcp/src/developer/tools/shell.rs" +``` + +**Understanding patterns:** +``` +Ask: "Show me the pattern for implementing a new Provider in goose" +Then: "What's the difference between streaming and non-streaming providers?" +``` + +--- + +## Practical Examples + +### Example 1: Understanding How to Add a New MCP Tool + +**Scenario:** You want to add a new tool to the developer MCP server. + +**Step 1 - Explore existing tools:** +```bash +# Ask AI: "Show me the structure of an existing MCP tool" +ls crates/goose-mcp/src/developer/tools/ + +# Pick a simple one to study +# Ask AI: "Explain this tool implementation line by line" +cat crates/goose-mcp/src/developer/tools/shell.rs +``` + +**Step 2 - Ask AI to draft your new tool:** +``` +Prompt: "I want to add a new MCP tool called 'git_status' that runs git status +and returns the output. Based on the pattern in shell.rs, draft the implementation." +``` + +**Step 3 - Validate with AI:** +``` +Ask: "Review this code for: +1. Proper error handling using anyhow::Result +2. Security concerns (command injection, etc.) +3. Async/await patterns matching the codebase +4. Test coverage needs" +``` + +**Step 4 - Test locally:** +```bash +# Build and test +cargo build -p goose-mcp +cargo test -p goose-mcp + +# Run clippy +./scripts/clippy-lint.sh +``` + +### Example 2: Fixing a Rust Compiler Error + +**Scenario:** You're getting a lifetime error you don't understand. + +**Step 1 - Copy the full error:** +```bash +cargo build 2>&1 | pbcopy # macOS +cargo build 2>&1 | xclip # Linux +``` + +**Step 2 - Ask AI with context:** +``` +Prompt: "I'm getting this Rust compiler error in the goose project: + +[paste error] + +Here's the relevant code: +[paste code section] + +Explain what's wrong and how to fix it following Rust best practices." +``` + +**Step 3 - Understand the fix:** +``` +Ask: "Explain why this fix works and what I should learn about Rust lifetimes" +``` + +**Step 4 - Apply and verify:** +```bash +# Apply the fix +# Then verify it compiles and tests pass +cargo build +cargo test +``` + +### Example 3: Adding a Feature to the CLI + +**Scenario:** You want to add a new command-line flag to goose-cli. + +**Step 1 - Find the CLI argument parsing:** +```bash +# Ask AI: "Where does goose-cli parse command line arguments?" +rg "clap" crates/goose-cli/src/ -l +``` + +**Step 2 - Study the pattern:** +``` +Ask: "Explain how goose-cli uses clap for argument parsing. +Show me how existing flags are defined." +``` + +**Step 3 - Draft your addition:** +``` +Prompt: "I want to add a --verbose flag that enables debug logging. +Based on the existing patterns in goose-cli, show me: +1. How to add the flag to the CLI args struct +2. How to pass it to the goose core +3. How to use it to control log levels" +``` + +**Step 4 - Implement with validation:** +```bash +# Make changes +# Build both crates +cargo build -p goose-cli -p goose + +# Test the new flag +./target/debug/goose --verbose session + +# Run tests +cargo test -p goose-cli +``` \ No newline at end of file diff --git a/ai-assisted-coding-guide.md b/ai-assisted-coding-guide.md deleted file mode 100644 index 3464f0bb4d80..000000000000 --- a/ai-assisted-coding-guide.md +++ /dev/null @@ -1,91 +0,0 @@ -# Responsible AI-Assisted Coding Guide -_Guidelines for contributing responsibly to goose during Hacktoberfest_ - -goose benefits from thoughtful AI assisted development, but contributors must maintain high standards for code quality, security, and collaboration. Whether you use goose, Copilot, Claude, or other AI tools, these principles will help you avoid common pitfalls. - ---- - -## Core Principles - -- **Human Oversight**: You are accountable for all code you submit. Never commit code you don’t understand or can’t maintain. -- **Quality Standards**: AI code must meet the same standards as human written code—tests, docs, and patterns included. -- **Transparency**: Be open about significant AI usage in PRs and explain how you validated it. - ---- - -## Best Practices - -**✅ Recommended Uses** - -- Generating boilerplate code and common patterns -- Creating comprehensive test suites -- Writing documentation and comments -- Refactoring existing code for clarity -- Generating utility functions and helpers -- Explaining existing code patterns - -**❌ Avoid AI For** - -- Complex business logic without thorough review -- Security critical authentication/authorization code -- Code you don’t fully understand -- Large architectural changes -- Database migrations or schema changes - -**Workflow Tips** - -- Start small and validate often—build, lint, and test incrementally -- Study existing patterns before generating new code -- Always ask: “Is this secure? Does it follow project patterns? What edge cases need testing?” - -**Security Considerations** - -- Extra review required for MCP servers, network code, file system ops, user input, and credential handling -- Never expose secrets in prompts -- Sanitize inputs/outputs and follow goose’s security patterns - ---- - -## Testing & Review - -Before submitting AI assisted code, confirm that: -- You understand every line -- All tests pass locally (happy path + error cases) -- Docs are updated and accurate -- Code follows existing patterns - -**Always get human review** for: - -- Security sensitive code -- Core architecture changes -- Async/concurrency logic -- MCP protocol implementations -- Large refactors or anything you’re unsure about - ---- - -## Using goose for goose Development - -- Protect sensitive files with `.gooseignore` (e.g., `.env*`, `*.key`, `target/`, `.git/`) -- Guide Goose with `.goosehints` (patterns, error handling, formatting, tests, docs) -- Use `/plan` to structure work, and choose modes wisely: - - **Chat** for understanding - - **Smart Approval** for most dev work - - **Approval** for critical areas - - **Autonomous** only with safety nets - ---- - -## Community & Collaboration - -- In PRs, note significant AI use and how you validated results -- Share prompting tips, patterns, and pitfalls -- Be responsive to feedback and help improve this guide - ---- - -## Remember - -AI is a powerful assistant, not a replacement for your judgment. Use it to speed up development; while keeping your brain engaged, your standards high, and goose secure. - -Questions? Join our [Discord](https://discord.gg/goose-oss) or [GitHub Discussions](https://github.com/block/goose/discussions) to talk more about responsible AI development. diff --git a/documentation/blog/2025-09-26-hacktoberfest-2025/index.md b/documentation/blog/2025-09-26-hacktoberfest-2025/index.md index c55f2e291cf8..34240f7a8e7d 100644 --- a/documentation/blog/2025-09-26-hacktoberfest-2025/index.md +++ b/documentation/blog/2025-09-26-hacktoberfest-2025/index.md @@ -34,7 +34,7 @@ To help you make the most of each of your contributions, below is a quick guide ## ✅ Key Rules 1. Read the [code of conduct](https://github.com/block/.github/blob/main/CODE_OF_CONDUCT.md). -2. Refer to the [Responsible AI-Assisted Coding Guide](https://github.com/block/goose/blob/main/ai-assisted-coding-guide.md), [Contributing Guide](https://github.com/block/goose/blob/main/CONTRIBUTING.md) & [README](https://github.com/block/goose/blob/main/README.md) for your contributions. +2. Refer to the [Responsible AI-Assisted Coding Guide](https://github.com/block/goose/blob/main/HOWTOAI.md), [Contributing Guide](https://github.com/block/goose/blob/main/CONTRIBUTING.md) & [README](https://github.com/block/goose/blob/main/README.md) for your contributions. 3. Choose a task from this project's Hacktoberfest [Project Hub](https://github.com/block/goose/issues/4705). Each issue has the 🏷️ `hacktoberfest` label. 4. Comment ".take" on the corresponding issue to get assigned the task. 5. Fork the repository and create a new branch for your work. From 5ddb0e8f1cf2a4af16b14b34661c671d3d2498cf Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 12:23:11 -0500 Subject: [PATCH 063/121] chore(tests/mcp): testing for MCP sampling (#5456) Signed-off-by: fbalicchia --- .github/workflows/pr-smoke-test.yml | 15 +++ crates/goose/tests/mcp_integration_test.rs | 55 +++++++- ...iet-pgoose-server--bingoosed--mcpdeveloper | 28 ++--- ...rver--bingoosed--mcpdeveloper.results.json | 4 +- ...x-y@modelcontextprotocol_server-everything | 29 ++--- ...extprotocol_server-everything.results.json | 6 + .../tests/mcp_replays/uvxmcp-server-fetch | 28 +---- .../uvxmcp-server-fetch.results.json | 2 +- scripts/test_mcp.sh | 118 ++++++++++++++++++ 9 files changed, 218 insertions(+), 67 deletions(-) create mode 100755 scripts/test_mcp.sh diff --git a/.github/workflows/pr-smoke-test.yml b/.github/workflows/pr-smoke-test.yml index 8fee5945ed91..07ae49654feb 100644 --- a/.github/workflows/pr-smoke-test.yml +++ b/.github/workflows/pr-smoke-test.yml @@ -125,6 +125,21 @@ jobs: # Run the provider test script (binary already built and downloaded) bash scripts/test_providers.sh + - name: Run MCP Tests + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + DATABRICKS_HOST: ${{ secrets.DATABRICKS_HOST }} + DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + TETRATE_API_KEY: ${{ secrets.TETRATE_API_KEY }} + HOME: /tmp/goose-home + GOOSE_DISABLE_KEYRING: 1 + SKIP_BUILD: 1 + run: | + bash scripts/test_mcp.sh + - name: Run Subrecipe Tests env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/crates/goose/tests/mcp_integration_test.rs b/crates/goose/tests/mcp_integration_test.rs index 6704119e638b..df1b70d36fa5 100644 --- a/crates/goose/tests/mcp_integration_test.rs +++ b/crates/goose/tests/mcp_integration_test.rs @@ -1,18 +1,25 @@ use serde::Deserialize; + use std::collections::HashMap; use std::fs::File; use std::path::PathBuf; +use std::sync::Arc; use std::{env, fs}; -use rmcp::model::{CallToolRequestParam, Content}; +use rmcp::model::{CallToolRequestParam, Content, Tool}; use rmcp::object; use tokio_util::sync::CancellationToken; use goose::agents::extension::{Envs, ExtensionConfig}; use goose::agents::extension_manager::ExtensionManager; +use goose::model::ModelConfig; use test_case::test_case; +use async_trait::async_trait; +use goose::conversation::message::Message; +use goose::providers::base::{Provider, ProviderMetadata, ProviderUsage, Usage}; +use goose::providers::errors::ProviderError; use once_cell::sync::Lazy; use std::process::Command; @@ -29,6 +36,45 @@ struct Target { kind: Vec, } +#[derive(Clone)] +pub struct MockProvider { + pub model_config: ModelConfig, +} + +impl MockProvider { + pub fn new(model_config: ModelConfig) -> Self { + Self { model_config } + } +} + +#[async_trait] +impl Provider for MockProvider { + fn metadata() -> ProviderMetadata { + ProviderMetadata::empty() + } + + fn get_name(&self) -> &str { + "mock" + } + + async fn complete_with_model( + &self, + _model_config: &ModelConfig, + _system: &str, + _messages: &[Message], + _tools: &[Tool], + ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { + Ok(( + Message::assistant().with_text("\"So we beat on, boats against the current, borne back ceaselessly into the past.\" — F. Scott Fitzgerald, The Great Gatsby (1925)"), + ProviderUsage::new("mock".to_string(), Usage::default()), + )) + } + + fn get_model_config(&self) -> ModelConfig { + self.model_config.clone() + } +} + fn build_and_get_binary_path() -> PathBuf { let output = Command::new("cargo") .args([ @@ -79,6 +125,7 @@ enum TestMode { CallToolRequestParam { name: "add".into(), arguments: Some(object!({"a": 1, "b": 2 })) }, CallToolRequestParam { name: "longRunningOperation".into(), arguments: Some(object!({"duration": 1, "steps": 5 })) }, CallToolRequestParam { name: "structuredContent".into(), arguments: Some(object!({"location": "11238"})) }, + CallToolRequestParam { name: "sampleLLM".into(), arguments: Some(object!({"prompt": "Please provide a quote from The Great Gatsby", "maxTokens": 100 })) } ], vec![] )] @@ -205,7 +252,11 @@ async fn test_replayed_session( bundled: Some(false), available_tools: vec![], }; - let extension_manager = ExtensionManager::new_without_provider(); + + let provider = Arc::new(tokio::sync::Mutex::new(Some(Arc::new(MockProvider { + model_config: ModelConfig::new("test-model").unwrap(), + }) as Arc))); + let extension_manager = ExtensionManager::new(provider); #[allow(clippy::redundant_closure_call)] let result = (async || -> Result<(), Box> { diff --git a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper index c5b490b065f4..38cf176226bc 100644 --- a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper +++ b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper @@ -1,20 +1,20 @@ STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} -STDERR: 2025-09-27T04:13:30.409389Z  INFO goose_mcp::mcp_server_runner: Starting MCP server +STDERR: 2025-10-30T14:41:09.117156Z  INFO goose_mcp::mcp_server_runner: Starting MCP server STDERR: at crates/goose-mcp/src/mcp_server_runner.rs:18 -STDERR: -STDERR: 2025-09-27T04:13:30.412663Z  INFO goose_mcp::developer::analyze::cache: Initializing analysis cache with size 100 -STDERR: at crates/goose-mcp/src/developer/analyze/cache.rs:25 -STDERR: -STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"prompts":{},"tools":{}},"serverInfo":{"name":"goose-developer","version":"1.9.0"},"instructions":" The developer extension gives you the capabilities to edit code files and run shell commands,\n and can be used to solve a wide range of problems.\n\nYou can use the shell tool to run any command that would work on the relevant operating system.\nUse the shell tool as needed to locate files or interact with the project.\n\nLeverage `analyze` through `return_last_only=true` subagents for deep codebase understanding with lean context\n- delegate analysis, retain summaries\n\nYour windows/screen tools can be used for visual debugging. You should not use these tools unless\nprompted to, but you can mention they are available if they are relevant.\n\nAlways prefer ripgrep (rg -C 3) to grep.\n\noperating system: macos\ncurrent directory: /Users/angiej/workspace/goose/crates/goose\n\n \n\nAdditional Text Editor Tool Instructions:\n\nPerform text editing operations on files.\n\nThe `command` parameter specifies the operation to perform. Allowed options are:\n- `view`: View the content of a file.\n- `write`: Create or overwrite a file with the given content\n- `str_replace`: Replace text in one or more files.\n- `insert`: Insert text at a specific line location in the file.\n- `undo_edit`: Undo the last edit made to a file.\n\nTo use the write command, you must specify `file_text` which will become the new content of the file. Be careful with\nexisting files! This is a full overwrite, so you must include everything - not just sections you are modifying.\n\nTo use the str_replace command to edit multiple files, use the `diff` parameter with a unified diff.\nTo use the str_replace command to edit one file, you must specify both `old_str` and `new_str` - the `old_str` needs to exactly match one\nunique section of the original file, including any whitespace. Make sure to include enough context that the match is not\nambiguous. The entire original string will be replaced with `new_str`\n\nWhen possible, batch file edits together by using a multi-file unified `diff` within a single str_replace tool call.\n\nTo use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning, -1 for end)\nand `new_str` (the text to insert).\n\n\n\nAdditional Shell Tool Instructions:\nExecute a command in the shell.\n\nThis will return the output and error concatenated into a single string, as\nyou would see from running on the command line. There will also be an indication\nof if the command succeeded or failed.\n\nAvoid commands that produce a large amount of output, and consider piping those outputs to files.\n\n**Important**: Each shell command runs in its own process. Things like directory changes or\nsourcing files do not persist between tool calls. So you may need to repeat them each time by\nstringing together commands.\nIf you need to run a long lived command, background it - e.g. `uvicorn main:app &` so that\nthis tool does not run indefinitely.\n\n**Important**: Use ripgrep - `rg` - exclusively when you need to locate a file or a code reference,\nother solutions may produce too large output because of hidden files! For example *do not* use `find` or `ls -r`\n - List files by name: `rg --files | rg `\n - List files that contain a regex: `rg '' -l`\n\n - Multiple commands: Use && to chain commands, avoid newlines\n - Example: `cd example && ls` or `source env/bin/activate && pip install numpy`\n\n\n### Global Hints\nThe developer extension includes some global hints that apply to all projects & directories.\nCloned Goose repo: /Users/angiej/workspace/goose\nMCP means Model Context Protocol. Docs: https://modelcontextprotocol.io/introduction\nUse GitHub CLI for GitHub-related tasks.\nWhen prompted for date-related information, do not rely on your internal knowledge for the current date. Instead, use the `date` terminal command to get the actual date and time.\nNEVER run blocking server commands (node server.js, npm start, etc.) - provide commands for user to run separately\n\n### Project Hints\nThe developer extension includes some hints for working on the project in this directory.\n# AGENTS Instructions\n\ngoose is an AI agent framework in Rust with CLI and Electron desktop interfaces.\n\n## Setup\n```bash\nsource bin/activate-hermit\ncargo build\n```\n\n## Commands\n\n### Build\n```bash\ncargo build # debug\ncargo build --release # release \njust release-binary # release + openapi\n```\n\n### Test\n```bash\ncargo test # all tests\ncargo test -p goose # specific crate\ncargo test --package goose --test mcp_integration_test\njust record-mcp-tests # record MCP\n```\n\n### Lint/Format\n```bash\ncargo fmt\n./scripts/clippy-lint.sh\ncargo clippy --fix\n```\n\n### UI\n```bash\njust generate-openapi # after server changes\njust run-ui # start desktop\ncd ui/desktop && npm test # test UI\n```\n\n## Structure\n```\ncrates/\n├── goose # core logic\n├── goose-bench # benchmarking\n├── goose-cli # CLI entry\n├── goose-server # backend (binary: goosed)\n├── goose-mcp # MCP extensions\n├── goose-test # test utilities\n├── mcp-client # MCP client\n├── mcp-core # MCP shared\n└── mcp-server # MCP server\n\ntemporal-service/ # Go scheduler\nui/desktop/ # Electron app\n```\n\n## Development Loop\n```bash\n# 1. source bin/activate-hermit\n# 2. Make changes\n# 3. cargo fmt\n# 4. cargo build\n# 5. cargo test -p \n# 6. ./scripts/clippy-lint.sh\n# 7. [if server] just generate-openapi\n```\n\n## Rules\n\nTest: Prefer tests/ folder, e.g. crates/goose/tests/\nError: Use anyhow::Result\nProvider: Implement Provider trait see providers/base.rs\nMCP: Extensions in crates/goose-mcp/\nServer: Changes need just generate-openapi\n\n## Never\n\nNever: Edit ui/desktop/openapi.json manually\nNever: Edit Cargo.toml use cargo add\nNever: Skip cargo fmt\nNever: Merge without ./scripts/clippy-lint.sh\n\n## Entry Points\n- CLI: crates/goose-cli/src/main.rs\n- Server: crates/goose-server/src/main.rs\n- UI: ui/desktop/src/main.ts\n- Agent: crates/goose/src/agents/agent.rs\n\nThis is a rust project with crates in the crates dir:\ngoose: the main code for goose, contains all the core logic\ngoose-bench: bench marking\ngoose-cli: the command line interface, use goose crate\ngoose-mcp: the mcp servers that ship with goose. the developer sub system is of special interest\ngoose-server: the server that suports the desktop (electron) app. also known as goosed\n\n\nui/desktop has an electron app in typescript. \n\nnon trivial features should be implemented in the goose crate and then be called from the goose-cli crate for the cli. for the desktop, you want to add routes to \ngoose-server/src/routes. you can then run `just generate-openapi` to generate the openapi spec which will modify the ui/desktop/src/api files. once you have\nthat you can call the functionality from the server from the typescript.\n\ntips: \n- can look at unstaged changes for what is being worked on if starting\n- always check rust compiles, cargo fmt etc and `./scripts/clippy-lint.sh` (as well as run tests in files you are working on)\n- in ui/desktop, look at how you can run lint checks and if other tests can run\n"}} +STDERR: +STDERR: 2025-10-30T14:41:09.120902Z  INFO goose_mcp::developer::analyze::cache: Initializing analysis cache with size 100 +STDERR: at crates/goose-mcp/src/developer/analyze/cache.rs:26 +STDERR: +STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"prompts":{},"tools":{}},"serverInfo":{"name":"goose-developer","version":"1.11.0"},"instructions":" The developer extension gives you the capabilities to edit code files and run shell commands,\n and can be used to solve a wide range of problems.\n\nYou can use the shell tool to run any command that would work on the relevant operating system.\nUse the shell tool as needed to locate files or interact with the project.\n\nLeverage `analyze` through `return_last_only=true` subagents for deep codebase understanding with lean context\n- delegate analysis, retain summaries\n\nYour windows/screen tools can be used for visual debugging. You should not use these tools unless\nprompted to, but you can mention they are available if they are relevant.\n\nAlways prefer ripgrep (rg -C 3) to grep.\n\noperating system: macos\ncurrent directory: /Users/alexhancock/Development/goose/crates/goose\nshell: zsh\n\n \n\nAdditional Text Editor Tool Instructions:\n\nPerform text editing operations on files.\n\nThe `command` parameter specifies the operation to perform. Allowed options are:\n- `view`: View the content of a file.\n- `write`: Create or overwrite a file with the given content\n- `str_replace`: Replace text in one or more files.\n- `insert`: Insert text at a specific line location in the file.\n- `undo_edit`: Undo the last edit made to a file.\n\nTo use the write command, you must specify `file_text` which will become the new content of the file. Be careful with\nexisting files! This is a full overwrite, so you must include everything - not just sections you are modifying.\n\nTo use the str_replace command to edit multiple files, use the `diff` parameter with a unified diff.\nTo use the str_replace command to edit one file, you must specify both `old_str` and `new_str` - the `old_str` needs to exactly match one\nunique section of the original file, including any whitespace. Make sure to include enough context that the match is not\nambiguous. The entire original string will be replaced with `new_str`\n\nWhen possible, batch file edits together by using a multi-file unified `diff` within a single str_replace tool call.\n\nTo use the insert command, you must specify both `insert_line` (the line number after which to insert, 0 for beginning, -1 for end)\nand `new_str` (the text to insert).\n\n\n\nAdditional Shell Tool Instructions:\nExecute a command in the shell.\n\nThis will return the output and error concatenated into a single string, as\nyou would see from running on the command line. There will also be an indication\nof if the command succeeded or failed.\n\nAvoid commands that produce a large amount of output, and consider piping those outputs to files.\n\n**Important**: Each shell command runs in its own process. Things like directory changes or\nsourcing files do not persist between tool calls. So you may need to repeat them each time by\nstringing together commands.\nIf you need to run a long lived command, background it - e.g. `uvicorn main:app &` so that\nthis tool does not run indefinitely.\n\n**Important**: Use ripgrep - `rg` - exclusively when you need to locate a file or a code reference,\nother solutions may produce too large output because of hidden files! For example *do not* use `find` or `ls -r`\n - List files by name: `rg --files | rg `\n - List files that contain a regex: `rg '' -l`\n\n - Multiple commands: Use && to chain commands, avoid newlines\n - Example: `cd example && ls` or `source env/bin/activate && pip install numpy`\n\n\n### Global Hints\nThe developer extension includes some global hints that apply to all projects & directories.\nThese are my global goose hints.\n\n### Project Hints\nThe developer extension includes some hints for working on the project in this directory.\n# AGENTS Instructions\n\ngoose is an AI agent framework in Rust with CLI and Electron desktop interfaces.\n\n## Setup\n```bash\nsource bin/activate-hermit\ncargo build\n```\n\n## Commands\n\n### Build\n```bash\ncargo build # debug\ncargo build --release # release \njust release-binary # release + openapi\n```\n\n### Test\n```bash\ncargo test # all tests\ncargo test -p goose # specific crate\ncargo test --package goose --test mcp_integration_test\njust record-mcp-tests # record MCP\n```\n\n### Lint/Format\n```bash\ncargo fmt\n./scripts/clippy-lint.sh\ncargo clippy --fix\n```\n\n### UI\n```bash\njust generate-openapi # after server changes\njust run-ui # start desktop\ncd ui/desktop && npm test # test UI\n```\n\n## Structure\n```\ncrates/\n├── goose # core logic\n├── goose-bench # benchmarking\n├── goose-cli # CLI entry\n├── goose-server # backend (binary: goosed)\n├── goose-mcp # MCP extensions\n├── goose-test # test utilities\n├── mcp-client # MCP client\n├── mcp-core # MCP shared\n└── mcp-server # MCP server\n\ntemporal-service/ # Go scheduler\nui/desktop/ # Electron app\n```\n\n## Development Loop\n```bash\n# 1. source bin/activate-hermit\n# 2. Make changes\n# 3. cargo fmt\n# 4. cargo build\n# 5. cargo test -p \n# 6. ./scripts/clippy-lint.sh\n# 7. [if server] just generate-openapi\n```\n\n## Rules\n\nTest: Prefer tests/ folder, e.g. crates/goose/tests/\nTest: When adding features, update goose-self-test.yaml, rebuild, then run `goose run --recipe goose-self-test.yaml` to validate\nError: Use anyhow::Result\nProvider: Implement Provider trait see providers/base.rs\nMCP: Extensions in crates/goose-mcp/\nServer: Changes need just generate-openapi\n\n## Never\n\nNever: Edit ui/desktop/openapi.json manually\nNever: Edit Cargo.toml use cargo add\nNever: Skip cargo fmt\nNever: Merge without ./scripts/clippy-lint.sh\nNever: Comment self-evident operations (`// Initialize`, `// Return result`), getters/setters, constructors, or standard Rust idioms\n\n## Entry Points\n- CLI: crates/goose-cli/src/main.rs\n- Server: crates/goose-server/src/main.rs\n- UI: ui/desktop/src/main.ts\n- Agent: crates/goose/src/agents/agent.rs\n\nThis is a rust project with crates in the crates dir:\ngoose: the main code for goose, contains all the core logic\ngoose-bench: bench marking\ngoose-cli: the command line interface, use goose crate\ngoose-mcp: the mcp servers that ship with goose. the developer sub system is of special interest\ngoose-server: the server that suports the desktop (electron) app. also known as goosed\n\n\nui/desktop has an electron app in typescript. \n\nnon trivial features should be implemented in the goose crate and then be called from the goose-cli crate for the cli. for the desktop, you want to add routes to \ngoose-server/src/routes. you can then run `just generate-openapi` to generate the openapi spec which will modify the ui/desktop/src/api files. once you have\nthat you can call the functionality from the server from the typescript.\n\ntips: \n- can look at unstaged changes for what is being worked on if starting\n- always check rust compiles, cargo fmt etc and `./scripts/clippy-lint.sh` (as well as run tests in files you are working on)\n- in ui/desktop, look at how you can run lint checks and if other tests can run\n"}} STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"} -STDERR: 2025-09-27T04:13:30.418172Z  INFO rmcp::handler::server: client initialized -STDERR: at /Users/angiej/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.6.2/src/handler/server.rs:218 -STDERR: +STDERR: 2025-10-30T14:41:09.126014Z  INFO rmcp::handler::server: client initialized +STDERR: at /Users/alexhancock/Development/goose/.hermit/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.8.1/src/handler/server.rs:218 +STDERR: STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"text_editor","arguments":{"command":"view","path":"/tmp/goose_test/goose.txt"}}} -STDERR: 2025-09-27T04:13:30.418412Z  INFO rmcp::service: Service initialized as server, peer_info: Some(InitializeRequestParam { protocol_version: ProtocolVersion("2025-03-26"), capabilities: ClientCapabilities { experimental: None, roots: None, sampling: None, elicitation: None }, client_info: Implementation { name: "goose", version: "1.9.0" } }) -STDERR: at /Users/angiej/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.6.2/src/service.rs:561 +STDERR: 2025-10-30T14:41:09.126196Z  INFO rmcp::service: Service initialized as server, peer_info: Some(InitializeRequestParam { protocol_version: ProtocolVersion("2025-03-26"), capabilities: ClientCapabilities { experimental: None, roots: None, sampling: Some({}), elicitation: None }, client_info: Implementation { name: "goose", title: None, version: "0.0.0", icons: None, website_url: None } }) +STDERR: at /Users/alexhancock/Development/goose/.hermit/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rmcp-0.8.1/src/service.rs:562 STDERR: in rmcp::service::serve_inner -STDERR: +STDERR: STDOUT: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"resource","resource":{"uri":"file:///tmp/goose_test/goose.txt","mimeType":"text","text":"# goose\n"},"annotations":{"audience":["assistant"]}},{"type":"text","text":"### /tmp/goose_test/goose.txt\n```\n1: # goose\n```\n","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} STDIN: {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"_meta":{"progressToken":1},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose (modified by test)","old_str":"# goose","path":"/tmp/goose_test/goose.txt"}}} STDOUT: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose (modified by test)\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose (modified by test)\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} @@ -24,5 +24,5 @@ STDOUT: {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"# go STDIN: {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"_meta":{"progressToken":3},"name":"text_editor","arguments":{"command":"str_replace","new_str":"# goose","old_str":"# goose (modified by test)","path":"/tmp/goose_test/goose.txt"}}} STDOUT: {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"The file /tmp/goose_test/goose.txt has been edited, and the section now reads:\n```\n# goose\n```\n\nReview the changes above for errors. Undo and edit the file again if necessary!\n","annotations":{"audience":["assistant"]}},{"type":"text","text":"```\n# goose\n```\n","annotations":{"audience":["user"],"priority":0.2}}],"isError":false}} STDIN: {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"_meta":{"progressToken":4},"name":"list_windows","arguments":{}}} -STDOUT: {"jsonrpc":"2.0","id":5,"result":{"content":[{"type":"text","text":"Available windows:\nMenubar","annotations":{"audience":["assistant"]}},{"type":"text","text":"Available windows:\nMenubar","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} -STDERR: 2025-09-27T04:13:30.505916Z  INFO rmcp::service: input stream terminated +STDOUT: {"jsonrpc":"2.0","id":5,"result":{"content":[{"type":"text","text":"Available windows:\n\nItem-0\nbb3cc23c-6950-4e96-8b40-850e09f46934\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nBattery\nWiFi\nItem-0\nBentoBox\nSiri\nClock\nMenubar\nDock\njust record-mcp-tests","annotations":{"audience":["assistant"]}},{"type":"text","text":"Available windows:\n\nItem-0\nbb3cc23c-6950-4e96-8b40-850e09f46934\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nBattery\nWiFi\nItem-0\nBentoBox\nSiri\nClock\nMenubar\nDock\njust record-mcp-tests","annotations":{"audience":["user"],"priority":0.0}}],"isError":false}} +STDERR: 2025-10-30T14:41:09.200915Z  INFO rmcp::service: input stream terminated diff --git a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json index 1f53d3c2629e..e3d4e6a35541 100644 --- a/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json +++ b/crates/goose/tests/mcp_replays/cargorun--quiet-pgoose-server--bingoosed--mcpdeveloper.results.json @@ -90,7 +90,7 @@ [ { "type": "text", - "text": "Available windows:\nMenubar", + "text": "Available windows:\n\nItem-0\nbb3cc23c-6950-4e96-8b40-850e09f46934\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nBattery\nWiFi\nItem-0\nBentoBox\nSiri\nClock\nMenubar\nDock\njust record-mcp-tests", "annotations": { "audience": [ "assistant" @@ -99,7 +99,7 @@ }, { "type": "text", - "text": "Available windows:\nMenubar", + "text": "Available windows:\n\nItem-0\nbb3cc23c-6950-4e96-8b40-850e09f46934\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nItem-0\nBattery\nWiFi\nItem-0\nBentoBox\nSiri\nClock\nMenubar\nDock\njust record-mcp-tests", "annotations": { "audience": [ "user" diff --git a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything index 8ac4f0843488..39cca7e5dfa7 100644 --- a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything +++ b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything @@ -1,29 +1,10 @@ STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} -STDERR: 2025-09-26 23:13:04 - Starting npx setup script. -STDERR: 2025-09-26 23:13:04 - Creating directory ~/.config/goose/mcp-hermit/bin if it does not exist. -STDERR: 2025-09-26 23:13:04 - Changing to directory ~/.config/goose/mcp-hermit. -STDERR: 2025-09-26 23:13:04 - Hermit binary already exists. Skipping download. -STDERR: 2025-09-26 23:13:04 - setting hermit cache to be local for MCP servers -STDERR: 2025-09-26 23:13:04 - Updated PATH to include ~/.config/goose/mcp-hermit/bin. -STDERR: 2025-09-26 23:13:04 - Checking for hermit in PATH. -STDERR: 2025-09-26 23:13:04 - Initializing hermit. -STDERR: 2025-09-26 23:13:04 - Installing Node.js with hermit. -STDERR: 2025-09-26 23:13:04 - Verifying installation locations: -STDERR: 2025-09-26 23:13:04 - hermit: /Users/angiej/.config/goose/mcp-hermit/bin/hermit -STDERR: 2025-09-26 23:13:04 - node: /Users/angiej/.config/goose/mcp-hermit/bin/node -STDERR: 2025-09-26 23:13:04 - npx: /Users/angiej/.config/goose/mcp-hermit/bin/npx -STDERR: 2025-09-26 23:13:04 - Checking for GOOSE_NPM_REGISTRY and GOOSE_NPM_CERT environment variables for custom npm registry setup... -STDERR: 2025-09-26 23:13:05 - Checking custom goose registry availability: https://global.block-artifacts.com/artifactory/api/npm/square-npm/ -STDERR: 2025-09-26 23:13:05 - https://global.block-artifacts.com/artifactory/api/npm/square-npm/ is accessible. Using it for npm registry. -STDERR: 2025-09-26 23:13:06 - Downloading certificate from: https://block-ca.squareup.com/root-certs.pem -STDERR: 2025-09-26 23:13:07 - Certificate downloaded successfully. -STDERR: 2025-09-26 23:13:07 - Executing 'npx' command with arguments: -y @modelcontextprotocol/server-everything STDERR: Starting default (STDIO) server... STDERR: Starting logs update interval STDOUT: {"result":{"protocolVersion":"2025-03-26","capabilities":{"prompts":{},"resources":{"subscribe":true},"tools":{},"logging":{},"completions":{}},"serverInfo":{"name":"example-servers/everything","title":"Everything Example Server","version":"1.0.0"},"instructions":"Testing and demonstration server for MCP protocol features.\n\n## Resources\n\nResources 1-100 follow pattern: even IDs contain text, odd IDs contain binary data. Resources are paginated at 10 items per page with cursor-based navigation.\n\n## Key dependencies\n\nProgress notifications require `_meta.progressToken` in tool calls. Resource subscriptions generate updates every 10 seconds.\n\n## Performance characteristics\n\nServer generates automatic log messages every 20 seconds (filtered by current log level), stderr notifications every 30 seconds, and resource update notifications every 10 seconds for active subscriptions. Log level changes affect message filtering in real-time.\n\n## Multi-modal testing\n\n`complex_prompt` includes both text arguments and image content for testing client multi-modal handling. `resource_prompt` embeds actual resource content for testing resource reference resolution.\n\nArgument completion is available for prompt parameters and resource IDs. Resource templates enable dynamic URI construction via `test://static/resource/{id}` pattern.\n\n## Easter egg\n\nIf asked about server instructions, respond with \"🎉 Server instructions are working! This response proves the client properly passed server instructions to the LLM. This demonstrates MCP's instructions feature in action.\"\n"},"jsonrpc":"2.0","id":0} STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"} -STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"echo","arguments":{"message":"Hello, world!"}}} STDOUT: {"method":"notifications/message","params":{"level":"info","logger":"everything-server","data":"Client does not support MCP roots protocol"},"jsonrpc":"2.0"} +STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"echo","arguments":{"message":"Hello, world!"}}} STDOUT: {"result":{"content":[{"type":"text","text":"Echo: Hello, world!"}]},"jsonrpc":"2.0","id":1} STDIN: {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"_meta":{"progressToken":1},"name":"add","arguments":{"a":1,"b":2}}} STDOUT: {"result":{"content":[{"type":"text","text":"The sum of 1 and 2 is 3."}]},"jsonrpc":"2.0","id":2} @@ -36,5 +17,9 @@ STDOUT: {"method":"notifications/progress","params":{"progress":5,"total":5,"pro STDOUT: {"result":{"content":[{"type":"text","text":"Long running operation completed. Duration: 1 seconds, Steps: 5."}]},"jsonrpc":"2.0","id":3} STDIN: {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"_meta":{"progressToken":3},"name":"structuredContent","arguments":{"location":"11238"}}} STDOUT: {"result":{"content":[{"type":"text","text":"{\"temperature\":22.5,\"conditions\":\"Partly cloudy\",\"humidity\":65}"}],"structuredContent":{"temperature":22.5,"conditions":"Partly cloudy","humidity":65}},"jsonrpc":"2.0","id":4} -STDOUT: {"method":"notifications/message","params":{"level":"emergency","data":"Emergency-level message"},"jsonrpc":"2.0"} -STDERR: node:events:497 +STDIN: {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"_meta":{"progressToken":4},"name":"sampleLLM","arguments":{"maxTokens":100,"prompt":"Please provide a quote from The Great Gatsby"}}} +STDOUT: {"method":"sampling/createMessage","params":{"messages":[{"role":"user","content":{"type":"text","text":"Resource sampleLLM context: Please provide a quote from The Great Gatsby"}}],"systemPrompt":"You are a helpful test server.","maxTokens":100,"temperature":0.7,"includeContext":"thisServer"},"jsonrpc":"2.0","id":0} +STDIN: {"jsonrpc":"2.0","id":0,"result":{"model":"mock","stopReason":"endTurn","role":"assistant","content":{"type":"text","text":"\"So we beat on, boats against the current, borne back ceaselessly into the past.\" — F. Scott Fitzgerald, The Great Gatsby (1925)"}}} +STDOUT: {"result":{"content":[{"type":"text","text":"LLM sampling result: \"So we beat on, boats against the current, borne back ceaselessly into the past.\" — F. Scott Fitzgerald, The Great Gatsby (1925)"}]},"jsonrpc":"2.0","id":5} +STDOUT: {"method":"notifications/message","params":{"level":"error","data":"Error-level message"},"jsonrpc":"2.0"} +STDERR: node:events:486 diff --git a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything.results.json b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything.results.json index 7d4a3b268c6a..2b7f47b8d8bf 100644 --- a/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything.results.json +++ b/crates/goose/tests/mcp_replays/npx-y@modelcontextprotocol_server-everything.results.json @@ -22,5 +22,11 @@ "type": "text", "text": "{\"temperature\":22.5,\"conditions\":\"Partly cloudy\",\"humidity\":65}" } + ], + [ + { + "type": "text", + "text": "LLM sampling result: \"So we beat on, boats against the current, borne back ceaselessly into the past.\" — F. Scott Fitzgerald, The Great Gatsby (1925)" + } ] ] \ No newline at end of file diff --git a/crates/goose/tests/mcp_replays/uvxmcp-server-fetch b/crates/goose/tests/mcp_replays/uvxmcp-server-fetch index a473f29fa8eb..d84548d8c0fb 100644 --- a/crates/goose/tests/mcp_replays/uvxmcp-server-fetch +++ b/crates/goose/tests/mcp_replays/uvxmcp-server-fetch @@ -1,29 +1,5 @@ STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} -STDERR: 2025-09-26 23:13:04 - Starting uvx setup script. -STDERR: 2025-09-26 23:13:04 - Creating directory ~/.config/goose/mcp-hermit/bin if it does not exist. -STDERR: 2025-09-26 23:13:04 - Changing to directory ~/.config/goose/mcp-hermit. -STDERR: 2025-09-26 23:13:04 - Hermit binary already exists. Skipping download. -STDERR: 2025-09-26 23:13:04 - setting hermit cache to be local for MCP servers -STDERR: 2025-09-26 23:13:04 - Updated PATH to include ~/.config/goose/mcp-hermit/bin. -STDERR: 2025-09-26 23:13:04 - Checking for hermit in PATH. -STDERR: 2025-09-26 23:13:04 - Initializing hermit. -STDERR: 2025-09-26 23:13:04 - hermit install python 3.10 -STDERR: 2025-09-26 23:13:04 - Installing UV with hermit. -STDERR: 2025-09-26 23:13:04 - Verifying installation locations: -STDERR: 2025-09-26 23:13:04 - hermit: /Users/angiej/.config/goose/mcp-hermit/bin/hermit -STDERR: 2025-09-26 23:13:04 - uv: /Users/angiej/.config/goose/mcp-hermit/bin/uv -STDERR: 2025-09-26 23:13:04 - uvx: /Users/angiej/.config/goose/mcp-hermit/bin/uvx -STDERR: 2025-09-26 23:13:04 - Checking for GOOSE_UV_REGISTRY environment variable for custom python/pip/UV registry setup... -STDERR: 2025-09-26 23:13:05 - Checking custom goose registry availability: https://global.block-artifacts.com/artifactory/api/pypi/block-pypi/simple -STDERR: 2025-09-26 23:13:05 - https://global.block-artifacts.com/artifactory/api/pypi/block-pypi/simple is accessible, setting it as UV_DEFAULT_INDEX. Setting UV_NATIVE_TLS to true. -STDERR: 2025-09-26 23:13:05 - Executing 'uvx' command with arguments: mcp-server-fetch -STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"mcp-fetch","version":"1.15.0"}}} +STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"mcp-fetch","version":"1.19.0"}}} STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"} STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"progressToken":0},"name":"fetch","arguments":{"url":"https://example.com"}}} -STDERR: npm error code FETCH_ERROR -STDERR: npm error errno FETCH_ERROR -STDERR: npm error invalid json response body at https://blocked.teams.cloudflare.com/?account_id=1e25787f854fa4b713d08a859d3e16ed&background_color=%23000000&block_reason=This+has+been+blocked+as+part+of+the+Dependency+Confusion+threat.+Please+see+go%2Fdependencyconfusionpypi+and+go%2Fdependencyconfusionnpm+for+more+info.&device_id=***&footer_text=The+website+you+are+trying+to+access+has+been+blocked+because+it+presents+a+risk+to+the+safety+and+security+of+Block%E2%80%99s+IT+systems.&header_text=This+page+presents+a+risk+to+Block&location=cf1ebd1203624140846ced63a200519e&logo_path=https%3A%2F%2Fmedia.block.xyz%2Flogos%2Fblock-jewel_white.png&mailto_address=&mailto_subject=&name=Block%2C+Inc.¶ms_sign=yrMcT5HYDMHvixy%2BdLHApce3BcNYIdlI8qh3wTcIrLA%3D&query_id=***&rule_id=***&source_ip=2a09%3Abac0%3A1000%3A2df%3A%3A281%3Ac0&suppress_footer=false&url=registry.npmjs.org&user_id=*** reason: Unexpected token '<', " -STDERR: npm error &1) | tee "$TMPFILE" + echo "" + if grep -q "sampleLLM | " "$TMPFILE"; then + + JUDGE_PROMPT=$(cat <&1) + + if echo "$JUDGE_OUT" | tr -d '\r' | grep -Eq '^[[:space:]]*PASS[[:space:]]*$'; then + echo "✓ SUCCESS: MCP sampling test passed - confirmed Gatsby related response" + RESULTS+=("✓ MCP Sampling ${PROVIDER}: ${MODEL}") + else + echo "✗ FAILED: MCP sampling test failed - did not confirm Gatsby related response" + echo " Judge provider/model: ${JUDGE_PROVIDER}:${JUDGE_MODEL}" + echo " Judge output (snippet):" + echo "$JUDGE_OUT" | tail -n 20 + RESULTS+=("✗ MCP Sampling ${PROVIDER}: ${MODEL}") + fi + else + echo "✗ FAILED: MCP sampling test failed - sampleLLM tool not called" + RESULTS+=("✗ MCP Sampling ${PROVIDER}: ${MODEL}") + fi + rm "$TMPFILE" + rm -rf "$TESTDIR" + echo "---" + done +done + +echo "" +echo "=== MCP Sampling Test Summary ===" +for result in "${RESULTS[@]}"; do + echo "$result" +done + +if echo "${RESULTS[@]}" | grep -q "✗"; then + echo "" + echo "Some MCP sampling tests failed!" + exit 1 +else + echo "" + echo "All MCP sampling tests passed!" +fi From 67c5d70b261d70b8adec5c47535e5caefab2d0b1 Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Mon, 3 Nov 2025 11:24:21 -0600 Subject: [PATCH 064/121] docs: AI attribution for PRs (#5547) Signed-off-by: fbalicchia --- .github/pull_request_template.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b8f1f7e29f82..bc90ec22d9a6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,6 +14,10 @@ - [ ] Build / Release - [ ] Other (specify below) +### AI Assistance + +- [ ] This PR was created or reviewed with AI assistance + ### Testing @@ -27,5 +31,6 @@ Before: After: - +### Submitting a Recipe? + **Email**: From 65cdb34bc5191d1727ca2bb6cac1f078dbcd7545 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Mon, 3 Nov 2025 12:29:43 -0500 Subject: [PATCH 065/121] Fix image processing (#5544) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose/src/providers/formats/databricks.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/goose/src/providers/formats/databricks.rs b/crates/goose/src/providers/formats/databricks.rs index c781422d9250..54668e9dfe21 100644 --- a/crates/goose/src/providers/formats/databricks.rs +++ b/crates/goose/src/providers/formats/databricks.rs @@ -212,13 +212,7 @@ fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec { - // Handle direct image content - content_array.push(json!({ - "type": "image_url", - "image_url": { - "url": convert_image(image, image_format) - } - })); + content_array.push(convert_image(image, image_format)); } MessageContent::FrontendToolRequest(req) => { // Frontend tool requests are converted to text messages From dcf50ddf872e6756b9516121d47b10a2ee09ff0f Mon Sep 17 00:00:00 2001 From: BestCodes <106822363+The-Best-Codes@users.noreply.github.com> Date: Mon, 3 Nov 2025 11:37:25 -0600 Subject: [PATCH 066/121] fix hermit `text file busy` issues on linux (#5372) Signed-off-by: The-Best-Codes Signed-off-by: fbalicchia --- ui/desktop/src/bin/node-setup-common.sh | 36 ++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/ui/desktop/src/bin/node-setup-common.sh b/ui/desktop/src/bin/node-setup-common.sh index 97c3551d5ac0..16eee6854714 100755 --- a/ui/desktop/src/bin/node-setup-common.sh +++ b/ui/desktop/src/bin/node-setup-common.sh @@ -57,9 +57,39 @@ log "Updated PATH to include ~/.config/goose/mcp-hermit/bin." log "Checking for hermit in PATH." which hermit >> "$LOG_FILE" -# Initialize hermit -log "Initializing hermit." -hermit init >> "$LOG_FILE" +# Check if hermit environment is already initialized (only run init on first setup) +if [ ! -f bin/activate-hermit ]; then + log "Hermit environment not yet initialized. Setting up hermit." + + # Fix hermit self-update lock issues on Linux by using temp binary for init only + if [[ "$(uname -s)" == "Linux" ]]; then + log "Creating temp dir with bin subdirectory for hermit copy to avoid self-update locks." + HERMIT_TMP_DIR="/tmp/hermit_tmp_$$/bin" + mkdir -p "$HERMIT_TMP_DIR" + cp ~/.config/goose/mcp-hermit/bin/hermit "$HERMIT_TMP_DIR/hermit" + chmod +x "$HERMIT_TMP_DIR/hermit" + export PATH="$HERMIT_TMP_DIR:$PATH" + HERMIT_CLEANUP_DIR="/tmp/hermit_tmp_$$" + fi + + # Initialize hermit + log "Initializing hermit." + hermit init >> "$LOG_FILE" + + # Clean up temp dir if it was created + if [[ -n "${HERMIT_CLEANUP_DIR:-}" ]]; then + log "Cleaning up temporary hermit binary directory." + rm -rf "$HERMIT_CLEANUP_DIR" + fi +else + log "Hermit environment already initialized. Skipping init." +fi + +# Activate the environment with output redirected to log +if [[ "$(uname -s)" == "Linux" ]]; then + log "Activating hermit environment." + { . bin/activate-hermit; } >> "$LOG_FILE" 2>&1 +fi # Install Node.js using hermit log "Installing Node.js with hermit." From 50df27dc4ddd2fefb9ac57072774bb8d2ff003c3 Mon Sep 17 00:00:00 2001 From: Timothy <1695613+timothyis@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:40:38 +0000 Subject: [PATCH 067/121] Fix 404 for responsible coding guide (#5543) Merging because it's docs only and fixes a 404 Signed-off-by: fbalicchia --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df5c911c338c..de9bdde7f260 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Designed for maximum flexibility, goose works with any LLM and supports multi-mo - [Installation](https://block.github.io/goose/docs/getting-started/installation) - [Tutorials](https://block.github.io/goose/docs/category/tutorials) - [Documentation](https://block.github.io/goose/docs/category/getting-started) -- [Responsible AI-Assisted Coding Guide](https://github.com/block/goose/blob/main/ai-assisted-coding-guide.md) +- [Responsible AI-Assisted Coding Guide](https://github.com/block/goose/blob/main/HOWTOAI.md) - [Governance](https://github.com/block/goose/blob/main/GOVERNANCE.md) ## Need Help? From 22fba69ba461faa6022dcab9da7712883a82917b Mon Sep 17 00:00:00 2001 From: Sheikh Limon Date: Mon, 3 Nov 2025 23:55:38 +0600 Subject: [PATCH 068/121] fix: update Husky prepare script to v9 format (#5522) Signed-off-by: sheikhlimon Signed-off-by: fbalicchia --- ui/desktop/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/package.json b/ui/desktop/package.json index ee19c0290888..3bd202413df0 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -35,7 +35,7 @@ "test:run": "vitest run", "test:ui": "vitest --ui", "test:coverage": "vitest run --coverage", - "prepare": "cd ../.. && husky install", + "prepare": "husky", "start-alpha-gui": "ALPHA=true npm run start-gui" }, "dependencies": { From c2fa151ec41f15a114d0ec8f71d4e4353d22c6ac Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 13:23:33 -0500 Subject: [PATCH 069/121] fix: do not build unsigned desktop app bundles on every PR in ci. add manual option. (#5550) Signed-off-by: fbalicchia --- .github/workflows/bundle-desktop-manual.yml | 19 +++++++++++++++++++ .github/workflows/bundle-desktop.yml | 1 + .github/workflows/ci.yml | 11 +---------- 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/bundle-desktop-manual.yml diff --git a/.github/workflows/bundle-desktop-manual.yml b/.github/workflows/bundle-desktop-manual.yml new file mode 100644 index 000000000000..f2943e8d6637 --- /dev/null +++ b/.github/workflows/bundle-desktop-manual.yml @@ -0,0 +1,19 @@ +name: Manual Desktop Bundle (Unsigned) + +on: + workflow_dispatch: + inputs: + branch: + description: 'Branch name to bundle app from' + required: true + type: string + +jobs: + bundle-desktop-unsigned: + uses: ./.github/workflows/bundle-desktop.yml + permissions: + id-token: write + contents: read + with: + signing: false + ref: ${{ inputs.branch }} diff --git a/.github/workflows/bundle-desktop.yml b/.github/workflows/bundle-desktop.yml index 8995eb92c6d1..978242a621bd 100644 --- a/.github/workflows/bundle-desktop.yml +++ b/.github/workflows/bundle-desktop.yml @@ -3,6 +3,7 @@ # - release.yml # - canary.yml # - pr-comment-bundle-desktop.yml +# - bundle-desktop-manual.yml on: workflow_call: inputs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 172b02d30e0d..4242db371883 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,13 +131,4 @@ jobs: run: source ../../bin/activate-hermit && npm run test:run working-directory: ui/desktop - # Faster Desktop App build for PRs only - bundle-desktop-unsigned: - uses: ./.github/workflows/bundle-desktop.yml - permissions: - id-token: write - contents: read - needs: changes - if: (github.event_name == 'pull_request' || github.event_name == 'merge_group') && (needs.changes.outputs.code == 'true' || github.event_name != 'pull_request') - with: - signing: false + From 0c08b4779c5d75bb5fc3d70062f5828ba60bb80d Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 14:33:49 -0500 Subject: [PATCH 070/121] fix: remove qwen3-coder from provider/mcp smoke tests (#5551) Signed-off-by: fbalicchia --- scripts/test_mcp.sh | 2 +- scripts/test_providers.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test_mcp.sh b/scripts/test_mcp.sh index 44201d258c99..ae5c93c62445 100755 --- a/scripts/test_mcp.sh +++ b/scripts/test_mcp.sh @@ -20,7 +20,7 @@ JUDGE_MODEL=${GOOSE_JUDGE_MODEL:-google/gemini-2.5-flash} PROVIDERS=( "anthropic:claude-haiku-4-5-20251001" "google:gemini-2.5-flash" - "openrouter:qwen/qwen3-coder" + "openrouter:google/gemini-2.5-flash" "openai:gpt-5-mini" ) diff --git a/scripts/test_providers.sh b/scripts/test_providers.sh index 6ca15928ad91..d710ebdc8a9d 100755 --- a/scripts/test_providers.sh +++ b/scripts/test_providers.sh @@ -15,7 +15,7 @@ fi SCRIPT_DIR=$(pwd) PROVIDERS=( - "openrouter:google/gemini-2.5-pro:google/gemini-2.5-flash:anthropic/claude-sonnet-4.5:qwen/qwen3-coder" + "openrouter:google/gemini-2.5-pro:google/gemini-2.5-flash:anthropic/claude-sonnet-4.5" "openai:gpt-4o:gpt-4o-mini:gpt-3.5-turbo:gpt-5" "anthropic:claude-sonnet-4-5-20250929:claude-opus-4-1-20250805" "google:gemini-2.5-pro:gemini-2.5-flash" From 90215c51807ff10dd43018e79949ed40fccb1c63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:09:29 -0500 Subject: [PATCH 071/121] chore(deps): bump prismjs and react-syntax-highlighter in /ui/desktop (#5549) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: fbalicchia --- ui/desktop/package-lock.json | 257 +++++++---------------------------- ui/desktop/package.json | 2 +- 2 files changed, 47 insertions(+), 212 deletions(-) diff --git a/ui/desktop/package-lock.json b/ui/desktop/package-lock.json index 008375acf13a..67ee1410849a 100644 --- a/ui/desktop/package-lock.json +++ b/ui/desktop/package-lock.json @@ -46,7 +46,7 @@ "react-markdown": "^10.1.0", "react-router-dom": "^7.9.4", "react-select": "^5.10.2", - "react-syntax-highlighter": "^15.6.6", + "react-syntax-highlighter": "^16.1.0", "react-toastify": "^11.0.5", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", @@ -328,7 +328,6 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -698,7 +697,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -745,7 +743,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1185,7 +1182,6 @@ "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", @@ -2735,7 +2731,6 @@ "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^3.0.1", "@inquirer/confirm": "^4.0.1", @@ -5965,7 +5960,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -6254,7 +6250,6 @@ "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -6265,6 +6260,12 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "license": "MIT" }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "license": "MIT" + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -6290,7 +6291,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -6301,7 +6301,6 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6448,7 +6447,6 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -6850,7 +6848,6 @@ "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", @@ -7100,7 +7097,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7740,7 +7736,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -9076,7 +9071,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -9134,7 +9130,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", @@ -10150,7 +10145,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -10610,7 +10604,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -11664,10 +11657,13 @@ } }, "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -11714,70 +11710,22 @@ } }, "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hastscript/node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/hastscript/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" - }, - "node_modules/hastscript/node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hastscript/node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -12871,7 +12819,6 @@ "integrity": "sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@asamuzakjp/dom-selector": "^6.7.2", "cssstyle": "^5.3.1", @@ -14096,6 +14043,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -14116,7 +14064,6 @@ "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", @@ -16491,7 +16438,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -16580,6 +16526,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -16595,6 +16542,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -16911,7 +16859,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16921,7 +16868,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -16943,7 +16889,8 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/react-markdown": { "version": "10.1.0", @@ -17120,17 +17067,20 @@ } }, "node_modules/react-syntax-highlighter": { - "version": "15.6.6", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.6.tgz", - "integrity": "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.0.tgz", + "integrity": "sha512-E40/hBiP5rCNwkeBN1vRP+xow1X0pndinO+z3h7HLsHyjztbyjfzNWNKuAsJj+7DLam9iT4AaaOZnueCU+Nplg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.3.1", + "@babel/runtime": "^7.28.4", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", - "refractor": "^3.6.0" + "refractor": "^5.0.0" + }, + "engines": { + "node": ">= 16.20.2" }, "peerDependencies": { "react": ">= 0.14.0" @@ -17363,121 +17313,21 @@ } }, "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", - "license": "MIT", - "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz", + "integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==", "license": "MIT", "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@types/hast": "^3.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^9.0.0", + "parse-entities": "^4.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/refractor/node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -17989,7 +17839,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -18983,8 +18832,7 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.15.tgz", "integrity": "sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -19603,7 +19451,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -19989,7 +19836,6 @@ "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -20103,7 +19949,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -20669,15 +20514,6 @@ "dev": true, "license": "MIT" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -20818,7 +20654,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 3bd202413df0..5f946457aadb 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -76,7 +76,7 @@ "react-markdown": "^10.1.0", "react-router-dom": "^7.9.4", "react-select": "^5.10.2", - "react-syntax-highlighter": "^15.6.6", + "react-syntax-highlighter": "^16.1.0", "react-toastify": "^11.0.5", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", From 3cf9a95dbf5cc667e0bf780fca9bde81b480c460 Mon Sep 17 00:00:00 2001 From: David Katz Date: Mon, 3 Nov 2025 16:27:12 -0500 Subject: [PATCH 072/121] Manual compaction counting fix + cli cleanup (#5480) Signed-off-by: fbalicchia --- crates/goose-cli/src/session/input.rs | 24 +++----- crates/goose-cli/src/session/mod.rs | 82 +++----------------------- crates/goose/src/agents/agent.rs | 12 ++-- crates/goose/src/agents/mod.rs | 2 +- crates/goose/src/agents/reply_parts.rs | 19 +++++- crates/goose/src/context_mgmt/mod.rs | 34 ++--------- 6 files changed, 46 insertions(+), 127 deletions(-) diff --git a/crates/goose-cli/src/session/input.rs b/crates/goose-cli/src/session/input.rs index 987415d1251f..081be75f9862 100644 --- a/crates/goose-cli/src/session/input.rs +++ b/crates/goose-cli/src/session/input.rs @@ -20,7 +20,7 @@ pub enum InputResult { EndPlan, Clear, Recipe(Option), - Summarize, + Compact, } #[derive(Debug)] @@ -120,7 +120,8 @@ fn handle_slash_command(input: &str) -> Option { const CMD_ENDPLAN: &str = "/endplan"; const CMD_CLEAR: &str = "/clear"; const CMD_RECIPE: &str = "/recipe"; - const CMD_SUMMARIZE: &str = "/summarize"; + const CMD_COMPACT: &str = "/compact"; + const CMD_SUMMARIZE_DEPRECATED: &str = "/summarize"; match input { "/exit" | "/quit" => Some(InputResult::Exit), @@ -180,7 +181,11 @@ fn handle_slash_command(input: &str) -> Option { s if s == CMD_ENDPLAN => Some(InputResult::EndPlan), s if s == CMD_CLEAR => Some(InputResult::Clear), s if s.starts_with(CMD_RECIPE) => parse_recipe_command(s), - s if s == CMD_SUMMARIZE => Some(InputResult::Summarize), + s if s == CMD_COMPACT => Some(InputResult::Compact), + s if s == CMD_SUMMARIZE_DEPRECATED => { + println!("{}", console::style("⚠️ Note: /summarize has been renamed to /compact and will be removed in a future release.").yellow()); + Some(InputResult::Compact) + } _ => None, } } @@ -305,7 +310,7 @@ fn print_help() { /endplan - Exit plan mode and return to 'normal' goose mode. /recipe [filepath] - Generate a recipe from the current conversation and save it to the specified filepath (must end with .yaml). If no filepath is provided, it will be saved to ./recipe.yaml. -/summarize - Summarize the current conversation to reduce context length while preserving key information. +/compact - Compact the current conversation to reduce context length while preserving key information. /? or /help - Display this help message /clear - Clears the current chat history @@ -541,17 +546,6 @@ mod tests { assert!(matches!(result, Some(InputResult::Retry))); } - #[test] - fn test_summarize_command() { - // Test the summarize command - let result = handle_slash_command("/summarize"); - assert!(matches!(result, Some(InputResult::Summarize))); - - // Test with whitespace - let result = handle_slash_command(" /summarize "); - assert!(matches!(result, Some(InputResult::Summarize))); - } - #[test] fn test_get_input_prompt_string() { let prompt = get_input_prompt_string(); diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index 529fff3a1fa7..bed33e87fa9c 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -28,7 +28,7 @@ use anyhow::{Context, Result}; use completion::GooseCompleter; use goose::agents::extension::{Envs, ExtensionConfig}; use goose::agents::types::RetryConfig; -use goose::agents::{Agent, SessionConfig}; +use goose::agents::{Agent, SessionConfig, MANUAL_COMPACT_TRIGGER}; use goose::config::{Config, GooseMode}; use goose::providers::pricing::initialize_pricing_cache; use goose::session::SessionManager; @@ -641,16 +641,16 @@ impl CliSession { continue; } - InputResult::Summarize => { + InputResult::Compact => { save_history(&mut editor); - let prompt = "Are you sure you want to summarize this conversation? This will condense the message history."; + let prompt = "Are you sure you want to compact this conversation? This will condense the message history."; let should_summarize = match cliclack::confirm(prompt).initial_value(true).interact() { Ok(choice) => choice, Err(e) => { if e.kind() == std::io::ErrorKind::Interrupted { - false // If interrupted, set should_summarize to false + false } else { return Err(e.into()); } @@ -658,81 +658,13 @@ impl CliSession { }; if should_summarize { - println!("{}", console::style("Summarizing conversation...").yellow()); + self.push_message(Message::user().with_text(MANUAL_COMPACT_TRIGGER)); output::show_thinking(); - - let (summarized_messages, _token_counts, summarization_usage) = - goose::context_mgmt::compact_messages( - &self.agent, - &self.messages, - false, - ) + self.process_agent_response(true, CancellationToken::default()) .await?; - - // Update the session messages with the summarized ones - self.messages = summarized_messages.clone(); - - // Persist the summarized messages and update session metadata - if let Some(session_id) = &self.session_id { - // Replace all messages with the summarized version - SessionManager::replace_conversation(session_id, &summarized_messages) - .await?; - - // Update session metadata with the new token counts from summarization - if let Some(usage) = summarization_usage { - let session = - SessionManager::get_session(session_id, false).await?; - - // Update token counts with the summarization usage - let summary_tokens = usage.usage.output_tokens.unwrap_or(0); - - // Update accumulated tokens (add the summarization cost) - let accumulate = |a: Option, b: Option| -> Option { - match (a, b) { - (Some(x), Some(y)) => Some(x + y), - _ => a.or(b), - } - }; - - let accumulated_total = accumulate( - session.accumulated_total_tokens, - usage.usage.total_tokens, - ); - let accumulated_input = accumulate( - session.accumulated_input_tokens, - usage.usage.input_tokens, - ); - let accumulated_output = accumulate( - session.accumulated_output_tokens, - usage.usage.output_tokens, - ); - - SessionManager::update_session(session_id) - .total_tokens(Some(summary_tokens)) - .input_tokens(None) - .output_tokens(Some(summary_tokens)) - .accumulated_total_tokens(accumulated_total) - .accumulated_input_tokens(accumulated_input) - .accumulated_output_tokens(accumulated_output) - .apply() - .await?; - } - } - output::hide_thinking(); - println!( - "{}", - console::style("Conversation has been summarized.").green() - ); - println!( - "{}", - console::style( - "Key information has been preserved while reducing context length." - ) - .green() - ); } else { - println!("{}", console::style("Summarization cancelled.").yellow()); + println!("{}", console::style("Compaction cancelled.").yellow()); } continue; } diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 444c7666f13a..f958397046c3 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -65,7 +65,7 @@ use crate::session::SessionManager; const DEFAULT_MAX_TURNS: u32 = 1000; const COMPACTION_THINKING_TEXT: &str = "goose is compacting the conversation..."; -const MANUAL_COMPACT_TRIGGER: &str = "Please compact this conversation"; +pub const MANUAL_COMPACT_TRIGGER: &str = "Please compact this conversation"; /// Context needed for the reply function pub struct ReplyContext { @@ -803,9 +803,10 @@ impl Agent { ); match crate::context_mgmt::compact_messages(self, &conversation_to_compact, false).await { - Ok((compacted_conversation, _token_counts, _summarization_usage)) => { + Ok((compacted_conversation, summarization_usage)) => { if let Some(session_to_store) = &session { SessionManager::replace_conversation(&session_to_store.id, &compacted_conversation).await?; + Self::update_session_metrics(session_to_store, &summarization_usage, true).await?; } yield AgentEvent::HistoryReplaced(compacted_conversation.clone()); @@ -991,7 +992,7 @@ impl Agent { // Record usage for the session if let Some(ref session_config) = &session { if let Some(ref usage) = usage { - Self::update_session_metrics(session_config, usage).await?; + Self::update_session_metrics(session_config, usage, false).await?; } } @@ -1166,9 +1167,10 @@ impl Agent { ); match crate::context_mgmt::compact_messages(self, &conversation, true).await { - Ok((compacted_conversation, _token_counts, _usage)) => { + Ok((compacted_conversation, usage)) => { if let Some(session_to_store) = &session { - SessionManager::replace_conversation(&session_to_store.id, &compacted_conversation).await? + SessionManager::replace_conversation(&session_to_store.id, &compacted_conversation).await?; + Self::update_session_metrics(session_to_store, &usage, true).await?; } conversation = compacted_conversation; diff --git a/crates/goose/src/agents/mod.rs b/crates/goose/src/agents/mod.rs index 5fa9f0ce109c..0f633307c747 100644 --- a/crates/goose/src/agents/mod.rs +++ b/crates/goose/src/agents/mod.rs @@ -26,7 +26,7 @@ mod tool_route_manager; mod tool_router_index_manager; pub mod types; -pub use agent::{Agent, AgentEvent}; +pub use agent::{Agent, AgentEvent, MANUAL_COMPACT_TRIGGER}; pub use extension::ExtensionConfig; pub use extension_manager::ExtensionManager; pub use prompt_manager::PromptManager; diff --git a/crates/goose/src/agents/reply_parts.rs b/crates/goose/src/agents/reply_parts.rs index 1d8fdaea06b4..86cb8095c472 100644 --- a/crates/goose/src/agents/reply_parts.rs +++ b/crates/goose/src/agents/reply_parts.rs @@ -255,6 +255,7 @@ impl Agent { pub(crate) async fn update_session_metrics( session_config: &crate::agents::types::SessionConfig, usage: &ProviderUsage, + is_compaction_usage: bool, ) -> Result<()> { let session_id = session_config.id.as_str(); let session = SessionManager::get_session(session_id, false).await?; @@ -273,11 +274,23 @@ impl Agent { let accumulated_output = accumulate(session.accumulated_output_tokens, usage.usage.output_tokens); + let (current_total, current_input, current_output) = if is_compaction_usage { + // After compaction: summary output becomes new input context + let new_input = usage.usage.output_tokens; + (new_input, new_input, None) + } else { + ( + usage.usage.total_tokens, + usage.usage.input_tokens, + usage.usage.output_tokens, + ) + }; + SessionManager::update_session(session_id) .schedule_id(session_config.schedule_id.clone()) - .total_tokens(usage.usage.total_tokens) - .input_tokens(usage.usage.input_tokens) - .output_tokens(usage.usage.output_tokens) + .total_tokens(current_total) + .input_tokens(current_input) + .output_tokens(current_output) .accumulated_total_tokens(accumulated_total) .accumulated_input_tokens(accumulated_input) .accumulated_output_tokens(accumulated_output) diff --git a/crates/goose/src/context_mgmt/mod.rs b/crates/goose/src/context_mgmt/mod.rs index 03b2871b017e..57e43a706a75 100644 --- a/crates/goose/src/context_mgmt/mod.rs +++ b/crates/goose/src/context_mgmt/mod.rs @@ -31,13 +31,12 @@ struct SummarizeContext { /// # Returns /// * A tuple containing: /// - `Conversation`: The compacted messages -/// - `Vec`: Token counts for each message -/// - `Option`: Provider usage from summarization +/// - `ProviderUsage`: Provider usage from summarization pub async fn compact_messages( agent: &Agent, conversation: &Conversation, preserve_last_user_message: bool, -) -> Result<(Conversation, Vec, Option)> { +) -> Result<(Conversation, ProviderUsage)> { info!("Performing message compaction"); let messages = conversation.messages(); @@ -99,16 +98,8 @@ pub async fn compact_messages( }; let provider = agent.provider().await?; - let summary = do_compact(provider.clone(), messages_to_compact).await?; - - let (summary_message, summarization_usage) = match summary { - Some((summary_message, provider_usage)) => (summary_message, Some(provider_usage)), - None => { - // No summary was generated (empty input) - tracing::warn!("Summarization failed. Returning empty messages."); - return Ok((Conversation::empty(), vec![], None)); - } - }; + let (summary_message, summarization_usage) = + do_compact(provider.clone(), messages_to_compact).await?; // Create the final message list with updated visibility metadata: // 1. Original messages become user_visible but not agent_visible @@ -116,27 +107,17 @@ pub async fn compact_messages( // 3. Assistant messages to continue the conversation remain both user_visible and agent_visible let mut final_messages = Vec::new(); - let mut final_token_counts = Vec::new(); // Add all original messages with updated visibility (preserve user_visible, set agent_visible=false) for msg in messages_to_compact.iter().cloned() { let updated_metadata = msg.metadata.with_agent_invisible(); let updated_msg = msg.with_metadata(updated_metadata); final_messages.push(updated_msg); - // Token count doesn't matter for agent_visible=false messages, but we'll use 0 - final_token_counts.push(0); } // Add the summary message (agent_visible=true, user_visible=false) let summary_msg = summary_message.with_metadata(MessageMetadata::agent_only()); - // For token counting purposes, we use the output tokens (the actual summary content) - // since that's what will be in the context going forward - let summary_tokens = summarization_usage - .as_ref() - .and_then(|usage| usage.usage.output_tokens) - .unwrap_or(0) as usize; final_messages.push(summary_msg); - final_token_counts.push(summary_tokens); // Add an assistant message to continue the conversation (agent_visible=true, user_visible=false) let assistant_message = Message::assistant() @@ -146,9 +127,7 @@ Do not mention that you read a summary or that conversation summarization occurr Just continue the conversation naturally based on the summarized context" ) .with_metadata(MessageMetadata::agent_only()); - let assistant_message_tokens: usize = 0; // Not counted since it's for agent context only final_messages.push(assistant_message); - final_token_counts.push(assistant_message_tokens); // Add back the preserved user message if it exists if let Some(user_text) = preserved_user_text { @@ -157,7 +136,6 @@ Just continue the conversation naturally based on the summarized context" Ok(( Conversation::new_unvalidated(final_messages), - final_token_counts, summarization_usage, )) } @@ -222,7 +200,7 @@ pub async fn check_if_compaction_needed( async fn do_compact( provider: Arc, messages: &[Message], -) -> Result, anyhow::Error> { +) -> Result<(Message, ProviderUsage), anyhow::Error> { let agent_visible_messages: Vec<&Message> = messages .iter() .filter(|msg| msg.is_agent_visible()) @@ -255,7 +233,7 @@ async fn do_compact( .await .map_err(|e| anyhow::anyhow!("Failed to ensure usage tokens: {}", e))?; - Ok(Some((response, provider_usage))) + Ok((response, provider_usage)) } fn format_message_for_compacting(msg: &Message) -> String { From 83789e0a3a7dbed2a60e9cda5e075f175b5c2811 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 16:46:22 -0500 Subject: [PATCH 073/121] cli: adjust default theme to address #1905 (#5552) Signed-off-by: fbalicchia --- crates/goose-cli/src/session/mod.rs | 8 ++++---- crates/goose-cli/src/session/output.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index bed33e87fa9c..a8f5ce06c1b0 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -495,6 +495,10 @@ impl CliSession { let current = output::get_theme(); let new_theme = match current { + output::Theme::Ansi => { + println!("Switching to Light theme"); + output::Theme::Light + } output::Theme::Light => { println!("Switching to Dark theme"); output::Theme::Dark @@ -503,10 +507,6 @@ impl CliSession { println!("Switching to Ansi theme"); output::Theme::Ansi } - output::Theme::Ansi => { - println!("Switching to Light theme"); - output::Theme::Light - } }; output::set_theme(new_theme); continue; diff --git a/crates/goose-cli/src/session/output.rs b/crates/goose-cli/src/session/output.rs index 7b115ff90a2c..14b598e3b638 100644 --- a/crates/goose-cli/src/session/output.rs +++ b/crates/goose-cli/src/session/output.rs @@ -60,7 +60,7 @@ thread_local! { .unwrap_or_else(|| Config::global().get_param::("GOOSE_CLI_THEME").ok() .map(|val| Theme::from_config_str(&val)) - .unwrap_or(Theme::Dark) + .unwrap_or(Theme::Ansi) ) ); } From cf6a1ebffb2835345bd2cfc003470307c3c0052e Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 17:03:15 -0500 Subject: [PATCH 074/121] chore: remove yarn usage from documentation (#5555) Signed-off-by: fbalicchia --- documentation/.gitignore | 2 - documentation/README.md | 10 +- documentation/package-lock.json | 5982 +++++++++++--------- documentation/package.json | 6 +- documentation/yarn.lock | 9377 ------------------------------- 5 files changed, 3347 insertions(+), 12030 deletions(-) delete mode 100644 documentation/yarn.lock diff --git a/documentation/.gitignore b/documentation/.gitignore index 70973d918f6f..83d108cffde3 100644 --- a/documentation/.gitignore +++ b/documentation/.gitignore @@ -16,5 +16,3 @@ .env.production.local npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/documentation/README.md b/documentation/README.md index 9edbce8a6761..d9b319730058 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -5,13 +5,13 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati ### Installation ``` -$ yarn +$ npm i ``` ### Local Development ``` -$ yarn start +$ npm run start ``` This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. @@ -19,7 +19,7 @@ This command starts a local development server and opens up a browser window. Mo ### Build ``` -$ yarn build +$ npm run build ``` This command generates static content into the `build` directory and can be served using any static contents hosting service. @@ -29,13 +29,13 @@ This command generates static content into the `build` directory and can be serv Using SSH: ``` -$ USE_SSH=true yarn deploy +$ USE_SSH=true npm run deploy ``` Not using SSH: ``` -$ GIT_USER= yarn deploy +$ GIT_USER= npm run deploy ``` If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/documentation/package-lock.json b/documentation/package-lock.json index d6f0b6ccf135..cb0412efe636 100644 --- a/documentation/package-lock.json +++ b/documentation/package-lock.json @@ -8,9 +8,9 @@ "name": "goose", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/plugin-client-redirects": "^3.7.0", - "@docusaurus/preset-classic": "3.7.0", + "@docusaurus/core": "^3.9.2", + "@docusaurus/plugin-client-redirects": "^3.9.2", + "@docusaurus/preset-classic": "^3.9.2", "@inkeep/docusaurus": "^2.0.16", "@mdx-js/react": "^3.0.0", "autoprefixer": "^10.4.17", @@ -27,7 +27,8 @@ "react-markdown": "^10.1.0", "swiper": "^11.2.6", "tailwind-merge": "^3.0.2", - "tailwindcss": "^3.4.1" + "tailwindcss": "^3.4.1", + "turndown": "^7.2.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.7.0", @@ -41,45 +42,117 @@ "node": ">=18.0" } }, - "node_modules/@algolia/autocomplete-core": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", - "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", - "license": "MIT", + "node_modules/@ai-sdk/gateway": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.5.tgz", + "integrity": "sha512-5TTDSl0USWY6YGnb4QmJGplFZhk+p9OT7hZevAaER6OGiZ17LB1GypsGYDpNo/MiVMklk8kX4gk6p1/R/EiJ8Q==", + "license": "Apache-2.0", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", - "@algolia/autocomplete-shared": "1.17.9" + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.15", + "@vercel/oidc": "3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", - "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", - "license": "MIT", + "node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.15.tgz", + "integrity": "sha512-kOc6Pxb7CsRlNt+sLZKL7/VGQUd7ccl3/tIK+Bqf5/QhHR0Qm3qRBMz1IwU1RmjJEZA73x+KB5cUckbDl2WF7Q==", + "license": "Apache-2.0", "dependencies": { - "@algolia/autocomplete-shared": "1.17.9" + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "search-insights": ">= 1 < 3" + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/react": { + "version": "2.0.86", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.86.tgz", + "integrity": "sha512-vqxbbMOKMpYFHZy0aYEO4jtDcKaFCHL/rEtTqAIDlH14GT0uusSjN99gkDHHG3EnbyJSQmk9gqtqbd1GDwlRRg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider-utils": "3.0.15", + "ai": "5.0.86", + "swr": "^2.2.5", + "throttleit": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "zod": "^3.25.76 || ^4.1.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.8.0.tgz", + "integrity": "sha512-Hb4BkGNnvgCj3F9XzqjiFTpA5IGkjOXwGAOV13qtc27l2qNF8X9rzSp1H5hu8XewlC0DzYtQtZZIOYzRZDyuXg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" } }, - "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", - "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.17.9" + "@algolia/autocomplete-shared": "1.19.2" }, "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" + "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", - "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", "license": "MIT", "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -87,99 +160,100 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.20.0.tgz", - "integrity": "sha512-YaEoNc1Xf2Yk6oCfXXkZ4+dIPLulCx8Ivqj0OsdkHWnsI3aOJChY5qsfyHhDBNSOhqn2ilgHWxSfyZrjxBcAww==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.42.0.tgz", + "integrity": "sha512-JLyyG7bb7XOda+w/sp8ch7rEVy6LnWs3qtxr6VJJ2XIINqGsY6U+0L3aJ6QFliBRNUeEAr2QBDxSm8u9Sal5uA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.20.0.tgz", - "integrity": "sha512-CIT9ni0+5sYwqehw+t5cesjho3ugKQjPVy/iPiJvtJX4g8Cdb6je6SPt2uX72cf2ISiXCAX9U3cY0nN0efnRDw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.42.0.tgz", + "integrity": "sha512-SkCrvtZpdSWjNq9NGu/TtOg4TbzRuUToXlQqV6lLePa2s/WQlEyFw7QYjrz4itprWG9ASuH+StDlq7n49F2sBA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.20.0.tgz", - "integrity": "sha512-iSTFT3IU8KNpbAHcBUJw2HUrPnMXeXLyGajmCL7gIzWOsYM4GabZDHXOFx93WGiXMti1dymz8k8R+bfHv1YZmA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.42.0.tgz", + "integrity": "sha512-6iiFbm2tRn6B2OqFv9XDTcw5LdWPudiJWIbRk+fsTX+hkPrPm4e1/SbU+lEYBciPoaTShLkDbRge4UePEyCPMQ==", "license": "MIT", "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.20.0.tgz", - "integrity": "sha512-w9RIojD45z1csvW1vZmAko82fqE/Dm+Ovsy2ElTsjFDB0HMAiLh2FO86hMHbEXDPz6GhHKgGNmBRiRP8dDPgJg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.42.0.tgz", + "integrity": "sha512-iEokmw2k6FBa8g/TT7ClyEriaP/FUEmz3iczRoCklEHWSgoABMkaeYrxRXrA2yx76AN+gyZoC8FX0iCJ55dsOg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.20.0.tgz", - "integrity": "sha512-p/hftHhrbiHaEcxubYOzqVV4gUqYWLpTwK+nl2xN3eTrSW9SNuFlAvUBFqPXSVBqc6J5XL9dNKn3y8OA1KElSQ==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.42.0.tgz", + "integrity": "sha512-ivVniRqX2ARd+jGvRHTxpWeOtO9VT+rK+OmiuRgkSunoTyxk0vjeDO7QkU7+lzBOXiYgakNjkZrBtIpW9c+muw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.20.0.tgz", - "integrity": "sha512-m4aAuis5vZi7P4gTfiEs6YPrk/9hNTESj3gEmGFgfJw3hO2ubdS4jSId1URd6dGdt0ax2QuapXufcrN58hPUcw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.42.0.tgz", + "integrity": "sha512-9+BIw6rerUfA+eLMIS2lF4mgoeBGTCIHiqb35PLn3699Rm3CaJXz03hChdwAWcA6SwGw0haYXYJa7LF0xI6EpA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.20.0.tgz", - "integrity": "sha512-KL1zWTzrlN4MSiaK1ea560iCA/UewMbS4ZsLQRPoDTWyrbDKVbztkPwwv764LAqgXk0fvkNZvJ3IelcK7DqhjQ==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.42.0.tgz", + "integrity": "sha512-NZR7yyHj2WzK6D5X8gn+/KOxPdzYEXOqVdSaK/biU8QfYUpUuEA0sCWg/XlO05tPVEcJelF/oLrrNY3UjRbOww==", "license": "MIT", + "peer": true, "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" @@ -192,81 +266,81 @@ "license": "MIT" }, "node_modules/@algolia/ingestion": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.20.0.tgz", - "integrity": "sha512-shj2lTdzl9un4XJblrgqg54DoK6JeKFO8K8qInMu4XhE2JuB8De6PUuXAQwiRigZupbI0xq8aM0LKdc9+qiLQA==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.42.0.tgz", + "integrity": "sha512-MBkjRymf4BT6VOvMpJlg6kq8K+PkH9q+N+K4YMNdzTXlL40YwOa1wIWQ5LxP/Jhlz64kW5g9/oaMWY06Sy9dcw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.20.0.tgz", - "integrity": "sha512-aF9blPwOhKtWvkjyyXh9P5peqmhCA1XxLBRgItT+K6pbT0q4hBDQrCid+pQZJYy4HFUKjB/NDDwyzFhj/rwKhw==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.42.0.tgz", + "integrity": "sha512-kmLs7YfjT4cpr4FnhhRmnoSX4psh9KYZ9NAiWt/YcUV33m0B/Os5L4QId30zVXkOqAPAEpV5VbDPWep+/aoJdQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.20.0.tgz", - "integrity": "sha512-T6B/WPdZR3b89/F9Vvk6QCbt/wrLAtrGoL8z4qPXDFApQ8MuTFWbleN/4rHn6APWO3ps+BUePIEbue2rY5MlRw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.42.0.tgz", + "integrity": "sha512-U5yZ8+Jj+A4ZC0IMfElpPcddQ9NCoawD1dKyWmjHP49nzN2Z4284IFVMAJWR6fq/0ddGf4OMjjYO9cnF8L+5tw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "@algolia/client-common": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.20.0.tgz", - "integrity": "sha512-t6//lXsq8E85JMenHrI6mhViipUT5riNhEfCcvtRsTV+KIBpC6Od18eK864dmBhoc5MubM0f+sGpKOqJIlBSCg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.42.0.tgz", + "integrity": "sha512-EbuxgteaYBlKgc2Fs3JzoPIKAIaevAIwmv1F+fakaEXeibG4pkmVNsyTUjpOZIgJ1kXeqNvDrcjRb6g3vYBJ9A==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0" + "@algolia/client-common": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.20.0.tgz", - "integrity": "sha512-FHxYGqRY+6bgjKsK4aUsTAg6xMs2S21elPe4Y50GB0Y041ihvw41Vlwy2QS6K9ldoftX4JvXodbKTcmuQxywdQ==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.42.0.tgz", + "integrity": "sha512-4vnFvY5Q8QZL9eDNkywFLsk/eQCRBXCBpE8HWs8iUsFNHYoamiOxAeYMin0W/nszQj6abc+jNxMChHmejO+ftQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0" + "@algolia/client-common": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.20.0.tgz", - "integrity": "sha512-kmtQClq/w3vtPteDSPvaW9SPZL/xrIgMrxZyAgsFwrJk0vJxqyC5/hwHmrCraDnStnGSADnLpBf4SpZnwnkwWw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.42.0.tgz", + "integrity": "sha512-gkLNpU+b1pCIwk1hKTJz2NWQPT8gsfGhQasnZ5QVv4jd79fKRL/1ikd86P0AzuIQs9tbbhlMwxsSTyJmlq502w==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.20.0" + "@algolia/client-common": "5.42.0" }, "engines": { "node": ">= 14.0.0" @@ -284,58 +358,46 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", - "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "license": "MIT", + "peer": true, + "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/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.1.0", "gensync": "^1.0.0-beta.2", @@ -360,15 +422,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", - "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.5", - "@babel/types": "^7.26.5", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -376,25 +438,25 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -413,17 +475,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@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/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "engines": { @@ -443,13 +505,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", - "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "regexpu-core": "^6.2.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "engines": { @@ -469,56 +531,65 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", - "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -528,35 +599,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-wrap-function": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -566,14 +637,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -583,79 +654,79 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -665,13 +736,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", - "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -681,12 +752,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", - "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -696,12 +767,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", - "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -711,14 +782,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -728,13 +799,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", - "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -768,12 +839,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", - "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -783,12 +854,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -798,12 +869,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -813,12 +884,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -844,12 +915,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -859,14 +930,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", - "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -876,14 +947,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -893,12 +964,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", - "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -908,12 +979,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -923,13 +994,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", - "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -939,13 +1010,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", - "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -955,17 +1026,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", - "globals": "^11.1.0" + "@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/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -975,13 +1046,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -991,12 +1062,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1006,13 +1078,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1022,12 +1094,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1037,13 +1109,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1053,12 +1125,28 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", - "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1068,12 +1156,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1083,12 +1171,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", - "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1098,13 +1186,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", - "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1114,14 +1202,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1131,12 +1219,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", - "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1146,12 +1234,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1161,12 +1249,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", - "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1176,12 +1264,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1191,13 +1279,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1207,13 +1295,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1223,15 +1311,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1241,13 +1329,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1257,13 +1345,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1273,12 +1361,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1288,12 +1376,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.26.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", - "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1303,12 +1391,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", - "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1318,14 +1406,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", - "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1335,13 +1425,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1351,12 +1441,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", - "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1366,13 +1456,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1382,12 +1472,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1397,13 +1487,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", - "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1413,14 +1503,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", - "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1430,12 +1520,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1445,12 +1535,12 @@ } }, "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz", - "integrity": "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1460,12 +1550,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", - "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1475,16 +1565,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", - "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1494,12 +1584,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", - "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.25.9" + "@babel/plugin-transform-react-jsx": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1509,13 +1599,13 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", - "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1525,13 +1615,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1541,13 +1630,13 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", - "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1557,12 +1646,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1572,16 +1661,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", - "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.5.tgz", + "integrity": "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", - "babel-plugin-polyfill-regenerator": "^0.6.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "engines": { @@ -1601,12 +1690,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1616,13 +1705,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1632,12 +1721,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1647,12 +1736,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", - "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1662,12 +1751,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", - "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1677,16 +1766,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz", - "integrity": "sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", + "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^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" }, "engines": { "node": ">=6.9.0" @@ -1696,12 +1785,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1711,13 +1800,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", - "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1727,13 +1816,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1743,13 +1832,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", - "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1759,79 +1848,80 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^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/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.25.9", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.25.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "engines": { @@ -1865,17 +1955,17 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", - "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-transform-react-display-name": "^7.25.9", - "@babel/plugin-transform-react-jsx": "^7.25.9", - "@babel/plugin-transform-react-jsx-development": "^7.25.9", - "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1885,16 +1975,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", - "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-typescript": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1904,70 +1994,66 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.0.tgz", - "integrity": "sha512-UWjX6t+v+0ckwZ50Y5ShZLnlk95pP5MyW/pon9tiYzl3+18pkTHTFNTKr7rQbfRXPkowt2QAn30o1b6oswszew==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", + "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", "license": "MIT", "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" + "core-js-pure": "^3.43.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz", - "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.5", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.5", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1984,9 +2070,9 @@ } }, "node_modules/@csstools/cascade-layer-name-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz", - "integrity": "sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", + "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", "funding": [ { "type": "github", @@ -2002,14 +2088,14 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/color-helpers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", - "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "funding": [ { "type": "github", @@ -2026,9 +2112,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", - "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", "funding": [ { "type": "github", @@ -2044,14 +2130,14 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", - "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "funding": [ { "type": "github", @@ -2064,21 +2150,21 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.0.1", - "@csstools/css-calc": "^2.1.1" + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" }, "engines": { "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", - "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "funding": [ { "type": "github", @@ -2090,17 +2176,18 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", - "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "funding": [ { "type": "github", @@ -2112,14 +2199,15 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", - "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", "funding": [ { "type": "github", @@ -2135,14 +2223,43 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/postcss-alpha-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", + "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, "node_modules/@csstools/postcss-cascade-layers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz", - "integrity": "sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", "funding": [ { "type": "github", @@ -2188,10 +2305,11 @@ } }, "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2201,9 +2319,38 @@ } }, "node_modules/@csstools/postcss-color-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.7.tgz", - "integrity": "sha512-aDHYmhNIHR6iLw4ElWhf+tRqqaXwKnMl0YsQ/X105Zc4dQwe6yJpMrTN6BwOoESrkDjOYMOfORviSSLeDTJkdQ==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", + "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-function-display-p3-linear": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", + "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", "funding": [ { "type": "github", @@ -2216,10 +2363,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2230,9 +2377,38 @@ } }, "node_modules/@csstools/postcss-color-mix-function": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.7.tgz", - "integrity": "sha512-e68Nev4CxZYCLcrfWhHH4u/N1YocOfTmw67/kVX5Rb7rnguqqLyxPjhHWjSBX8o4bmyuukmNf3wrUSU3//kT7g==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", + "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", + "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", "funding": [ { "type": "github", @@ -2245,10 +2421,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2259,9 +2435,37 @@ } }, "node_modules/@csstools/postcss-content-alt-text": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", - "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", + "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-contrast-color-function": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", + "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", "funding": [ { "type": "github", @@ -2274,9 +2478,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2287,9 +2492,9 @@ } }, "node_modules/@csstools/postcss-exponential-functions": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.6.tgz", - "integrity": "sha512-IgJA5DQsQLu/upA3HcdvC6xEMR051ufebBTIXZ5E9/9iiaA7juXWz1ceYj814lnDYP/7eWjZnw0grRJlX4eI6g==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", + "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", "funding": [ { "type": "github", @@ -2302,9 +2507,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -2340,9 +2545,9 @@ } }, "node_modules/@csstools/postcss-gamut-mapping": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.7.tgz", - "integrity": "sha512-gzFEZPoOkY0HqGdyeBXR3JP218Owr683u7KOZazTK7tQZBE8s2yhg06W1tshOqk7R7SWvw9gkw2TQogKpIW8Xw==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", + "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", "funding": [ { "type": "github", @@ -2355,9 +2560,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -2367,9 +2572,9 @@ } }, "node_modules/@csstools/postcss-gradients-interpolation-method": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.7.tgz", - "integrity": "sha512-WgEyBeg6glUeTdS2XT7qeTFBthTJuXlS9GFro/DVomj7W7WMTamAwpoP4oQCq/0Ki2gvfRYFi/uZtmRE14/DFA==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", + "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", "funding": [ { "type": "github", @@ -2382,10 +2587,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2396,9 +2601,9 @@ } }, "node_modules/@csstools/postcss-hwb-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.7.tgz", - "integrity": "sha512-LKYqjO+wGwDCfNIEllessCBWfR4MS/sS1WXO+j00KKyOjm7jDW2L6jzUmqASEiv/kkJO39GcoIOvTTfB3yeBUA==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", + "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", "funding": [ { "type": "github", @@ -2411,10 +2616,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2425,9 +2630,9 @@ } }, "node_modules/@csstools/postcss-ic-unit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", - "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", + "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", "funding": [ { "type": "github", @@ -2440,7 +2645,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, @@ -2452,9 +2657,9 @@ } }, "node_modules/@csstools/postcss-initial": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", - "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", "funding": [ { "type": "github", @@ -2474,9 +2679,9 @@ } }, "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz", - "integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", + "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", "funding": [ { "type": "github", @@ -2522,10 +2727,11 @@ } }, "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2535,9 +2741,9 @@ } }, "node_modules/@csstools/postcss-light-dark-function": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", - "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", + "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", "funding": [ { "type": "github", @@ -2550,9 +2756,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2654,9 +2860,9 @@ } }, "node_modules/@csstools/postcss-logical-viewport-units": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz", - "integrity": "sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", + "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", "funding": [ { "type": "github", @@ -2669,7 +2875,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-tokenizer": "^3.0.3", + "@csstools/css-tokenizer": "^3.0.4", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2680,9 +2886,9 @@ } }, "node_modules/@csstools/postcss-media-minmax": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.6.tgz", - "integrity": "sha512-J1+4Fr2W3pLZsfxkFazK+9kr96LhEYqoeBszLmFjb6AjYs+g9oDAw3J5oQignLKk3rC9XHW+ebPTZ9FaW5u5pg==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", + "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", "funding": [ { "type": "github", @@ -2695,10 +2901,10 @@ ], "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/media-query-list-parser": "^4.0.2" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" }, "engines": { "node": ">=18" @@ -2708,9 +2914,9 @@ } }, "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz", - "integrity": "sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", + "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", "funding": [ { "type": "github", @@ -2723,9 +2929,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/media-query-list-parser": "^4.0.2" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" }, "engines": { "node": ">=18" @@ -2786,9 +2992,9 @@ } }, "node_modules/@csstools/postcss-oklab-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.7.tgz", - "integrity": "sha512-I6WFQIbEKG2IO3vhaMGZDkucbCaUSXMxvHNzDdnfsTCF5tc0UlV3Oe2AhamatQoKFjBi75dSEMrgWq3+RegsOQ==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", + "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", "funding": [ { "type": "github", @@ -2801,10 +3007,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2815,9 +3021,9 @@ } }, "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", - "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", + "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", "funding": [ { "type": "github", @@ -2840,9 +3046,9 @@ } }, "node_modules/@csstools/postcss-random-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.2.tgz", - "integrity": "sha512-vBCT6JvgdEkvRc91NFoNrLjgGtkLWt47GKT6E2UDn3nd8ZkMBiziQ1Md1OiKoSsgzxsSnGKG3RVdhlbdZEkHjA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", + "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", "funding": [ { "type": "github", @@ -2855,9 +3061,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -2867,9 +3073,9 @@ } }, "node_modules/@csstools/postcss-relative-color-syntax": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.7.tgz", - "integrity": "sha512-apbT31vsJVd18MabfPOnE977xgct5B1I+Jpf+Munw3n6kKb1MMuUmGGH+PT9Hm/fFs6fe61Q/EWnkrb4bNoNQw==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", + "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", "funding": [ { "type": "github", @@ -2882,10 +3088,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2921,9 +3127,9 @@ } }, "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2934,9 +3140,9 @@ } }, "node_modules/@csstools/postcss-sign-functions": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.1.tgz", - "integrity": "sha512-MslYkZCeMQDxetNkfmmQYgKCy4c+w9pPDfgOBCJOo/RI1RveEUdZQYtOfrC6cIZB7sD7/PHr2VGOcMXlZawrnA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", + "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", "funding": [ { "type": "github", @@ -2949,9 +3155,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -2961,9 +3167,9 @@ } }, "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.6.tgz", - "integrity": "sha512-/dwlO9w8vfKgiADxpxUbZOWlL5zKoRIsCymYoh1IPuBsXODKanKnfuZRr32DEqT0//3Av1VjfNZU9yhxtEfIeA==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", + "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", "funding": [ { "type": "github", @@ -2976,9 +3182,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -2988,9 +3194,9 @@ } }, "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", - "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", + "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", "funding": [ { "type": "github", @@ -3003,7 +3209,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/color-helpers": "^5.0.1", + "@csstools/color-helpers": "^5.1.0", "postcss-value-parser": "^4.2.0" }, "engines": { @@ -3014,9 +3220,9 @@ } }, "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.6.tgz", - "integrity": "sha512-c4Y1D2Why/PeccaSouXnTt6WcNHJkoJRidV2VW9s5gJ97cNxnLgQ4Qj8qOqkIR9VmTQKJyNcbF4hy79ZQnWD7A==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", + "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", "funding": [ { "type": "github", @@ -3029,9 +3235,9 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.1", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { "node": ">=18" @@ -3094,26 +3300,29 @@ } }, "node_modules/@docsearch/css": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.3.tgz", - "integrity": "sha512-1nELpMV40JDLJ6rpVVFX48R1jsBFIQ6RnEQDsLFGmzOjPWTOMlZqUcXcvRx8VmYV/TqnS1l784Ofz+ZEb+wEOQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.2.0.tgz", + "integrity": "sha512-65KU9Fw5fGsPPPlgIghonMcndyx1bszzrDQYLfierN+Ha29yotMHzVS94bPkZS6On9LS8dE4qmW4P/fGjtCf/g==", "license": "MIT" }, "node_modules/@docsearch/react": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.3.tgz", - "integrity": "sha512-6UNrg88K7lJWmuS6zFPL/xgL+n326qXqZ7Ybyy4E8P/6Rcblk3GE8RXxeol4Pd5pFpKMhOhBhzABKKwHtbJCIg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.2.0.tgz", + "integrity": "sha512-zSN/KblmtBcerf7Z87yuKIHZQmxuXvYc6/m0+qnjyNu+Ir67AVOagTa1zBqcxkVUVkmBqUExdcyrdo9hbGbqTw==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-core": "1.17.9", - "@algolia/autocomplete-preset-algolia": "1.17.9", - "@docsearch/css": "3.8.3", - "algoliasearch": "^5.14.2" + "@ai-sdk/react": "^2.0.30", + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/css": "4.2.0", + "ai": "^5.0.30", + "algoliasearch": "^5.28.0", + "marked": "^16.3.0", + "zod": "^4.1.8" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0", + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", "search-insights": ">= 1 < 3" }, "peerDependenciesMeta": { @@ -3132,9 +3341,9 @@ } }, "node_modules/@docusaurus/babel": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.7.0.tgz", - "integrity": "sha512-0H5uoJLm14S/oKV3Keihxvh8RV+vrid+6Gv+2qhuzbqHanawga8tYnsdpjEyt36ucJjqlby2/Md2ObWjA02UXQ==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.9.2.tgz", + "integrity": "sha512-GEANdi/SgER+L7Japs25YiGil/AUDnFFHaCGPBbundxoWtCkA2lmy7/tFmgED4y1htAy6Oi4wkJEQdGssnw9MA==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", @@ -3147,42 +3356,41 @@ "@babel/runtime": "^7.25.9", "@babel/runtime-corejs3": "^7.25.9", "@babel/traverse": "^7.25.9", - "@docusaurus/logger": "3.7.0", - "@docusaurus/utils": "3.7.0", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", "babel-plugin-dynamic-import-node": "^2.3.3", "fs-extra": "^11.1.1", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" } }, "node_modules/@docusaurus/bundler": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.7.0.tgz", - "integrity": "sha512-CUUT9VlSGukrCU5ctZucykvgCISivct+cby28wJwCC/fkQFgAHRp/GKv2tx38ZmXb7nacrKzFTcp++f9txUYGg==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.9.2.tgz", + "integrity": "sha512-ZOVi6GYgTcsZcUzjblpzk3wH1Fya2VNpd5jtHoCCFcJlMQ1EYXZetfAnRHLcyiFeBABaI1ltTYbOBtH/gahGVA==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.7.0", - "@docusaurus/cssnano-preset": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", + "@docusaurus/babel": "3.9.2", + "@docusaurus/cssnano-preset": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", "babel-loader": "^9.2.1", - "clean-css": "^5.3.2", + "clean-css": "^5.3.3", "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.8.1", + "css-loader": "^6.11.0", "css-minimizer-webpack-plugin": "^5.0.1", "cssnano": "^6.1.2", "file-loader": "^6.2.0", "html-minifier-terser": "^7.2.0", - "mini-css-extract-plugin": "^2.9.1", + "mini-css-extract-plugin": "^2.9.2", "null-loader": "^4.0.1", - "postcss": "^8.4.26", - "postcss-loader": "^7.3.3", - "postcss-preset-env": "^10.1.0", - "react-dev-utils": "^12.0.1", + "postcss": "^8.5.4", + "postcss-loader": "^7.3.4", + "postcss-preset-env": "^10.2.1", "terser-webpack-plugin": "^5.3.9", "tslib": "^2.6.0", "url-loader": "^4.1.1", @@ -3190,7 +3398,7 @@ "webpackbar": "^6.0.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "@docusaurus/faster": "*" @@ -3201,39 +3409,75 @@ } } }, - "node_modules/@docusaurus/core": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.7.0.tgz", - "integrity": "sha512-b0fUmaL+JbzDIQaamzpAFpTviiaU4cX3Qz8cuo14+HGBCwa0evEK0UYCBFY3n4cLzL8Op1BueeroUD2LYAIHbQ==", + "node_modules/@docusaurus/bundler/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", "license": "MIT", "dependencies": { - "@docusaurus/babel": "3.7.0", - "@docusaurus/bundler": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cli-table3": "^0.6.3", - "combine-promises": "^1.1.0", + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", "commander": "^5.1.0", - "core-js": "^3.31.1", - "del": "^6.1.1", - "detect-port": "^1.5.1", - "escape-html": "^1.0.3", - "eta": "^2.2.0", - "eval": "^0.1.8", - "fs-extra": "^11.1.1", - "html-tags": "^3.3.1", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/bundler/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/core": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.9.2.tgz", + "integrity": "sha512-HbjwKeC+pHUFBfLMNzuSjqFE/58+rLVKmOU3lxQrpsxLBOGosYco/Q0GduBb0/jEMRiyEqjNT/01rRdOMWq5pw==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.9.2", + "@docusaurus/bundler": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "execa": "5.1.1", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", "html-webpack-plugin": "^5.6.0", "leven": "^3.1.0", "lodash": "^4.17.21", + "open": "^8.4.0", "p-map": "^4.0.0", "prompts": "^2.4.2", - "react-dev-utils": "^12.0.1", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", "react-loadable-ssr-addon-v5-slorber": "^1.0.1", @@ -3242,19 +3486,19 @@ "react-router-dom": "^5.3.4", "semver": "^7.5.4", "serve-handler": "^6.1.6", - "shelljs": "^0.8.5", + "tinypool": "^1.0.2", "tslib": "^2.6.0", "update-notifier": "^6.0.2", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", - "webpack-dev-server": "^4.15.2", + "webpack-dev-server": "^5.2.2", "webpack-merge": "^6.0.1" }, "bin": { "docusaurus": "bin/docusaurus.mjs" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "@mdx-js/react": "^3.0.0", @@ -3263,49 +3507,49 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.7.0.tgz", - "integrity": "sha512-X9GYgruZBSOozg4w4dzv9uOz8oK/EpPVQXkp0MM6Tsgp/nRIU9hJzJ0Pxg1aRa3xCeEQTOimZHcocQFlLwYajQ==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.9.2.tgz", + "integrity": "sha512-8gBKup94aGttRduABsj7bpPFTX7kbwu+xh3K9NMCF5K4bWBqTFYW+REKHF6iBVDHRJ4grZdIPbvkiHd/XNKRMQ==", "license": "MIT", "dependencies": { "cssnano-preset-advanced": "^6.1.2", - "postcss": "^8.4.38", + "postcss": "^8.5.4", "postcss-sort-media-queries": "^5.2.0", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" } }, "node_modules/@docusaurus/logger": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.7.0.tgz", - "integrity": "sha512-z7g62X7bYxCYmeNNuO9jmzxLQG95q9QxINCwpboVcNff3SJiHJbGrarxxOVMVmAh1MsrSfxWkVGv4P41ktnFsA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.9.2.tgz", + "integrity": "sha512-/SVCc57ByARzGSU60c50rMyQlBuMIJCjcsJlkphxY6B0GV4UH3tcA1994N8fFfbJ9kX3jIBe/xg3XP5qBtGDbA==", "license": "MIT", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" } }, "node_modules/@docusaurus/mdx-loader": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.7.0.tgz", - "integrity": "sha512-OFBG6oMjZzc78/U3WNPSHs2W9ZJ723ewAcvVJaqS0VgyeUfmzUV8f1sv+iUHA0DtwiR5T5FjOxj6nzEE8LY6VA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz", + "integrity": "sha512-wiYoGwF9gdd6rev62xDU8AAM8JuLI/hlwOtCzMmYcspEkzecKrP8J8X+KpYnTlACBUUtXNJpSoCwFWJhLRevzQ==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", - "image-size": "^1.0.2", + "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-string": "^4.0.0", "rehype-raw": "^7.0.0", @@ -3322,7 +3566,7 @@ "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -3333,6 +3577,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.7.0.tgz", "integrity": "sha512-g7WdPqDNaqA60CmBrr0cORTrsOit77hbsTj7xE2l71YhBn79sxdm7WMK7wfhcaafkbpIh7jv5ef5TOpf1Xv9Lg==", + "dev": true, "license": "MIT", "dependencies": { "@docusaurus/types": "3.7.0", @@ -3349,23 +3594,23 @@ } }, "node_modules/@docusaurus/plugin-client-redirects": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.7.0.tgz", - "integrity": "sha512-6B4XAtE5ZVKOyhPgpgMkb7LwCkN+Hgd4vOnlbwR8nCdTQhLjz8MHbGlwwvZ/cay2SPNRX5KssqKAlcHVZP2m8g==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.9.2.tgz", + "integrity": "sha512-lUgMArI9vyOYMzLRBUILcg9vcPTCyyI2aiuXq/4npcMVqOr6GfmwtmBYWSbNMlIUM0147smm4WhpXD0KFboffw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "eta": "^2.2.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -3373,24 +3618,24 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.7.0.tgz", - "integrity": "sha512-EFLgEz6tGHYWdPU0rK8tSscZwx+AsyuBW/r+tNig2kbccHYGUJmZtYN38GjAa3Fda4NU+6wqUO5kTXQSRBQD3g==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/theme-common": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.9.2.tgz", + "integrity": "sha512-3I2HXy3L1QcjLJLGAoTvoBnpOwa6DPUa3Q0dMK19UTY9mhPkKQg/DYhAGTiBUKcTR0f08iw7kLPqOhIgdV3eVQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "cheerio": "1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^11.1.1", "lodash": "^4.17.21", - "reading-time": "^1.5.0", + "schema-dts": "^1.1.2", "srcset": "^4.0.0", "tslib": "^2.6.0", "unist-util-visit": "^5.0.0", @@ -3398,7 +3643,7 @@ "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", @@ -3406,301 +3651,844 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.7.0.tgz", - "integrity": "sha512-GXg5V7kC9FZE4FkUZA8oo/NrlRb06UwuICzI6tcbzj0+TVgjq/mpUXXzSgKzMS82YByi4dY2Q808njcBCyy6tQ==", + "node_modules/@docusaurus/plugin-content-blog/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/module-type-aliases": "3.7.0", - "@docusaurus/theme-common": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-blog/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", + "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", "js-yaml": "^4.1.0", "lodash": "^4.17.21", + "schema-dts": "^1.1.2", "tslib": "^2.6.0", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/module-type-aliases": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz", + "integrity": "sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.9.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-content-docs/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.7.0.tgz", - "integrity": "sha512-YJSU3tjIJf032/Aeao8SZjFOrXJbz/FACMveSMjLyMH4itQyZ2XgUIzt4y+1ISvvk5zrW4DABVT2awTCqBkx0Q==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.9.2.tgz", + "integrity": "sha512-s4849w/p4noXUrGpPUF0BPqIAfdAe76BLaRGAGKZ1gTDNiGxGcpsLcwJ9OTi1/V8A+AzvsmI9pkjie2zjIQZKA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-content-pages/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.9.2.tgz", + "integrity": "sha512-w1s3+Ss+eOQbscGM4cfIFBlVg/QKxyYgj26k5AnakuHkKxH6004ZtuLe5awMBotIYF2bbGDoDhpgQ4r/kcj4rQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-debug": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.7.0.tgz", - "integrity": "sha512-Qgg+IjG/z4svtbCNyTocjIwvNTNEwgRjSXXSJkKVG0oWoH0eX/HAPiu+TS1HBwRPQV+tTYPWLrUypYFepfujZA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.9.2.tgz", + "integrity": "sha512-j7a5hWuAFxyQAkilZwhsQ/b3T7FfHZ+0dub6j/GxKNFJp2h9qk/P1Bp7vrGASnvA9KNQBBL1ZXTe7jlh4VdPdA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", "fs-extra": "^11.1.1", - "react-json-view-lite": "^1.2.0", + "react-json-view-lite": "^2.3.0", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-debug/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.7.0.tgz", - "integrity": "sha512-otIqiRV/jka6Snjf+AqB360XCeSv7lQC+DKYW+EUZf6XbuE8utz5PeUQ8VuOcD8Bk5zvT1MC4JKcd5zPfDuMWA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.9.2.tgz", + "integrity": "sha512-mAwwQJ1Us9jL/lVjXtErXto4p4/iaLlweC54yDUK1a97WfkC6Z2k5/769JsFgwOwOP+n5mUQGACXOEQ0XDuVUw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-google-analytics/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.7.0.tgz", - "integrity": "sha512-M3vrMct1tY65ModbyeDaMoA+fNJTSPe5qmchhAbtqhDD/iALri0g9LrEpIOwNaoLmm6lO88sfBUADQrSRSGSWA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.9.2.tgz", + "integrity": "sha512-YJ4lDCphabBtw19ooSlc1MnxtYGpjFV9rEdzjLsUnBCeis2djUyCozZaFhCg6NGEwOn7HDDyMh0yzcdRpnuIvA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "@types/gtag.js": "^0.0.12", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-google-gtag/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.7.0.tgz", - "integrity": "sha512-X8U78nb8eiMiPNg3jb9zDIVuuo/rE1LjGDGu+5m5CX4UBZzjMy+klOY2fNya6x8ACyE/L3K2erO1ErheP55W/w==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.9.2.tgz", + "integrity": "sha512-LJtIrkZN/tuHD8NqDAW1Tnw0ekOwRTfobWPsdO15YxcicBo2ykKF0/D6n0vVBfd3srwr9Z6rzrIWYrMzBGrvNw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-google-tag-manager/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.7.0.tgz", - "integrity": "sha512-bTRT9YLZ/8I/wYWKMQke18+PF9MV8Qub34Sku6aw/vlZ/U+kuEuRpQ8bTcNOjaTSfYsWkK4tTwDMHK2p5S86cA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz", + "integrity": "sha512-WLh7ymgDXjG8oPoM/T4/zUP7KcSuFYRZAUTl8vR6VzYkfc18GBM4xLhcT+AKOwun6kBivYKUJf+vlqYJkm+RHw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-sitemap/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/plugin-svgr": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.7.0.tgz", - "integrity": "sha512-HByXIZTbc4GV5VAUkZ2DXtXv1Qdlnpk3IpuImwSnEzCDBkUMYcec5282hPjn6skZqB25M1TYCmWS91UbhBGxQg==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.9.2.tgz", + "integrity": "sha512-n+1DE+5b3Lnf27TgVU5jM1d4x5tUh2oW5LTsBxJX4PsAPV0JGcmI6p3yLYtEY0LRVEIJh+8RsdQmRE66wSV8mw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", "@svgr/core": "8.1.0", "@svgr/webpack": "^8.1.0", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-svgr/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-svgr/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/preset-classic": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.7.0.tgz", - "integrity": "sha512-nPHj8AxDLAaQXs+O6+BwILFuhiWbjfQWrdw2tifOClQoNfuXDjfjogee6zfx6NGHWqshR23LrcN115DmkHC91Q==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/plugin-content-blog": "3.7.0", - "@docusaurus/plugin-content-docs": "3.7.0", - "@docusaurus/plugin-content-pages": "3.7.0", - "@docusaurus/plugin-debug": "3.7.0", - "@docusaurus/plugin-google-analytics": "3.7.0", - "@docusaurus/plugin-google-gtag": "3.7.0", - "@docusaurus/plugin-google-tag-manager": "3.7.0", - "@docusaurus/plugin-sitemap": "3.7.0", - "@docusaurus/plugin-svgr": "3.7.0", - "@docusaurus/theme-classic": "3.7.0", - "@docusaurus/theme-common": "3.7.0", - "@docusaurus/theme-search-algolia": "3.7.0", - "@docusaurus/types": "3.7.0" + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.9.2.tgz", + "integrity": "sha512-IgyYO2Gvaigi21LuDIe+nvmN/dfGXAiMcV/murFqcpjnZc7jxFAxW+9LEjdPt61uZLxG4ByW/oUmX/DDK9t/8w==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/plugin-content-blog": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/plugin-content-pages": "3.9.2", + "@docusaurus/plugin-css-cascade-layers": "3.9.2", + "@docusaurus/plugin-debug": "3.9.2", + "@docusaurus/plugin-google-analytics": "3.9.2", + "@docusaurus/plugin-google-gtag": "3.9.2", + "@docusaurus/plugin-google-tag-manager": "3.9.2", + "@docusaurus/plugin-sitemap": "3.9.2", + "@docusaurus/plugin-svgr": "3.9.2", + "@docusaurus/theme-classic": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-search-algolia": "3.9.2", + "@docusaurus/types": "3.9.2" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/theme-classic": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.7.0.tgz", - "integrity": "sha512-MnLxG39WcvLCl4eUzHr0gNcpHQfWoGqzADCly54aqCofQX6UozOS9Th4RK3ARbM9m7zIRv3qbhggI53dQtx/hQ==", + "node_modules/@docusaurus/preset-classic/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz", + "integrity": "sha512-IGUsArG5hhekXd7RDb11v94ycpJpFdJPkLnt10fFQWOVxAtq5/D7hT6lzc2fhyQKaaCE62qVajOMKL7OiAFAIA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/plugin-content-blog": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/plugin-content-pages": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-translations": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.5.4", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/module-type-aliases": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz", + "integrity": "sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.9.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.9.2.tgz", + "integrity": "sha512-6c4DAbR6n6nPbnZhY2V3tzpnKnGL+6aOsLvFL26VRqhlczli9eWG0VDUNoCQEPnGwDMhPS42UhSAnz5pThm5Ag==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/module-type-aliases": "3.7.0", - "@docusaurus/plugin-content-blog": "3.7.0", - "@docusaurus/plugin-content-docs": "3.7.0", - "@docusaurus/plugin-content-pages": "3.7.0", - "@docusaurus/theme-common": "3.7.0", - "@docusaurus/theme-translations": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", - "@mdx-js/react": "^3.0.0", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", "clsx": "^2.0.0", - "copy-text-to-clipboard": "^3.2.0", - "infima": "0.2.0-alpha.45", - "lodash": "^4.17.21", - "nprogress": "^0.2.0", - "postcss": "^8.4.26", + "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^2.3.0", - "prismjs": "^1.29.0", - "react-router-dom": "^5.3.4", - "rtlcss": "^4.1.0", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/theme-common": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.7.0.tgz", - "integrity": "sha512-8eJ5X0y+gWDsURZnBfH0WabdNm8XMCXHv8ENy/3Z/oQKwaB/EHt5lP9VsTDTf36lKEp0V6DjzjFyFIB+CetL0A==", + "node_modules/@docusaurus/theme-common/node_modules/@docusaurus/module-type-aliases": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz", + "integrity": "sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew==", "license": "MIT", "dependencies": { - "@docusaurus/mdx-loader": "3.7.0", - "@docusaurus/module-type-aliases": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", + "@docusaurus/types": "3.9.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", - "clsx": "^2.0.0", - "parse-numeric-range": "^1.3.0", - "prism-react-renderer": "^2.3.0", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" }, - "engines": { - "node": ">=18.0" + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/theme-common/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { - "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/theme-common/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.7.0.tgz", - "integrity": "sha512-Al/j5OdzwRU1m3falm+sYy9AaB93S1XF1Lgk9Yc6amp80dNxJVplQdQTR4cYdzkGtuQqbzUA8+kaoYYO0RbK6g==", - "license": "MIT", - "dependencies": { - "@docsearch/react": "^3.8.1", - "@docusaurus/core": "3.7.0", - "@docusaurus/logger": "3.7.0", - "@docusaurus/plugin-content-docs": "3.7.0", - "@docusaurus/theme-common": "3.7.0", - "@docusaurus/theme-translations": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-validation": "3.7.0", - "algoliasearch": "^5.17.1", - "algoliasearch-helper": "^3.22.6", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.9.2.tgz", + "integrity": "sha512-GBDSFNwjnh5/LdkxCKQHkgO2pIMX1447BxYUBG2wBiajS21uj64a+gH/qlbQjDLxmGrbrllBrtJkUHxIsiwRnw==", + "license": "MIT", + "dependencies": { + "@docsearch/react": "^3.9.0 || ^4.1.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-translations": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "algoliasearch": "^5.37.0", + "algoliasearch-helper": "^3.26.0", "clsx": "^2.0.0", "eta": "^2.2.0", "fs-extra": "^11.1.1", @@ -3709,7 +4497,7 @@ "utility-types": "^3.10.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -3717,16 +4505,16 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.7.0.tgz", - "integrity": "sha512-Ewq3bEraWDmienM6eaNK7fx+/lHMtGDHQyd1O+4+3EsDxxUmrzPkV7Ct3nBWTuE0MsoZr3yNwQVKjllzCMuU3g==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.9.2.tgz", + "integrity": "sha512-vIryvpP18ON9T9rjgMRFLr2xJVDpw1rtagEGf8Ccce4CkTrvM/fRB8N2nyWYOW5u3DdjkwKw5fBa+3tbn9P4PA==", "license": "MIT", "dependencies": { "fs-extra": "^11.1.1", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" } }, "node_modules/@docusaurus/tsconfig": { @@ -3740,6 +4528,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.7.0.tgz", "integrity": "sha512-kOmZg5RRqJfH31m+6ZpnwVbkqMJrPOG5t0IOl4i/+3ruXyNfWzZ0lVtVrD0u4ONc/0NOsS9sWYaxxWNkH1LdLQ==", + "dev": true, "license": "MIT", "dependencies": { "@mdx-js/mdx": "^3.0.0", @@ -3761,6 +4550,7 @@ "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -3772,15 +4562,16 @@ } }, "node_modules/@docusaurus/utils": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.7.0.tgz", - "integrity": "sha512-e7zcB6TPnVzyUaHMJyLSArKa2AG3h9+4CfvKXKKWNx6hRs+p0a+u7HHTJBgo6KW2m+vqDnuIHK4X+bhmoghAFA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.9.2.tgz", + "integrity": "sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.7.0", - "@docusaurus/types": "3.7.0", - "@docusaurus/utils-common": "3.7.0", + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-common": "3.9.2", "escape-string-regexp": "^4.0.0", + "execa": "5.1.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "github-slugger": "^1.5.0", @@ -3790,40 +4581,76 @@ "js-yaml": "^4.1.0", "lodash": "^4.17.21", "micromatch": "^4.0.5", + "p-queue": "^6.6.2", "prompts": "^2.4.2", "resolve-pathname": "^3.0.0", - "shelljs": "^0.8.5", "tslib": "^2.6.0", "url-loader": "^4.1.1", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" } }, "node_modules/@docusaurus/utils-common": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz", - "integrity": "sha512-IZeyIfCfXy0Mevj6bWNg7DG7B8G+S6o6JVpddikZtWyxJguiQ7JYr0SIZ0qWd8pGNuMyVwriWmbWqMnK7Y5PwA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.9.2.tgz", + "integrity": "sha512-I53UC1QctruA6SWLvbjbhCpAw7+X7PePoe5pYcwTOEXD/PxeP8LnECAhTHHwWCblyUX5bMi4QLRkxvyZ+IT8Aw==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.7.0", + "@docusaurus/types": "3.9.2", "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-common/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/utils-common/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/@docusaurus/utils-validation": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.7.0.tgz", - "integrity": "sha512-w8eiKk8mRdN+bNfeZqC4nyFoxNyI1/VExMKAzD9tqpJfLLbsa46Wfn5wcKH761g9WkKh36RtFV49iL9lh1DYBA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.9.2.tgz", + "integrity": "sha512-l7yk3X5VnNmATbwijJkexdhulNsQaNDwoagiwujXoxFbWLcxHQqNQ+c/IAlzrfMMOfa/8xSBZ7KEKDesE/2J7A==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.7.0", - "@docusaurus/utils": "3.7.0", - "@docusaurus/utils-common": "3.7.0", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", @@ -3831,7 +4658,43 @@ "tslib": "^2.6.0" }, "engines": { - "node": ">=18.0" + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils/node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/utils/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/@hapi/hoek": { @@ -3873,9 +4736,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -3885,9 +4748,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3929,17 +4792,23 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -3951,19 +4820,10 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3971,21 +4831,135 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -3993,15 +4967,16 @@ "license": "MIT" }, "node_modules/@mdx-js/mdx": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", - "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", @@ -4029,10 +5004,11 @@ } }, "node_modules/@mdx-js/react": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", - "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -4045,6 +5021,12 @@ "react": ">=16" } }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4080,6 +5062,15 @@ "node": ">= 8" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -4132,9 +5123,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "license": "MIT" }, "node_modules/@sideway/address": { @@ -4187,6 +5178,12 @@ "micromark-util-symbol": "^1.0.1" } }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", @@ -4346,6 +5343,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -4465,19 +5463,10 @@ "node": ">=10.13.0" } }, - "node_modules/@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "license": "MIT", "dependencies": { "@types/connect": "*", @@ -4542,9 +5531,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/estree-jsx": { @@ -4557,33 +5546,21 @@ } }, "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.5.tgz", - "integrity": "sha512-GLZPrd9ckqEBFMcVM/qRFAP0Hg3qiVEojgEFsx/N/zKXsBzbGF6z5FBDpZ0+Xhp1xr+qRZYjfGr1cWHB9oFHSA==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/serve-static": "^1" } }, - "node_modules/@types/express/node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "node_modules/@types/express-serve-static-core": { + "version": "4.19.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -4626,15 +5603,15 @@ "license": "MIT" }, "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.15", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", - "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -4698,45 +5675,33 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", - "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "license": "MIT" - }, "node_modules/@types/prismjs": { "version": "1.26.5", "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "license": "MIT" - }, "node_modules/@types/qs": { - "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "license": "MIT" }, "node_modules/@types/range-parser": { @@ -4746,12 +5711,12 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", - "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, @@ -4788,9 +5753,9 @@ } }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "license": "MIT" }, "node_modules/@types/sax": { @@ -4803,12 +5768,11 @@ } }, "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "license": "MIT", "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, @@ -4822,14 +5786,24 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", - "@types/send": "*" + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" } }, "node_modules/@types/sockjs": { @@ -4848,18 +5822,18 @@ "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", - "integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz", + "integrity": "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==", "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -4877,6 +5851,15 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@vercel/oidc": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.3.tgz", + "integrity": "sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -5079,10 +6062,11 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5090,6 +6074,18 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -5133,11 +6129,30 @@ "node": ">=8" } }, + "node_modules/ai": { + "version": "5.0.86", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.86.tgz", + "integrity": "sha512-ooHwNTkLdedFf98iQhtSc5btc/P4UuXuOpYneoifq0190vqosLunNdW8Hs6CiE0Am7YOGNplDK56JIPlHZIL4w==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "2.0.5", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.15", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5179,33 +6194,35 @@ } }, "node_modules/algoliasearch": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.20.0.tgz", - "integrity": "sha512-groO71Fvi5SWpxjI9Ia+chy0QBwT61mg6yxJV27f5YFf+Mw+STT75K6SHySpP8Co5LsCrtsbCH5dJZSRtkSKaQ==", - "license": "MIT", - "dependencies": { - "@algolia/client-abtesting": "5.20.0", - "@algolia/client-analytics": "5.20.0", - "@algolia/client-common": "5.20.0", - "@algolia/client-insights": "5.20.0", - "@algolia/client-personalization": "5.20.0", - "@algolia/client-query-suggestions": "5.20.0", - "@algolia/client-search": "5.20.0", - "@algolia/ingestion": "1.20.0", - "@algolia/monitoring": "1.20.0", - "@algolia/recommend": "5.20.0", - "@algolia/requester-browser-xhr": "5.20.0", - "@algolia/requester-fetch": "5.20.0", - "@algolia/requester-node-http": "5.20.0" + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.42.0.tgz", + "integrity": "sha512-X5+PtWc9EJIPafT/cj8ZG+6IU3cjRRnlHGtqMHK/9gsiupQbAyYlH5y7qt/FtsAhfX5AICHffZy69ZAsVrxWkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/abtesting": "1.8.0", + "@algolia/client-abtesting": "5.42.0", + "@algolia/client-analytics": "5.42.0", + "@algolia/client-common": "5.42.0", + "@algolia/client-insights": "5.42.0", + "@algolia/client-personalization": "5.42.0", + "@algolia/client-query-suggestions": "5.42.0", + "@algolia/client-search": "5.42.0", + "@algolia/ingestion": "1.42.0", + "@algolia/monitoring": "1.42.0", + "@algolia/recommend": "5.42.0", + "@algolia/requester-browser-xhr": "5.42.0", + "@algolia/requester-fetch": "5.42.0", + "@algolia/requester-node-http": "5.42.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.23.1.tgz", - "integrity": "sha512-j/dF2ZELJBm4SJTK5ECsMuCDJpBB8ITiWKRjd3S15bK2bqrXKLWqDiA5A96WhVvCpZ2NmgNlUYmFbKOfcqivbg==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.26.0.tgz", + "integrity": "sha512-Rv2x3GXleQ3ygwhkhJubhhYGsICmShLAiqtUuJTUkr9uOCOXyF2E71LVT4XDnVffbknv8XgScP4U0Oxtgm+hIw==", "license": "MIT", "dependencies": { "@algolia/events": "^4.0.1" @@ -5361,19 +6378,10 @@ "astring": "bin/astring" } }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "funding": [ { "type": "opencollective", @@ -5390,11 +6398,11 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -5434,13 +6442,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", - "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.3", + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { @@ -5457,25 +6465,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3" + "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -5497,6 +6505,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.23.tgz", + "integrity": "sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5633,9 +6650,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", "funding": [ { "type": "opencollective", @@ -5651,11 +6668,13 @@ } ], "license": "MIT", + "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" @@ -5670,6 +6689,21 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -5725,9 +6759,9 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5738,13 +6772,13 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -5806,9 +6840,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001695", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", - "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", + "version": "1.0.30001753", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz", + "integrity": "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==", "funding": [ { "type": "opencollective", @@ -6173,9 +7207,9 @@ } }, "node_modules/compressible/node_modules/mime-db": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", - "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6268,9 +7302,9 @@ } }, "node_modules/consola": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", - "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" @@ -6315,18 +7349,6 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, - "node_modules/copy-text-to-clipboard": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", - "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", @@ -6395,9 +7417,9 @@ } }, "node_modules/core-js": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", - "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -6406,12 +7428,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz", - "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==", + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", + "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", "license": "MIT", "dependencies": { - "browserslist": "^4.24.3" + "browserslist": "^4.26.3" }, "funding": { "type": "opencollective", @@ -6419,9 +7441,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.40.0.tgz", - "integrity": "sha512-AtDzVIgRrmRKQai62yuSIN5vNiQjcJakJb4fbhVw3ehxx7Lohphvw9SGNWKhLFqSxC4ilD0g/L1huAYFQU3Q6A==", + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.46.0.tgz", + "integrity": "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -6528,9 +7550,9 @@ } }, "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -6541,9 +7563,9 @@ } }, "node_modules/css-declaration-sorter": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", - "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.0.tgz", + "integrity": "sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==", "license": "ISC", "engines": { "node": "^14 || ^16 || >=18" @@ -6553,9 +7575,9 @@ } }, "node_modules/css-has-pseudo": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.2.tgz", - "integrity": "sha512-nzol/h+E0bId46Kn2dQH5VElaknX2Sr0hFuB/1EomdC7j+OISt2ZzK7EHX9DZDY53WbIVAR7FYKSO2XnSf07MQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz", + "integrity": "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==", "funding": [ { "type": "github", @@ -6602,10 +7624,11 @@ } }, "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -6716,9 +7739,9 @@ } }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -6745,9 +7768,9 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -6757,9 +7780,9 @@ } }, "node_modules/cssdb": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.3.tgz", - "integrity": "sha512-9BDG5XmJrJQQnJ51VFxXCAtpZ5ebDlAREmO8sxMOVU0aSxN/gocbctjIG5LMh3WBUq+xTlb/jw2LoljBEqraTA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.4.2.tgz", + "integrity": "sha512-PzjkRkRUS+IHDJohtxkIczlxPPZqRo0nXplsYXOMBRPjcVRjj1W4DfvRgshUYTVuUigU7ptVYkFJQ7abUB0nyg==", "funding": [ { "type": "opencollective", @@ -6918,7 +7941,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/debounce": { "version": "1.2.1", @@ -6927,9 +7951,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6944,9 +7968,9 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -7001,16 +8025,32 @@ "node": ">=0.10.0" } }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "license": "BSD-2-Clause", + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "license": "MIT", "dependencies": { - "execa": "^5.0.0" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/defer-to-connect": { @@ -7065,28 +8105,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "license": "MIT", - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -7138,38 +8156,6 @@ "node": ">= 4.0.0" } }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "license": "MIT", - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -7318,9 +8304,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -7362,9 +8348,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.87", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.87.tgz", - "integrity": "sha512-mPFwmEWmRivw2F8x3w3l2m6htAUN97Gy0kwpO++2m9iT1Gt8RCFVUfv9U/sIbHJ6rY4P6/ooqFL/eL7ock+pPg==", + "version": "1.5.244", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.244.tgz", + "integrity": "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -7408,9 +8394,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", - "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -7433,9 +8419,9 @@ } }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -7460,9 +8446,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "license": "MIT" }, "node_modules/es-object-atoms": { @@ -7673,9 +8659,9 @@ } }, "node_modules/estree-util-value-to-estree": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.4.0.tgz", - "integrity": "sha512-Zlp+gxis+gCfK12d3Srl2PdX2ybsEA8ZYy6vQGVQTNNYLEGRQQ56XB64bjemN8kxIKXP1nC9ip4Z+ILy9LGzvQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.5.0.tgz", + "integrity": "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" @@ -7764,6 +8750,15 @@ "node": ">=0.8.x" } }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -7922,9 +8917,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -7938,9 +8933,9 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -8032,6 +9027,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -8076,15 +9072,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -8172,9 +9159,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -8201,159 +9188,22 @@ "signal-exit": "^4.0.1" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "license": "MIT", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { - "node": ">= 6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/form-data-encoder": { @@ -8432,9 +9282,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -8445,18 +9295,6 @@ "node": ">=14.14" } }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "license": "Unlicense" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -8490,17 +9328,17 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -8550,27 +9388,6 @@ "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", "license": "ISC" }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -8583,6 +9400,22 @@ "node": ">= 6" } }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -8613,53 +9446,6 @@ "node": ">=10" } }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "license": "MIT", - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "license": "MIT", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -8681,9 +9467,9 @@ } }, "node_modules/goober": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", - "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", "license": "MIT", "peerDependencies": { "csstype": "^3.0.10" @@ -8860,16 +9646,16 @@ } }, "node_modules/hast-util-from-parse5": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", - "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" @@ -8918,9 +9704,9 @@ } }, "node_modules/hast-util-to-estree": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.1.tgz", - "integrity": "sha512-IWtwwmPskfSmma9RpzCappDUitC8t5jhAynHhc1m2+5trOgsrp7txscUSavc5Ic8PATyAjfrCK1wgtxh2cICVQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -8934,9 +9720,9 @@ "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", + "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" }, @@ -8946,9 +9732,9 @@ } }, "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", - "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -8961,9 +9747,9 @@ "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", + "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" }, @@ -8991,6 +9777,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -9005,15 +9801,15 @@ } }, "node_modules/hastscript": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", - "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" }, "funding": { @@ -9101,22 +9897,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -9186,9 +9966,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", - "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.4.tgz", + "integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==", "license": "MIT", "dependencies": { "@types/html-minifier-terser": "^6.0.0", @@ -9267,9 +10047,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { @@ -9295,9 +10075,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", - "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", "license": "MIT" }, "node_modules/http-proxy": { @@ -9372,6 +10152,15 @@ "node": ">=10.17.0" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -9406,13 +10195,10 @@ } }, "node_modules/image-size": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", - "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", "license": "MIT", - "dependencies": { - "queue": "6.0.2" - }, "bin": { "image-size": "bin/image-size.js" }, @@ -9420,20 +10206,10 @@ "node": ">=16.x" } }, - "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -9482,17 +10258,6 @@ "node": ">=12" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -9506,20 +10271,11 @@ "license": "ISC" }, "node_modules/inline-style-parser": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", - "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.6.tgz", + "integrity": "sha512-gtGXVaBdl5mAes3rPcMedEBm12ibjt1kDMFfheul1wUAOVEJW60voNdMVzVkfLN06O7ZaD/rxhfKgtlgtTbMjg==", "license": "MIT" }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -9681,6 +10437,39 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-installed-globally": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", @@ -9697,10 +10486,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-network-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", + "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.1.0.tgz", + "integrity": "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -9727,15 +10528,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -9778,15 +10570,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -9980,6 +10763,12 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -9999,9 +10788,9 @@ } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -10053,13 +10842,13 @@ } }, "node_modules/launch-editor": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", - "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", + "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", "license": "MIT", "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" } }, "node_modules/leven": { @@ -10090,12 +10879,16 @@ "license": "MIT" }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { @@ -10234,6 +11027,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.1.tgz", + "integrity": "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -10363,9 +11168,9 @@ } }, "node_modules/mdast-util-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -10435,9 +11240,9 @@ "license": "MIT" }, "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -10661,15 +11466,21 @@ } }, "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "license": "Unlicense", + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.50.0.tgz", + "integrity": "sha512-N0LUYQMUA1yS5tJKmMtU9yprPm6ZIg24yr/OVv/7t6q0kKDIho4cBbXRi1XKttUmNYDYgF/q45qrKE/UhGO0CA==", + "license": "Apache-2.0", "dependencies": { - "fs-monkey": "^1.0.4" + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" }, - "engines": { - "node": ">= 4.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, "node_modules/merge-descriptors": { @@ -10706,9 +11517,9 @@ } }, "node_modules/micromark": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", - "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -10741,9 +11552,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", - "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -11299,9 +12110,9 @@ "license": "MIT" }, "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", - "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", "funding": [ { "type": "GitHub Sponsors", @@ -11381,12 +12192,11 @@ "license": "MIT" }, "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", - "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", @@ -11665,9 +12475,9 @@ "license": "MIT" }, "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", - "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", "funding": [ { "type": "GitHub Sponsors", @@ -12197,9 +13007,9 @@ "license": "MIT" }, "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", - "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", "funding": [ { "type": "GitHub Sponsors", @@ -12212,7 +13022,6 @@ ], "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", @@ -12366,9 +13175,9 @@ "license": "MIT" }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.4.tgz", - "integrity": "sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -12420,9 +13229,9 @@ "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", - "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -12559,9 +13368,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", - "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz", + "integrity": "sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==", "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", @@ -12630,9 +13439,9 @@ "license": "MIT" }, "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "license": "MIT", "engines": { "node": ">=10" @@ -12669,9 +13478,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -12736,9 +13545,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/normalize-path": { @@ -12760,9 +13569,9 @@ } }, "node_modules/normalize-url": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", - "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.0.tgz", + "integrity": "sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w==", "license": "MIT", "engines": { "node": ">=14.16" @@ -12826,6 +13635,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -12889,9 +13699,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -12956,15 +13766,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -13015,6 +13816,15 @@ "node": ">=12.20" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", @@ -13060,26 +13870,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/package-json": { @@ -13178,12 +14011,12 @@ "license": "ISC" }, "node_modules/parse5": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", - "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "entities": "^4.5.0" + "entities": "^6.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -13202,6 +14035,18 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -13230,15 +14075,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -13328,9 +14164,9 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" @@ -13351,83 +14187,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "license": "MIT", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/postcss": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz", - "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -13443,8 +14206,9 @@ } ], "license": "MIT", + "peer": true, "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -13478,9 +14242,9 @@ } }, "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13522,9 +14286,9 @@ } }, "node_modules/postcss-color-functional-notation": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.7.tgz", - "integrity": "sha512-EZvAHsvyASX63vXnyXOIynkxhaHRSsdb7z6yiXKIovGXAolW4cMZ3qoh7k3VdTsLBS6VGdksGfIo3r6+waLoOw==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.12.tgz", + "integrity": "sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==", "funding": [ { "type": "github", @@ -13537,10 +14301,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -13637,9 +14401,9 @@ } }, "node_modules/postcss-custom-media": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz", - "integrity": "sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz", + "integrity": "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==", "funding": [ { "type": "github", @@ -13652,10 +14416,10 @@ ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.4", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/media-query-list-parser": "^4.0.2" + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" }, "engines": { "node": ">=18" @@ -13665,9 +14429,9 @@ } }, "node_modules/postcss-custom-properties": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz", - "integrity": "sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==", + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz", + "integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==", "funding": [ { "type": "github", @@ -13680,9 +14444,9 @@ ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.4", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, @@ -13694,9 +14458,9 @@ } }, "node_modules/postcss-custom-selectors": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz", - "integrity": "sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz", + "integrity": "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==", "funding": [ { "type": "github", @@ -13709,9 +14473,9 @@ ], "license": "MIT", "dependencies": { - "@csstools/cascade-layer-name-parser": "^2.0.4", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", "postcss-selector-parser": "^7.0.0" }, "engines": { @@ -13722,9 +14486,9 @@ } }, "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13760,9 +14524,9 @@ } }, "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13836,9 +14600,9 @@ } }, "node_modules/postcss-double-position-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", - "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.4.tgz", + "integrity": "sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==", "funding": [ { "type": "github", @@ -13851,7 +14615,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, @@ -13888,9 +14652,9 @@ } }, "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13926,9 +14690,9 @@ } }, "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -13996,9 +14760,9 @@ } }, "node_modules/postcss-import": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", - "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.1.tgz", + "integrity": "sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -14013,9 +14777,19 @@ } }, "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -14023,18 +14797,14 @@ "engines": { "node": "^12 || ^14 || >= 16" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.4.21" } }, "node_modules/postcss-lab-function": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.7.tgz", - "integrity": "sha512-+ONj2bpOQfsCKZE2T9VGMyVVdGcGUpr7u3SVfvkJlvhTRmDCfY25k4Jc8fubB9DclAPR4+w8uVtDZmdRgdAHig==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.12.tgz", + "integrity": "sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==", "funding": [ { "type": "github", @@ -14047,10 +14817,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.7", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -14061,9 +14831,9 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "funding": [ { "type": "opencollective", @@ -14076,21 +14846,28 @@ ], "license": "MIT", "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { + "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { + "jiti": { + "optional": true + }, "postcss": { "optional": true }, - "ts-node": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } @@ -14118,9 +14895,9 @@ } }, "node_modules/postcss-logical": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", - "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", + "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", "funding": [ { "type": "github", @@ -14286,9 +15063,9 @@ } }, "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -14314,9 +15091,9 @@ } }, "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -14367,9 +15144,9 @@ } }, "node_modules/postcss-nesting": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", - "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz", + "integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==", "funding": [ { "type": "github", @@ -14382,7 +15159,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-resolve-nested": "^3.1.0", "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0" }, @@ -14394,9 +15171,9 @@ } }, "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", - "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", + "integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==", "funding": [ { "type": "github", @@ -14438,10 +15215,11 @@ } }, "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -14681,9 +15459,9 @@ } }, "node_modules/postcss-preset-env": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.3.tgz", - "integrity": "sha512-9qzVhcMFU/MnwYHyYpJz4JhGku/4+xEiPTmhn0hj3IxnUYlEF9vbh7OC1KoLAnenS6Fgg43TKNp9xcuMeAi4Zw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.4.0.tgz", + "integrity": "sha512-2kqpOthQ6JhxqQq1FSAAZGe9COQv75Aw8WbsOvQVNJ2nSevc9Yx/IKZGuZ7XJ+iOTtVon7LfO7ELRzg8AZ+sdw==", "funding": [ { "type": "github", @@ -14696,62 +15474,66 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/postcss-cascade-layers": "^5.0.1", - "@csstools/postcss-color-function": "^4.0.7", - "@csstools/postcss-color-mix-function": "^3.0.7", - "@csstools/postcss-content-alt-text": "^2.0.4", - "@csstools/postcss-exponential-functions": "^2.0.6", + "@csstools/postcss-alpha-function": "^1.0.1", + "@csstools/postcss-cascade-layers": "^5.0.2", + "@csstools/postcss-color-function": "^4.0.12", + "@csstools/postcss-color-function-display-p3-linear": "^1.0.1", + "@csstools/postcss-color-mix-function": "^3.0.12", + "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.2", + "@csstools/postcss-content-alt-text": "^2.0.8", + "@csstools/postcss-contrast-color-function": "^2.0.12", + "@csstools/postcss-exponential-functions": "^2.0.9", "@csstools/postcss-font-format-keywords": "^4.0.0", - "@csstools/postcss-gamut-mapping": "^2.0.7", - "@csstools/postcss-gradients-interpolation-method": "^5.0.7", - "@csstools/postcss-hwb-function": "^4.0.7", - "@csstools/postcss-ic-unit": "^4.0.0", - "@csstools/postcss-initial": "^2.0.0", - "@csstools/postcss-is-pseudo-class": "^5.0.1", - "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-gamut-mapping": "^2.0.11", + "@csstools/postcss-gradients-interpolation-method": "^5.0.12", + "@csstools/postcss-hwb-function": "^4.0.12", + "@csstools/postcss-ic-unit": "^4.0.4", + "@csstools/postcss-initial": "^2.0.1", + "@csstools/postcss-is-pseudo-class": "^5.0.3", + "@csstools/postcss-light-dark-function": "^2.0.11", "@csstools/postcss-logical-float-and-clear": "^3.0.0", "@csstools/postcss-logical-overflow": "^2.0.0", "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", "@csstools/postcss-logical-resize": "^3.0.0", - "@csstools/postcss-logical-viewport-units": "^3.0.3", - "@csstools/postcss-media-minmax": "^2.0.6", - "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", + "@csstools/postcss-logical-viewport-units": "^3.0.4", + "@csstools/postcss-media-minmax": "^2.0.9", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", "@csstools/postcss-nested-calc": "^4.0.0", "@csstools/postcss-normalize-display-values": "^4.0.0", - "@csstools/postcss-oklab-function": "^4.0.7", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", - "@csstools/postcss-random-function": "^1.0.2", - "@csstools/postcss-relative-color-syntax": "^3.0.7", + "@csstools/postcss-oklab-function": "^4.0.12", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/postcss-random-function": "^2.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.12", "@csstools/postcss-scope-pseudo-class": "^4.0.1", - "@csstools/postcss-sign-functions": "^1.1.1", - "@csstools/postcss-stepped-value-functions": "^4.0.6", - "@csstools/postcss-text-decoration-shorthand": "^4.0.1", - "@csstools/postcss-trigonometric-functions": "^4.0.6", + "@csstools/postcss-sign-functions": "^1.1.4", + "@csstools/postcss-stepped-value-functions": "^4.0.9", + "@csstools/postcss-text-decoration-shorthand": "^4.0.3", + "@csstools/postcss-trigonometric-functions": "^4.0.9", "@csstools/postcss-unset-value": "^4.0.0", - "autoprefixer": "^10.4.19", - "browserslist": "^4.23.1", + "autoprefixer": "^10.4.21", + "browserslist": "^4.26.0", "css-blank-pseudo": "^7.0.1", - "css-has-pseudo": "^7.0.2", + "css-has-pseudo": "^7.0.3", "css-prefers-color-scheme": "^10.0.0", - "cssdb": "^8.2.3", + "cssdb": "^8.4.2", "postcss-attribute-case-insensitive": "^7.0.1", "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^7.0.7", + "postcss-color-functional-notation": "^7.0.12", "postcss-color-hex-alpha": "^10.0.0", "postcss-color-rebeccapurple": "^10.0.0", - "postcss-custom-media": "^11.0.5", - "postcss-custom-properties": "^14.0.4", - "postcss-custom-selectors": "^8.0.4", + "postcss-custom-media": "^11.0.6", + "postcss-custom-properties": "^14.0.6", + "postcss-custom-selectors": "^8.0.5", "postcss-dir-pseudo-class": "^9.0.1", - "postcss-double-position-gradients": "^6.0.0", + "postcss-double-position-gradients": "^6.0.4", "postcss-focus-visible": "^10.0.1", "postcss-focus-within": "^9.0.1", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^6.0.0", "postcss-image-set-function": "^7.0.0", - "postcss-lab-function": "^7.0.7", - "postcss-logical": "^8.0.0", - "postcss-nesting": "^13.0.1", + "postcss-lab-function": "^7.0.12", + "postcss-logical": "^8.1.0", + "postcss-nesting": "^13.0.2", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^6.0.0", "postcss-page-break": "^3.0.4", @@ -14793,9 +15575,9 @@ } }, "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -14886,9 +15668,9 @@ } }, "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -15047,9 +15829,9 @@ } }, "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", "funding": { "type": "github", @@ -15094,9 +15876,9 @@ } }, "node_modules/pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.3.0.tgz", + "integrity": "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==", "license": "MIT", "dependencies": { "escape-goat": "^4.0.0" @@ -15123,15 +15905,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.3" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15231,158 +16004,28 @@ } }, "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", - "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { - "scheduler": "^0.25.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^19.2.0" } }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", - "license": "MIT" - }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -15408,9 +16051,9 @@ } }, "node_modules/react-hot-toast": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz", - "integrity": "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", "license": "MIT", "dependencies": { "csstype": "^3.1.3", @@ -15431,15 +16074,15 @@ "license": "MIT" }, "node_modules/react-json-view-lite": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz", - "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.5.0.tgz", + "integrity": "sha512-tk7o7QG9oYyELWHL8xiMQ8x4WzjCzbWNyig3uexmkLb54r8jO0yH3WCWx8UZS0c49eSA4QUmG5caiRJ8fAn58g==", "license": "MIT", "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + "react": "^18.0.0 || ^19.0.0" } }, "node_modules/react-loadable": { @@ -15448,6 +16091,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/react": "*" }, @@ -15503,6 +16147,7 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -15584,23 +16229,6 @@ "node": ">=8.10.0" } }, - "node_modules/reading-time": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", - "license": "MIT" - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/recma-build-jsx": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", @@ -15617,9 +16245,9 @@ } }, "node_modules/recma-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz", - "integrity": "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", "license": "MIT", "dependencies": { "acorn-jsx": "^5.0.0", @@ -15631,6 +16259,9 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/recma-parse": { @@ -15665,18 +16296,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -15684,9 +16303,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -15695,42 +16314,27 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { "node": ">=4" } }, "node_modules/registry-auth-token": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz", - "integrity": "sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", "license": "MIT", "dependencies": { "@pnpm/npm-conf": "^2.1.0" @@ -15761,27 +16365,15 @@ "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~3.0.2" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "jsesc": "~3.1.0" }, - "engines": { - "node": ">=6" + "bin": { + "regjsparser": "bin/parser" } }, "node_modules/rehype-raw": { @@ -15872,9 +16464,9 @@ } }, "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -15890,9 +16482,9 @@ } }, "node_modules/remark-mdx": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", - "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", "license": "MIT", "dependencies": { "mdast-util-mdx": "^3.0.0", @@ -15920,9 +16512,9 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", - "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -16084,12 +16676,12 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -16149,31 +16741,15 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rtlcss": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", @@ -16192,6 +16768,18 @@ "node": ">=12.0.0" } }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -16242,21 +16830,27 @@ "license": "MIT" }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.2.tgz", + "integrity": "sha512-FySGAa0RGcFiN6zfrO9JvK1r7TB59xuzCcTHOBXBNoKgDejlOQCR2KL/FGk3/iDlsqyYg1ELZpOmlg09B01Czw==", + "license": "BlueOak-1.0.0" }, "node_modules/scheduler": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/schema-dts": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", + "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", + "license": "Apache-2.0" + }, "node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -16312,9 +16906,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -16581,9 +17175,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -16592,23 +17186,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "license": "BSD-3-Clause", - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -16784,12 +17361,12 @@ } }, "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">= 12" } }, "node_modules/source-map-js": { @@ -16888,9 +17465,9 @@ } }, "node_modules/std-env": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", - "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "license": "MIT" }, "node_modules/string_decoder": { @@ -16941,9 +17518,9 @@ "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -16953,9 +17530,9 @@ } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -17050,13 +17627,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.19.tgz", + "integrity": "sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.12" + } + }, "node_modules/style-to-object": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", - "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.12.tgz", + "integrity": "sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw==", "license": "MIT", "dependencies": { - "inline-style-parser": "0.2.4" + "inline-style-parser": "0.2.6" } }, "node_modules/stylehacks": { @@ -17215,9 +17801,9 @@ } }, "node_modules/swiper": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.6.tgz", - "integrity": "sha512-8aXpYKtjy3DjcbzZfz+/OX/GhcU5h+looA6PbAzHMZT6ESSycSp9nAjPCenczgJyslV+rUGse64LMGpWE3PX9Q==", + "version": "11.2.10", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz", + "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==", "funding": [ { "type": "patreon", @@ -17233,10 +17819,23 @@ "node": ">= 4.7.0" } }, + "node_modules/swr": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz", + "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/tailwind-merge": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.2.0.tgz", - "integrity": "sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", "license": "MIT", "funding": { "type": "github", @@ -17244,9 +17843,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", - "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -17257,7 +17856,7 @@ "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.6", + "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", @@ -17266,7 +17865,7 @@ "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", @@ -17310,22 +17909,26 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -17337,9 +17940,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", - "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -17405,12 +18008,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "license": "MIT" - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -17432,6 +18029,34 @@ "node": ">=0.8" } }, + "node_modules/thingies": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", + "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -17450,6 +18075,15 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "license": "MIT" }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -17480,6 +18114,22 @@ "node": ">=6" } }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -17510,7 +18160,17 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true + }, + "node_modules/turndown": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.2.tgz", + "integrity": "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==", + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } }, "node_modules/type-fest": { "version": "2.19.0", @@ -17571,7 +18231,9 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -17581,9 +18243,9 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17618,18 +18280,18 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", "license": "MIT", "engines": { "node": ">=4" @@ -17670,9 +18332,9 @@ } }, "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -17737,9 +18399,9 @@ } }, "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -17769,9 +18431,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "funding": [ { "type": "opencollective", @@ -17861,9 +18523,9 @@ } }, "node_modules/update-notifier/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -17913,6 +18575,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17978,6 +18641,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -18061,9 +18733,9 @@ } }, "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -18075,9 +18747,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -18107,20 +18779,23 @@ } }, "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "version": "5.102.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", + "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.26.3", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -18130,11 +18805,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -18188,44 +18863,50 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", "license": "MIT", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -18241,54 +18922,52 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", - "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", - "license": "MIT", - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", + "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", + "express": "^4.21.2", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.4", - "ws": "^8.13.0" + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { @@ -18299,10 +18978,40 @@ } } }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -18335,45 +19044,14 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "license": "MIT", "engines": { "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, "node_modules/webpack/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -18395,24 +19073,6 @@ "node": ">= 0.6" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpackbar": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", @@ -18600,9 +19260,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -18612,9 +19272,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -18624,9 +19284,9 @@ } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -18638,12 +19298,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", @@ -18677,6 +19331,36 @@ } } }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xdg-basedir": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", @@ -18708,15 +19392,17 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "devOptional": true, "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" } }, "node_modules/yaml-loader": { @@ -18735,9 +19421,9 @@ } }, "node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "license": "MIT", "engines": { "node": ">=12.20" @@ -18746,6 +19432,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/documentation/package.json b/documentation/package.json index e27c0bedaa51..123c9ba67282 100644 --- a/documentation/package.json +++ b/documentation/package.json @@ -16,9 +16,9 @@ "generate-detail-pages": "node scripts/generate-detail-pages.js" }, "dependencies": { - "@docusaurus/core": "3.7.0", - "@docusaurus/plugin-client-redirects": "^3.7.0", - "@docusaurus/preset-classic": "3.7.0", + "@docusaurus/core": "^3.9.2", + "@docusaurus/plugin-client-redirects": "^3.9.2", + "@docusaurus/preset-classic": "^3.9.2", "@inkeep/docusaurus": "^2.0.16", "@mdx-js/react": "^3.0.0", "autoprefixer": "^10.4.17", diff --git a/documentation/yarn.lock b/documentation/yarn.lock deleted file mode 100644 index c771f760d930..000000000000 --- a/documentation/yarn.lock +++ /dev/null @@ -1,9377 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@algolia/autocomplete-core@1.17.9": - version "1.17.9" - resolved "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz" - integrity sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ== - dependencies: - "@algolia/autocomplete-plugin-algolia-insights" "1.17.9" - "@algolia/autocomplete-shared" "1.17.9" - -"@algolia/autocomplete-plugin-algolia-insights@1.17.9": - version "1.17.9" - resolved "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz" - integrity sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ== - dependencies: - "@algolia/autocomplete-shared" "1.17.9" - -"@algolia/autocomplete-preset-algolia@1.17.9": - version "1.17.9" - resolved "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz" - integrity sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ== - dependencies: - "@algolia/autocomplete-shared" "1.17.9" - -"@algolia/autocomplete-shared@1.17.9": - version "1.17.9" - resolved "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz" - integrity sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ== - -"@algolia/client-abtesting@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.20.0.tgz" - integrity sha512-YaEoNc1Xf2Yk6oCfXXkZ4+dIPLulCx8Ivqj0OsdkHWnsI3aOJChY5qsfyHhDBNSOhqn2ilgHWxSfyZrjxBcAww== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/client-analytics@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.20.0.tgz" - integrity sha512-CIT9ni0+5sYwqehw+t5cesjho3ugKQjPVy/iPiJvtJX4g8Cdb6je6SPt2uX72cf2ISiXCAX9U3cY0nN0efnRDw== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/client-common@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.20.0.tgz" - integrity sha512-iSTFT3IU8KNpbAHcBUJw2HUrPnMXeXLyGajmCL7gIzWOsYM4GabZDHXOFx93WGiXMti1dymz8k8R+bfHv1YZmA== - -"@algolia/client-insights@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.20.0.tgz" - integrity sha512-w9RIojD45z1csvW1vZmAko82fqE/Dm+Ovsy2ElTsjFDB0HMAiLh2FO86hMHbEXDPz6GhHKgGNmBRiRP8dDPgJg== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/client-personalization@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.20.0.tgz" - integrity sha512-p/hftHhrbiHaEcxubYOzqVV4gUqYWLpTwK+nl2xN3eTrSW9SNuFlAvUBFqPXSVBqc6J5XL9dNKn3y8OA1KElSQ== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/client-query-suggestions@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.20.0.tgz" - integrity sha512-m4aAuis5vZi7P4gTfiEs6YPrk/9hNTESj3gEmGFgfJw3hO2ubdS4jSId1URd6dGdt0ax2QuapXufcrN58hPUcw== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/client-search@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.20.0.tgz" - integrity sha512-KL1zWTzrlN4MSiaK1ea560iCA/UewMbS4ZsLQRPoDTWyrbDKVbztkPwwv764LAqgXk0fvkNZvJ3IelcK7DqhjQ== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/events@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz" - integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== - -"@algolia/ingestion@1.20.0": - version "1.20.0" - resolved "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.20.0.tgz" - integrity sha512-shj2lTdzl9un4XJblrgqg54DoK6JeKFO8K8qInMu4XhE2JuB8De6PUuXAQwiRigZupbI0xq8aM0LKdc9+qiLQA== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/monitoring@1.20.0": - version "1.20.0" - resolved "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.20.0.tgz" - integrity sha512-aF9blPwOhKtWvkjyyXh9P5peqmhCA1XxLBRgItT+K6pbT0q4hBDQrCid+pQZJYy4HFUKjB/NDDwyzFhj/rwKhw== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/recommend@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.20.0.tgz" - integrity sha512-T6B/WPdZR3b89/F9Vvk6QCbt/wrLAtrGoL8z4qPXDFApQ8MuTFWbleN/4rHn6APWO3ps+BUePIEbue2rY5MlRw== - dependencies: - "@algolia/client-common" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -"@algolia/requester-browser-xhr@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.20.0.tgz" - integrity sha512-t6//lXsq8E85JMenHrI6mhViipUT5riNhEfCcvtRsTV+KIBpC6Od18eK864dmBhoc5MubM0f+sGpKOqJIlBSCg== - dependencies: - "@algolia/client-common" "5.20.0" - -"@algolia/requester-fetch@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.20.0.tgz" - integrity sha512-FHxYGqRY+6bgjKsK4aUsTAg6xMs2S21elPe4Y50GB0Y041ihvw41Vlwy2QS6K9ldoftX4JvXodbKTcmuQxywdQ== - dependencies: - "@algolia/client-common" "5.20.0" - -"@algolia/requester-node-http@5.20.0": - version "5.20.0" - resolved "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.20.0.tgz" - integrity sha512-kmtQClq/w3vtPteDSPvaW9SPZL/xrIgMrxZyAgsFwrJk0vJxqyC5/hwHmrCraDnStnGSADnLpBf4SpZnwnkwWw== - dependencies: - "@algolia/client-common" "5.20.0" - -"@alloc/quick-lru@^5.2.0": - version "5.2.0" - resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" - integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2", "@babel/code-frame@^7.8.3": - version "7.26.2" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz" - integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== - dependencies: - "@babel/helper-validator-identifier" "^7.25.9" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.26.0", "@babel/compat-data@^7.26.5": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz" - integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== - -"@babel/core@^7.21.3", "@babel/core@^7.25.9": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz" - integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.26.0" - "@babel/generator" "^7.26.0" - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-module-transforms" "^7.26.0" - "@babel/helpers" "^7.26.0" - "@babel/parser" "^7.26.0" - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.26.0" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.25.9", "@babel/generator@^7.26.0", "@babel/generator@^7.26.5": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz" - integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== - dependencies: - "@babel/parser" "^7.26.5" - "@babel/types" "^7.26.5" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-annotate-as-pure@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz" - integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz" - integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== - dependencies: - "@babel/compat-data" "^7.26.5" - "@babel/helper-validator-option" "^7.25.9" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz" - integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/traverse" "^7.25.9" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9": - version "7.26.3" - resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz" - integrity sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - regexpu-core "^6.2.0" - semver "^6.3.1" - -"@babel/helper-define-polyfill-provider@^0.6.2", "@babel/helper-define-polyfill-provider@^0.6.3": - version "0.6.3" - resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz" - integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg== - dependencies: - "@babel/helper-compilation-targets" "^7.22.6" - "@babel/helper-plugin-utils" "^7.22.5" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - -"@babel/helper-member-expression-to-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz" - integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-imports@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz" - integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz" - integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-optimise-call-expression@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz" - integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== - dependencies: - "@babel/types" "^7.25.9" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz" - integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== - -"@babel/helper-remap-async-to-generator@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz" - integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-wrap-function" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/helper-replace-supers@^7.25.9": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz" - integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.25.9" - "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/traverse" "^7.26.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz" - integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== - dependencies: - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helper-string-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz" - integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== - -"@babel/helper-validator-identifier@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz" - integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== - -"@babel/helper-validator-option@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz" - integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== - -"@babel/helper-wrap-function@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz" - integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g== - dependencies: - "@babel/template" "^7.25.9" - "@babel/traverse" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/helpers@^7.26.0": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz" - integrity sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg== - dependencies: - "@babel/template" "^7.27.0" - "@babel/types" "^7.27.0" - -"@babel/parser@^7.26.0", "@babel/parser@^7.26.5", "@babel/parser@^7.27.0": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz" - integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== - dependencies: - "@babel/types" "^7.27.0" - -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz" - integrity sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz" - integrity sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz" - integrity sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz" - integrity sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/plugin-transform-optional-chaining" "^7.25.9" - -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz" - integrity sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": - version "7.21.0-placeholder-for-preset-env.2" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz" - integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-import-assertions@^7.26.0": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz" - integrity sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-import-attributes@^7.26.0": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz" - integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-jsx@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz" - integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-typescript@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz" - integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz" - integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-arrow-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz" - integrity sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-async-generator-functions@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz" - integrity sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-remap-async-to-generator" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-async-to-generator@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz" - integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-remap-async-to-generator" "^7.25.9" - -"@babel/plugin-transform-block-scoped-functions@^7.25.9": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz" - integrity sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - -"@babel/plugin-transform-block-scoping@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz" - integrity sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-class-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz" - integrity sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-class-static-block@^7.26.0": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz" - integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-classes@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz" - integrity sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - "@babel/traverse" "^7.25.9" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz" - integrity sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/template" "^7.25.9" - -"@babel/plugin-transform-destructuring@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz" - integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-dotall-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz" - integrity sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-duplicate-keys@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz" - integrity sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz" - integrity sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-dynamic-import@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz" - integrity sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-exponentiation-operator@^7.25.9": - version "7.26.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz" - integrity sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-export-namespace-from@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz" - integrity sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-for-of@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz" - integrity sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-function-name@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz" - integrity sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA== - dependencies: - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-json-strings@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz" - integrity sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz" - integrity sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-logical-assignment-operators@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz" - integrity sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-member-expression-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz" - integrity sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-amd@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz" - integrity sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-commonjs@^7.25.9": - version "7.26.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz" - integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ== - dependencies: - "@babel/helper-module-transforms" "^7.26.0" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-modules-systemjs@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz" - integrity sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - "@babel/traverse" "^7.25.9" - -"@babel/plugin-transform-modules-umd@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz" - integrity sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw== - dependencies: - "@babel/helper-module-transforms" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz" - integrity sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-new-target@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz" - integrity sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-nullish-coalescing-operator@^7.25.9": - version "7.26.6" - resolved "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz" - integrity sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw== - dependencies: - "@babel/helper-plugin-utils" "^7.26.5" - -"@babel/plugin-transform-numeric-separator@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz" - integrity sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-object-rest-spread@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz" - integrity sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg== - dependencies: - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/plugin-transform-parameters" "^7.25.9" - -"@babel/plugin-transform-object-super@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz" - integrity sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-replace-supers" "^7.25.9" - -"@babel/plugin-transform-optional-catch-binding@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz" - integrity sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-optional-chaining@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz" - integrity sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-parameters@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz" - integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-private-methods@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz" - integrity sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-private-property-in-object@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz" - integrity sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-property-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz" - integrity sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-constant-elements@^7.21.3": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz" - integrity sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-display-name@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz" - integrity sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-react-jsx-development@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz" - integrity sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw== - dependencies: - "@babel/plugin-transform-react-jsx" "^7.25.9" - -"@babel/plugin-transform-react-jsx@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz" - integrity sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/plugin-syntax-jsx" "^7.25.9" - "@babel/types" "^7.25.9" - -"@babel/plugin-transform-react-pure-annotations@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz" - integrity sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-regenerator@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz" - integrity sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - regenerator-transform "^0.15.2" - -"@babel/plugin-transform-regexp-modifiers@^7.26.0": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz" - integrity sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-reserved-words@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz" - integrity sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-runtime@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz" - integrity sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ== - dependencies: - "@babel/helper-module-imports" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.6" - babel-plugin-polyfill-regenerator "^0.6.1" - semver "^6.3.1" - -"@babel/plugin-transform-shorthand-properties@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz" - integrity sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-spread@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz" - integrity sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - -"@babel/plugin-transform-sticky-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz" - integrity sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-template-literals@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz" - integrity sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-typeof-symbol@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz" - integrity sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-typescript@^7.25.9": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz" - integrity sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.9" - "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.26.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" - "@babel/plugin-syntax-typescript" "^7.25.9" - -"@babel/plugin-transform-unicode-escapes@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz" - integrity sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-property-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz" - integrity sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz" - integrity sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/plugin-transform-unicode-sets-regex@^7.25.9": - version "7.25.9" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz" - integrity sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - -"@babel/preset-env@^7.20.2", "@babel/preset-env@^7.25.9": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz" - integrity sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw== - dependencies: - "@babel/compat-data" "^7.26.0" - "@babel/helper-compilation-targets" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.9" - "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.9" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.9" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.9" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.9" - "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-import-assertions" "^7.26.0" - "@babel/plugin-syntax-import-attributes" "^7.26.0" - "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.25.9" - "@babel/plugin-transform-async-generator-functions" "^7.25.9" - "@babel/plugin-transform-async-to-generator" "^7.25.9" - "@babel/plugin-transform-block-scoped-functions" "^7.25.9" - "@babel/plugin-transform-block-scoping" "^7.25.9" - "@babel/plugin-transform-class-properties" "^7.25.9" - "@babel/plugin-transform-class-static-block" "^7.26.0" - "@babel/plugin-transform-classes" "^7.25.9" - "@babel/plugin-transform-computed-properties" "^7.25.9" - "@babel/plugin-transform-destructuring" "^7.25.9" - "@babel/plugin-transform-dotall-regex" "^7.25.9" - "@babel/plugin-transform-duplicate-keys" "^7.25.9" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.9" - "@babel/plugin-transform-dynamic-import" "^7.25.9" - "@babel/plugin-transform-exponentiation-operator" "^7.25.9" - "@babel/plugin-transform-export-namespace-from" "^7.25.9" - "@babel/plugin-transform-for-of" "^7.25.9" - "@babel/plugin-transform-function-name" "^7.25.9" - "@babel/plugin-transform-json-strings" "^7.25.9" - "@babel/plugin-transform-literals" "^7.25.9" - "@babel/plugin-transform-logical-assignment-operators" "^7.25.9" - "@babel/plugin-transform-member-expression-literals" "^7.25.9" - "@babel/plugin-transform-modules-amd" "^7.25.9" - "@babel/plugin-transform-modules-commonjs" "^7.25.9" - "@babel/plugin-transform-modules-systemjs" "^7.25.9" - "@babel/plugin-transform-modules-umd" "^7.25.9" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.9" - "@babel/plugin-transform-new-target" "^7.25.9" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.9" - "@babel/plugin-transform-numeric-separator" "^7.25.9" - "@babel/plugin-transform-object-rest-spread" "^7.25.9" - "@babel/plugin-transform-object-super" "^7.25.9" - "@babel/plugin-transform-optional-catch-binding" "^7.25.9" - "@babel/plugin-transform-optional-chaining" "^7.25.9" - "@babel/plugin-transform-parameters" "^7.25.9" - "@babel/plugin-transform-private-methods" "^7.25.9" - "@babel/plugin-transform-private-property-in-object" "^7.25.9" - "@babel/plugin-transform-property-literals" "^7.25.9" - "@babel/plugin-transform-regenerator" "^7.25.9" - "@babel/plugin-transform-regexp-modifiers" "^7.26.0" - "@babel/plugin-transform-reserved-words" "^7.25.9" - "@babel/plugin-transform-shorthand-properties" "^7.25.9" - "@babel/plugin-transform-spread" "^7.25.9" - "@babel/plugin-transform-sticky-regex" "^7.25.9" - "@babel/plugin-transform-template-literals" "^7.25.9" - "@babel/plugin-transform-typeof-symbol" "^7.25.9" - "@babel/plugin-transform-unicode-escapes" "^7.25.9" - "@babel/plugin-transform-unicode-property-regex" "^7.25.9" - "@babel/plugin-transform-unicode-regex" "^7.25.9" - "@babel/plugin-transform-unicode-sets-regex" "^7.25.9" - "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.6" - babel-plugin-polyfill-regenerator "^0.6.1" - core-js-compat "^3.38.1" - semver "^6.3.1" - -"@babel/preset-modules@0.1.6-no-external-plugins": - version "0.1.6-no-external-plugins" - resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz" - integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/preset-react@^7.18.6", "@babel/preset-react@^7.25.9": - version "7.26.3" - resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz" - integrity sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-transform-react-display-name" "^7.25.9" - "@babel/plugin-transform-react-jsx" "^7.25.9" - "@babel/plugin-transform-react-jsx-development" "^7.25.9" - "@babel/plugin-transform-react-pure-annotations" "^7.25.9" - -"@babel/preset-typescript@^7.21.0", "@babel/preset-typescript@^7.25.9": - version "7.26.0" - resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz" - integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.9" - "@babel/helper-validator-option" "^7.25.9" - "@babel/plugin-syntax-jsx" "^7.25.9" - "@babel/plugin-transform-modules-commonjs" "^7.25.9" - "@babel/plugin-transform-typescript" "^7.25.9" - -"@babel/runtime-corejs3@^7.25.9": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.0.tgz" - integrity sha512-UWjX6t+v+0ckwZ50Y5ShZLnlk95pP5MyW/pon9tiYzl3+18pkTHTFNTKr7rQbfRXPkowt2QAn30o1b6oswszew== - dependencies: - core-js-pure "^3.30.2" - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.25.9", "@babel/runtime@^7.8.4": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz" - integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.25.9", "@babel/template@^7.27.0": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz" - integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== - dependencies: - "@babel/code-frame" "^7.26.2" - "@babel/parser" "^7.27.0" - "@babel/types" "^7.27.0" - -"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5": - version "7.26.5" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz" - integrity sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ== - dependencies: - "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.5" - "@babel/parser" "^7.26.5" - "@babel/template" "^7.25.9" - "@babel/types" "^7.26.5" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.21.3", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.5", "@babel/types@^7.27.0", "@babel/types@^7.4.4": - version "7.27.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz" - integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== - dependencies: - "@babel/helper-string-parser" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - -"@colors/colors@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" - integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== - -"@csstools/cascade-layer-name-parser@^2.0.4": - version "2.0.4" - resolved "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz" - integrity sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA== - -"@csstools/color-helpers@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz" - integrity sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA== - -"@csstools/css-calc@^2.1.1": - version "2.1.1" - resolved "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz" - integrity sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag== - -"@csstools/css-color-parser@^3.0.7": - version "3.0.7" - resolved "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz" - integrity sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA== - dependencies: - "@csstools/color-helpers" "^5.0.1" - "@csstools/css-calc" "^2.1.1" - -"@csstools/css-parser-algorithms@^3.0.4": - version "3.0.4" - resolved "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz" - integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== - -"@csstools/css-tokenizer@^3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz" - integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== - -"@csstools/media-query-list-parser@^4.0.2": - version "4.0.2" - resolved "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz" - integrity sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A== - -"@csstools/postcss-cascade-layers@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz" - integrity sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ== - dependencies: - "@csstools/selector-specificity" "^5.0.0" - postcss-selector-parser "^7.0.0" - -"@csstools/postcss-color-function@^4.0.7": - version "4.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.7.tgz" - integrity sha512-aDHYmhNIHR6iLw4ElWhf+tRqqaXwKnMl0YsQ/X105Zc4dQwe6yJpMrTN6BwOoESrkDjOYMOfORviSSLeDTJkdQ== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-color-mix-function@^3.0.7": - version "3.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.7.tgz" - integrity sha512-e68Nev4CxZYCLcrfWhHH4u/N1YocOfTmw67/kVX5Rb7rnguqqLyxPjhHWjSBX8o4bmyuukmNf3wrUSU3//kT7g== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-content-alt-text@^2.0.4": - version "2.0.4" - resolved "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz" - integrity sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw== - dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-exponential-functions@^2.0.6": - version "2.0.6" - resolved "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.6.tgz" - integrity sha512-IgJA5DQsQLu/upA3HcdvC6xEMR051ufebBTIXZ5E9/9iiaA7juXWz1ceYj814lnDYP/7eWjZnw0grRJlX4eI6g== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-font-format-keywords@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz" - integrity sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw== - dependencies: - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -"@csstools/postcss-gamut-mapping@^2.0.7": - version "2.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.7.tgz" - integrity sha512-gzFEZPoOkY0HqGdyeBXR3JP218Owr683u7KOZazTK7tQZBE8s2yhg06W1tshOqk7R7SWvw9gkw2TQogKpIW8Xw== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-gradients-interpolation-method@^5.0.7": - version "5.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.7.tgz" - integrity sha512-WgEyBeg6glUeTdS2XT7qeTFBthTJuXlS9GFro/DVomj7W7WMTamAwpoP4oQCq/0Ki2gvfRYFi/uZtmRE14/DFA== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-hwb-function@^4.0.7": - version "4.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.7.tgz" - integrity sha512-LKYqjO+wGwDCfNIEllessCBWfR4MS/sS1WXO+j00KKyOjm7jDW2L6jzUmqASEiv/kkJO39GcoIOvTTfB3yeBUA== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-ic-unit@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz" - integrity sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -"@csstools/postcss-initial@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz" - integrity sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA== - -"@csstools/postcss-is-pseudo-class@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz" - integrity sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ== - dependencies: - "@csstools/selector-specificity" "^5.0.0" - postcss-selector-parser "^7.0.0" - -"@csstools/postcss-light-dark-function@^2.0.7": - version "2.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz" - integrity sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw== - dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-logical-float-and-clear@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz" - integrity sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ== - -"@csstools/postcss-logical-overflow@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz" - integrity sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA== - -"@csstools/postcss-logical-overscroll-behavior@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz" - integrity sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w== - -"@csstools/postcss-logical-resize@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz" - integrity sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg== - dependencies: - postcss-value-parser "^4.2.0" - -"@csstools/postcss-logical-viewport-units@^3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz" - integrity sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw== - dependencies: - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-media-minmax@^2.0.6": - version "2.0.6" - resolved "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.6.tgz" - integrity sha512-J1+4Fr2W3pLZsfxkFazK+9kr96LhEYqoeBszLmFjb6AjYs+g9oDAw3J5oQignLKk3rC9XHW+ebPTZ9FaW5u5pg== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/media-query-list-parser" "^4.0.2" - -"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.4": - version "3.0.4" - resolved "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz" - integrity sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ== - dependencies: - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/media-query-list-parser" "^4.0.2" - -"@csstools/postcss-nested-calc@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz" - integrity sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A== - dependencies: - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -"@csstools/postcss-normalize-display-values@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz" - integrity sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q== - dependencies: - postcss-value-parser "^4.2.0" - -"@csstools/postcss-oklab-function@^4.0.7": - version "4.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.7.tgz" - integrity sha512-I6WFQIbEKG2IO3vhaMGZDkucbCaUSXMxvHNzDdnfsTCF5tc0UlV3Oe2AhamatQoKFjBi75dSEMrgWq3+RegsOQ== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-progressive-custom-properties@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz" - integrity sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q== - dependencies: - postcss-value-parser "^4.2.0" - -"@csstools/postcss-random-function@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.2.tgz" - integrity sha512-vBCT6JvgdEkvRc91NFoNrLjgGtkLWt47GKT6E2UDn3nd8ZkMBiziQ1Md1OiKoSsgzxsSnGKG3RVdhlbdZEkHjA== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-relative-color-syntax@^3.0.7": - version "3.0.7" - resolved "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.7.tgz" - integrity sha512-apbT31vsJVd18MabfPOnE977xgct5B1I+Jpf+Munw3n6kKb1MMuUmGGH+PT9Hm/fFs6fe61Q/EWnkrb4bNoNQw== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -"@csstools/postcss-scope-pseudo-class@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz" - integrity sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q== - dependencies: - postcss-selector-parser "^7.0.0" - -"@csstools/postcss-sign-functions@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.1.tgz" - integrity sha512-MslYkZCeMQDxetNkfmmQYgKCy4c+w9pPDfgOBCJOo/RI1RveEUdZQYtOfrC6cIZB7sD7/PHr2VGOcMXlZawrnA== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-stepped-value-functions@^4.0.6": - version "4.0.6" - resolved "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.6.tgz" - integrity sha512-/dwlO9w8vfKgiADxpxUbZOWlL5zKoRIsCymYoh1IPuBsXODKanKnfuZRr32DEqT0//3Av1VjfNZU9yhxtEfIeA== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-text-decoration-shorthand@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz" - integrity sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw== - dependencies: - "@csstools/color-helpers" "^5.0.1" - postcss-value-parser "^4.2.0" - -"@csstools/postcss-trigonometric-functions@^4.0.6": - version "4.0.6" - resolved "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.6.tgz" - integrity sha512-c4Y1D2Why/PeccaSouXnTt6WcNHJkoJRidV2VW9s5gJ97cNxnLgQ4Qj8qOqkIR9VmTQKJyNcbF4hy79ZQnWD7A== - dependencies: - "@csstools/css-calc" "^2.1.1" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - -"@csstools/postcss-unset-value@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz" - integrity sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA== - -"@csstools/selector-resolve-nested@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz" - integrity sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ== - -"@csstools/selector-specificity@^5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz" - integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw== - -"@csstools/utilities@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz" - integrity sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ== - -"@discoveryjs/json-ext@0.5.7": - version "0.5.7" - resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" - integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== - -"@docsearch/css@3.8.3": - version "3.8.3" - resolved "https://registry.npmjs.org/@docsearch/css/-/css-3.8.3.tgz" - integrity sha512-1nELpMV40JDLJ6rpVVFX48R1jsBFIQ6RnEQDsLFGmzOjPWTOMlZqUcXcvRx8VmYV/TqnS1l784Ofz+ZEb+wEOQ== - -"@docsearch/react@^3.8.1": - version "3.8.3" - resolved "https://registry.npmjs.org/@docsearch/react/-/react-3.8.3.tgz" - integrity sha512-6UNrg88K7lJWmuS6zFPL/xgL+n326qXqZ7Ybyy4E8P/6Rcblk3GE8RXxeol4Pd5pFpKMhOhBhzABKKwHtbJCIg== - dependencies: - "@algolia/autocomplete-core" "1.17.9" - "@algolia/autocomplete-preset-algolia" "1.17.9" - "@docsearch/css" "3.8.3" - algoliasearch "^5.14.2" - -"@docusaurus/babel@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.7.0.tgz" - integrity sha512-0H5uoJLm14S/oKV3Keihxvh8RV+vrid+6Gv+2qhuzbqHanawga8tYnsdpjEyt36ucJjqlby2/Md2ObWjA02UXQ== - dependencies: - "@babel/core" "^7.25.9" - "@babel/generator" "^7.25.9" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-transform-runtime" "^7.25.9" - "@babel/preset-env" "^7.25.9" - "@babel/preset-react" "^7.25.9" - "@babel/preset-typescript" "^7.25.9" - "@babel/runtime" "^7.25.9" - "@babel/runtime-corejs3" "^7.25.9" - "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.7.0" - "@docusaurus/utils" "3.7.0" - babel-plugin-dynamic-import-node "^2.3.3" - fs-extra "^11.1.1" - tslib "^2.6.0" - -"@docusaurus/bundler@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.7.0.tgz" - integrity sha512-CUUT9VlSGukrCU5ctZucykvgCISivct+cby28wJwCC/fkQFgAHRp/GKv2tx38ZmXb7nacrKzFTcp++f9txUYGg== - dependencies: - "@babel/core" "^7.25.9" - "@docusaurus/babel" "3.7.0" - "@docusaurus/cssnano-preset" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - babel-loader "^9.2.1" - clean-css "^5.3.2" - copy-webpack-plugin "^11.0.0" - css-loader "^6.8.1" - css-minimizer-webpack-plugin "^5.0.1" - cssnano "^6.1.2" - file-loader "^6.2.0" - html-minifier-terser "^7.2.0" - mini-css-extract-plugin "^2.9.1" - null-loader "^4.0.1" - postcss "^8.4.26" - postcss-loader "^7.3.3" - postcss-preset-env "^10.1.0" - react-dev-utils "^12.0.1" - terser-webpack-plugin "^5.3.9" - tslib "^2.6.0" - url-loader "^4.1.1" - webpack "^5.95.0" - webpackbar "^6.0.1" - -"@docusaurus/core@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/core/-/core-3.7.0.tgz" - integrity sha512-b0fUmaL+JbzDIQaamzpAFpTviiaU4cX3Qz8cuo14+HGBCwa0evEK0UYCBFY3n4cLzL8Op1BueeroUD2LYAIHbQ== - dependencies: - "@docusaurus/babel" "3.7.0" - "@docusaurus/bundler" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - boxen "^6.2.1" - chalk "^4.1.2" - chokidar "^3.5.3" - cli-table3 "^0.6.3" - combine-promises "^1.1.0" - commander "^5.1.0" - core-js "^3.31.1" - del "^6.1.1" - detect-port "^1.5.1" - escape-html "^1.0.3" - eta "^2.2.0" - eval "^0.1.8" - fs-extra "^11.1.1" - html-tags "^3.3.1" - html-webpack-plugin "^5.6.0" - leven "^3.1.0" - lodash "^4.17.21" - p-map "^4.0.0" - prompts "^2.4.2" - react-dev-utils "^12.0.1" - react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" - react-loadable "npm:@docusaurus/react-loadable@6.0.0" - react-loadable-ssr-addon-v5-slorber "^1.0.1" - react-router "^5.3.4" - react-router-config "^5.1.1" - react-router-dom "^5.3.4" - semver "^7.5.4" - serve-handler "^6.1.6" - shelljs "^0.8.5" - tslib "^2.6.0" - update-notifier "^6.0.2" - webpack "^5.95.0" - webpack-bundle-analyzer "^4.10.2" - webpack-dev-server "^4.15.2" - webpack-merge "^6.0.1" - -"@docusaurus/cssnano-preset@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.7.0.tgz" - integrity sha512-X9GYgruZBSOozg4w4dzv9uOz8oK/EpPVQXkp0MM6Tsgp/nRIU9hJzJ0Pxg1aRa3xCeEQTOimZHcocQFlLwYajQ== - dependencies: - cssnano-preset-advanced "^6.1.2" - postcss "^8.4.38" - postcss-sort-media-queries "^5.2.0" - tslib "^2.6.0" - -"@docusaurus/logger@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.7.0.tgz" - integrity sha512-z7g62X7bYxCYmeNNuO9jmzxLQG95q9QxINCwpboVcNff3SJiHJbGrarxxOVMVmAh1MsrSfxWkVGv4P41ktnFsA== - dependencies: - chalk "^4.1.2" - tslib "^2.6.0" - -"@docusaurus/mdx-loader@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.7.0.tgz" - integrity sha512-OFBG6oMjZzc78/U3WNPSHs2W9ZJ723ewAcvVJaqS0VgyeUfmzUV8f1sv+iUHA0DtwiR5T5FjOxj6nzEE8LY6VA== - dependencies: - "@docusaurus/logger" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - "@mdx-js/mdx" "^3.0.0" - "@slorber/remark-comment" "^1.0.0" - escape-html "^1.0.3" - estree-util-value-to-estree "^3.0.1" - file-loader "^6.2.0" - fs-extra "^11.1.1" - image-size "^1.0.2" - mdast-util-mdx "^3.0.0" - mdast-util-to-string "^4.0.0" - rehype-raw "^7.0.0" - remark-directive "^3.0.0" - remark-emoji "^4.0.0" - remark-frontmatter "^5.0.0" - remark-gfm "^4.0.0" - stringify-object "^3.3.0" - tslib "^2.6.0" - unified "^11.0.3" - unist-util-visit "^5.0.0" - url-loader "^4.1.1" - vfile "^6.0.1" - webpack "^5.88.1" - -"@docusaurus/module-type-aliases@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.7.0.tgz" - integrity sha512-g7WdPqDNaqA60CmBrr0cORTrsOit77hbsTj7xE2l71YhBn79sxdm7WMK7wfhcaafkbpIh7jv5ef5TOpf1Xv9Lg== - dependencies: - "@docusaurus/types" "3.7.0" - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router-config" "*" - "@types/react-router-dom" "*" - react-helmet-async "npm:@slorber/react-helmet-async@*" - react-loadable "npm:@docusaurus/react-loadable@6.0.0" - -"@docusaurus/plugin-client-redirects@^3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.7.0.tgz" - integrity sha512-6B4XAtE5ZVKOyhPgpgMkb7LwCkN+Hgd4vOnlbwR8nCdTQhLjz8MHbGlwwvZ/cay2SPNRX5KssqKAlcHVZP2m8g== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - eta "^2.2.0" - fs-extra "^11.1.1" - lodash "^4.17.21" - tslib "^2.6.0" - -"@docusaurus/plugin-content-blog@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.7.0.tgz" - integrity sha512-EFLgEz6tGHYWdPU0rK8tSscZwx+AsyuBW/r+tNig2kbccHYGUJmZtYN38GjAa3Fda4NU+6wqUO5kTXQSRBQD3g== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/theme-common" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - cheerio "1.0.0-rc.12" - feed "^4.2.2" - fs-extra "^11.1.1" - lodash "^4.17.21" - reading-time "^1.5.0" - srcset "^4.0.0" - tslib "^2.6.0" - unist-util-visit "^5.0.0" - utility-types "^3.10.0" - webpack "^5.88.1" - -"@docusaurus/plugin-content-docs@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.7.0.tgz" - integrity sha512-GXg5V7kC9FZE4FkUZA8oo/NrlRb06UwuICzI6tcbzj0+TVgjq/mpUXXzSgKzMS82YByi4dY2Q808njcBCyy6tQ== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/module-type-aliases" "3.7.0" - "@docusaurus/theme-common" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - "@types/react-router-config" "^5.0.7" - combine-promises "^1.1.0" - fs-extra "^11.1.1" - js-yaml "^4.1.0" - lodash "^4.17.21" - tslib "^2.6.0" - utility-types "^3.10.0" - webpack "^5.88.1" - -"@docusaurus/plugin-content-pages@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.7.0.tgz" - integrity sha512-YJSU3tjIJf032/Aeao8SZjFOrXJbz/FACMveSMjLyMH4itQyZ2XgUIzt4y+1ISvvk5zrW4DABVT2awTCqBkx0Q== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - fs-extra "^11.1.1" - tslib "^2.6.0" - webpack "^5.88.1" - -"@docusaurus/plugin-debug@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.7.0.tgz" - integrity sha512-Qgg+IjG/z4svtbCNyTocjIwvNTNEwgRjSXXSJkKVG0oWoH0eX/HAPiu+TS1HBwRPQV+tTYPWLrUypYFepfujZA== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - fs-extra "^11.1.1" - react-json-view-lite "^1.2.0" - tslib "^2.6.0" - -"@docusaurus/plugin-google-analytics@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.7.0.tgz" - integrity sha512-otIqiRV/jka6Snjf+AqB360XCeSv7lQC+DKYW+EUZf6XbuE8utz5PeUQ8VuOcD8Bk5zvT1MC4JKcd5zPfDuMWA== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - tslib "^2.6.0" - -"@docusaurus/plugin-google-gtag@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.7.0.tgz" - integrity sha512-M3vrMct1tY65ModbyeDaMoA+fNJTSPe5qmchhAbtqhDD/iALri0g9LrEpIOwNaoLmm6lO88sfBUADQrSRSGSWA== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - "@types/gtag.js" "^0.0.12" - tslib "^2.6.0" - -"@docusaurus/plugin-google-tag-manager@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.7.0.tgz" - integrity sha512-X8U78nb8eiMiPNg3jb9zDIVuuo/rE1LjGDGu+5m5CX4UBZzjMy+klOY2fNya6x8ACyE/L3K2erO1ErheP55W/w== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - tslib "^2.6.0" - -"@docusaurus/plugin-sitemap@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.7.0.tgz" - integrity sha512-bTRT9YLZ/8I/wYWKMQke18+PF9MV8Qub34Sku6aw/vlZ/U+kuEuRpQ8bTcNOjaTSfYsWkK4tTwDMHK2p5S86cA== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - fs-extra "^11.1.1" - sitemap "^7.1.1" - tslib "^2.6.0" - -"@docusaurus/plugin-svgr@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.7.0.tgz" - integrity sha512-HByXIZTbc4GV5VAUkZ2DXtXv1Qdlnpk3IpuImwSnEzCDBkUMYcec5282hPjn6skZqB25M1TYCmWS91UbhBGxQg== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - "@svgr/core" "8.1.0" - "@svgr/webpack" "^8.1.0" - tslib "^2.6.0" - webpack "^5.88.1" - -"@docusaurus/preset-classic@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.7.0.tgz" - integrity sha512-nPHj8AxDLAaQXs+O6+BwILFuhiWbjfQWrdw2tifOClQoNfuXDjfjogee6zfx6NGHWqshR23LrcN115DmkHC91Q== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/plugin-content-blog" "3.7.0" - "@docusaurus/plugin-content-docs" "3.7.0" - "@docusaurus/plugin-content-pages" "3.7.0" - "@docusaurus/plugin-debug" "3.7.0" - "@docusaurus/plugin-google-analytics" "3.7.0" - "@docusaurus/plugin-google-gtag" "3.7.0" - "@docusaurus/plugin-google-tag-manager" "3.7.0" - "@docusaurus/plugin-sitemap" "3.7.0" - "@docusaurus/plugin-svgr" "3.7.0" - "@docusaurus/theme-classic" "3.7.0" - "@docusaurus/theme-common" "3.7.0" - "@docusaurus/theme-search-algolia" "3.7.0" - "@docusaurus/types" "3.7.0" - -"@docusaurus/theme-classic@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.7.0.tgz" - integrity sha512-MnLxG39WcvLCl4eUzHr0gNcpHQfWoGqzADCly54aqCofQX6UozOS9Th4RK3ARbM9m7zIRv3qbhggI53dQtx/hQ== - dependencies: - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/module-type-aliases" "3.7.0" - "@docusaurus/plugin-content-blog" "3.7.0" - "@docusaurus/plugin-content-docs" "3.7.0" - "@docusaurus/plugin-content-pages" "3.7.0" - "@docusaurus/theme-common" "3.7.0" - "@docusaurus/theme-translations" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - "@mdx-js/react" "^3.0.0" - clsx "^2.0.0" - copy-text-to-clipboard "^3.2.0" - infima "0.2.0-alpha.45" - lodash "^4.17.21" - nprogress "^0.2.0" - postcss "^8.4.26" - prism-react-renderer "^2.3.0" - prismjs "^1.29.0" - react-router-dom "^5.3.4" - rtlcss "^4.1.0" - tslib "^2.6.0" - utility-types "^3.10.0" - -"@docusaurus/theme-common@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.7.0.tgz" - integrity sha512-8eJ5X0y+gWDsURZnBfH0WabdNm8XMCXHv8ENy/3Z/oQKwaB/EHt5lP9VsTDTf36lKEp0V6DjzjFyFIB+CetL0A== - dependencies: - "@docusaurus/mdx-loader" "3.7.0" - "@docusaurus/module-type-aliases" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router-config" "*" - clsx "^2.0.0" - parse-numeric-range "^1.3.0" - prism-react-renderer "^2.3.0" - tslib "^2.6.0" - utility-types "^3.10.0" - -"@docusaurus/theme-search-algolia@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.7.0.tgz" - integrity sha512-Al/j5OdzwRU1m3falm+sYy9AaB93S1XF1Lgk9Yc6amp80dNxJVplQdQTR4cYdzkGtuQqbzUA8+kaoYYO0RbK6g== - dependencies: - "@docsearch/react" "^3.8.1" - "@docusaurus/core" "3.7.0" - "@docusaurus/logger" "3.7.0" - "@docusaurus/plugin-content-docs" "3.7.0" - "@docusaurus/theme-common" "3.7.0" - "@docusaurus/theme-translations" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-validation" "3.7.0" - algoliasearch "^5.17.1" - algoliasearch-helper "^3.22.6" - clsx "^2.0.0" - eta "^2.2.0" - fs-extra "^11.1.1" - lodash "^4.17.21" - tslib "^2.6.0" - utility-types "^3.10.0" - -"@docusaurus/theme-translations@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.7.0.tgz" - integrity sha512-Ewq3bEraWDmienM6eaNK7fx+/lHMtGDHQyd1O+4+3EsDxxUmrzPkV7Ct3nBWTuE0MsoZr3yNwQVKjllzCMuU3g== - dependencies: - fs-extra "^11.1.1" - tslib "^2.6.0" - -"@docusaurus/tsconfig@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.7.0.tgz" - integrity sha512-vRsyj3yUZCjscgfgcFYjIsTcAru/4h4YH2/XAE8Rs7wWdnng98PgWKvP5ovVc4rmRpRg2WChVW0uOy2xHDvDBQ== - -"@docusaurus/types@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/types/-/types-3.7.0.tgz" - integrity sha512-kOmZg5RRqJfH31m+6ZpnwVbkqMJrPOG5t0IOl4i/+3ruXyNfWzZ0lVtVrD0u4ONc/0NOsS9sWYaxxWNkH1LdLQ== - dependencies: - "@mdx-js/mdx" "^3.0.0" - "@types/history" "^4.7.11" - "@types/react" "*" - commander "^5.1.0" - joi "^17.9.2" - react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" - utility-types "^3.10.0" - webpack "^5.95.0" - webpack-merge "^5.9.0" - -"@docusaurus/utils-common@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz" - integrity sha512-IZeyIfCfXy0Mevj6bWNg7DG7B8G+S6o6JVpddikZtWyxJguiQ7JYr0SIZ0qWd8pGNuMyVwriWmbWqMnK7Y5PwA== - dependencies: - "@docusaurus/types" "3.7.0" - tslib "^2.6.0" - -"@docusaurus/utils-validation@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.7.0.tgz" - integrity sha512-w8eiKk8mRdN+bNfeZqC4nyFoxNyI1/VExMKAzD9tqpJfLLbsa46Wfn5wcKH761g9WkKh36RtFV49iL9lh1DYBA== - dependencies: - "@docusaurus/logger" "3.7.0" - "@docusaurus/utils" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - fs-extra "^11.2.0" - joi "^17.9.2" - js-yaml "^4.1.0" - lodash "^4.17.21" - tslib "^2.6.0" - -"@docusaurus/utils@3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.7.0.tgz" - integrity sha512-e7zcB6TPnVzyUaHMJyLSArKa2AG3h9+4CfvKXKKWNx6hRs+p0a+u7HHTJBgo6KW2m+vqDnuIHK4X+bhmoghAFA== - dependencies: - "@docusaurus/logger" "3.7.0" - "@docusaurus/types" "3.7.0" - "@docusaurus/utils-common" "3.7.0" - escape-string-regexp "^4.0.0" - file-loader "^6.2.0" - fs-extra "^11.1.1" - github-slugger "^1.5.0" - globby "^11.1.0" - gray-matter "^4.0.3" - jiti "^1.20.0" - js-yaml "^4.1.0" - lodash "^4.17.21" - micromatch "^4.0.5" - prompts "^2.4.2" - resolve-pathname "^3.0.0" - shelljs "^0.8.5" - tslib "^2.6.0" - url-loader "^4.1.1" - utility-types "^3.10.0" - webpack "^5.88.1" - -"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": - version "9.3.0" - resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.1.0": - version "5.1.0" - resolved "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@inkeep/docusaurus@^2.0.16": - version "2.0.16" - resolved "https://registry.npmjs.org/@inkeep/docusaurus/-/docusaurus-2.0.16.tgz" - integrity sha512-dQhjlvFnl3CVr0gWeJ/V/qLnDy1XYrCfkdVSa2D3gJTxI9/vOf9639Y1aPxTxO88DiXuW9CertLrZLB6SoJ2yg== - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/types@^29.6.3": - version "29.6.3" - resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" - integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== - dependencies: - "@jest/schemas" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": - version "0.3.8" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz" - integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.5.0" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@leichtgewicht/ip-codec@^2.0.1": - version "2.0.5" - resolved "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz" - integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== - -"@mdx-js/mdx@^3.0.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz" - integrity sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw== - dependencies: - "@types/estree" "^1.0.0" - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdx" "^2.0.0" - collapse-white-space "^2.0.0" - devlop "^1.0.0" - estree-util-is-identifier-name "^3.0.0" - estree-util-scope "^1.0.0" - estree-walker "^3.0.0" - hast-util-to-jsx-runtime "^2.0.0" - markdown-extensions "^2.0.0" - recma-build-jsx "^1.0.0" - recma-jsx "^1.0.0" - recma-stringify "^1.0.0" - rehype-recma "^1.0.0" - remark-mdx "^3.0.0" - remark-parse "^11.0.0" - remark-rehype "^11.0.0" - source-map "^0.7.0" - unified "^11.0.0" - unist-util-position-from-estree "^2.0.0" - unist-util-stringify-position "^4.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -"@mdx-js/react@^3.0.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz" - integrity sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ== - dependencies: - "@types/mdx" "^2.0.0" - -"@mixmark-io/domino@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@mixmark-io/domino/-/domino-2.2.0.tgz#4e8ec69bf1afeb7a14f0628b7e2c0f35bdb336c3" - integrity sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@pnpm/config.env-replace@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz" - integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== - -"@pnpm/network.ca-file@^1.0.1": - version "1.0.2" - resolved "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz" - integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== - dependencies: - graceful-fs "4.2.10" - -"@pnpm/npm-conf@^2.1.0": - version "2.3.1" - resolved "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz" - integrity sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw== - dependencies: - "@pnpm/config.env-replace" "^1.1.0" - "@pnpm/network.ca-file" "^1.0.1" - config-chain "^1.1.11" - -"@polka/url@^1.0.0-next.24": - version "1.0.0-next.28" - resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz" - integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== - -"@sideway/address@^4.1.5": - version "4.1.5" - resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz" - integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.1": - version "3.0.1" - resolved "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz" - integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sindresorhus/is@^4.6.0": - version "4.6.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - -"@sindresorhus/is@^5.2.0": - version "5.6.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz" - integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== - -"@slorber/remark-comment@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz" - integrity sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.1.0" - micromark-util-symbol "^1.0.1" - -"@svgr/babel-plugin-add-jsx-attribute@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz" - integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g== - -"@svgr/babel-plugin-remove-jsx-attribute@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz" - integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== - -"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz" - integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== - -"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz" - integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ== - -"@svgr/babel-plugin-svg-dynamic-title@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz" - integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og== - -"@svgr/babel-plugin-svg-em-dimensions@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz" - integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g== - -"@svgr/babel-plugin-transform-react-native-svg@8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz" - integrity sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q== - -"@svgr/babel-plugin-transform-svg-component@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz" - integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw== - -"@svgr/babel-preset@8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz" - integrity sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "8.0.0" - "@svgr/babel-plugin-remove-jsx-attribute" "8.0.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0" - "@svgr/babel-plugin-svg-dynamic-title" "8.0.0" - "@svgr/babel-plugin-svg-em-dimensions" "8.0.0" - "@svgr/babel-plugin-transform-react-native-svg" "8.1.0" - "@svgr/babel-plugin-transform-svg-component" "8.0.0" - -"@svgr/core@8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz" - integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA== - dependencies: - "@babel/core" "^7.21.3" - "@svgr/babel-preset" "8.1.0" - camelcase "^6.2.0" - cosmiconfig "^8.1.3" - snake-case "^3.0.4" - -"@svgr/hast-util-to-babel-ast@8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz" - integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q== - dependencies: - "@babel/types" "^7.21.3" - entities "^4.4.0" - -"@svgr/plugin-jsx@8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz" - integrity sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA== - dependencies: - "@babel/core" "^7.21.3" - "@svgr/babel-preset" "8.1.0" - "@svgr/hast-util-to-babel-ast" "8.0.0" - svg-parser "^2.0.4" - -"@svgr/plugin-svgo@8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz" - integrity sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA== - dependencies: - cosmiconfig "^8.1.3" - deepmerge "^4.3.1" - svgo "^3.0.2" - -"@svgr/webpack@^8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz" - integrity sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA== - dependencies: - "@babel/core" "^7.21.3" - "@babel/plugin-transform-react-constant-elements" "^7.21.3" - "@babel/preset-env" "^7.20.2" - "@babel/preset-react" "^7.18.6" - "@babel/preset-typescript" "^7.21.0" - "@svgr/core" "8.1.0" - "@svgr/plugin-jsx" "8.1.0" - "@svgr/plugin-svgo" "8.1.0" - -"@szmarczak/http-timer@^5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz" - integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== - dependencies: - defer-to-connect "^2.0.1" - -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - -"@types/acorn@^4.0.0": - version "4.0.6" - resolved "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz" - integrity sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ== - dependencies: - "@types/estree" "*" - -"@types/body-parser@*": - version "1.19.5" - resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" - integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== - dependencies: - "@types/connect" "*" - "@types/node" "*" - -"@types/bonjour@^3.5.9": - version "3.5.13" - resolved "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz" - integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== - dependencies: - "@types/node" "*" - -"@types/connect-history-api-fallback@^1.3.5": - version "1.5.4" - resolved "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz" - integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== - dependencies: - "@types/express-serve-static-core" "*" - "@types/node" "*" - -"@types/connect@*": - version "3.4.38" - resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" - integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== - dependencies: - "@types/node" "*" - -"@types/debug@^4.0.0": - version "4.1.12" - resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - dependencies: - "@types/ms" "*" - -"@types/eslint-scope@^3.7.7": - version "3.7.7" - resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz" - integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "9.6.1" - resolved "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz" - integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree-jsx@^1.0.0": - version "1.0.5" - resolved "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz" - integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== - dependencies: - "@types/estree" "*" - -"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6": - version "1.0.6" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz" - integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== - -"@types/express-serve-static-core@*": - version "5.0.5" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.5.tgz" - integrity sha512-GLZPrd9ckqEBFMcVM/qRFAP0Hg3qiVEojgEFsx/N/zKXsBzbGF6z5FBDpZ0+Xhp1xr+qRZYjfGr1cWHB9oFHSA== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - "@types/send" "*" - -"@types/express-serve-static-core@^4.17.33": - version "4.19.6" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz" - integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - "@types/send" "*" - -"@types/express@*", "@types/express@^4.17.13": - version "4.17.21" - resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" - integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.33" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/gtag.js@^0.0.12": - version "0.0.12" - resolved "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz" - integrity sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg== - -"@types/hast@^3.0.0": - version "3.0.4" - resolved "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz" - integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== - dependencies: - "@types/unist" "*" - -"@types/history@^4.7.11": - version "4.7.11" - resolved "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz" - integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== - -"@types/html-minifier-terser@^6.0.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" - integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== - -"@types/http-cache-semantics@^4.0.2": - version "4.0.4" - resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz" - integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== - -"@types/http-errors@*": - version "2.0.4" - resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" - integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== - -"@types/http-proxy@^1.17.8": - version "1.17.15" - resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz" - integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.6" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.4" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" - integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.15" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/mdast@^4.0.0", "@types/mdast@^4.0.2": - version "4.0.4" - resolved "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz" - integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== - dependencies: - "@types/unist" "*" - -"@types/mdx@^2.0.0": - version "2.0.13" - resolved "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz" - integrity sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw== - -"@types/mime@^1": - version "1.3.5" - resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" - integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== - -"@types/ms@*": - version "2.1.0" - resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz" - integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== - -"@types/node-forge@^1.3.0": - version "1.3.11" - resolved "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz" - integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== - dependencies: - "@types/node" "*" - -"@types/node@*": - version "22.10.10" - resolved "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz" - integrity sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww== - dependencies: - undici-types "~6.20.0" - -"@types/node@^17.0.5": - version "17.0.45" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz" - integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== - -"@types/parse-json@^4.0.0": - version "4.0.2" - resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz" - integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== - -"@types/prismjs@^1.26.0": - version "1.26.5" - resolved "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz" - integrity sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ== - -"@types/prop-types@*": - version "15.7.14" - resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz" - integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== - -"@types/qs@*": - version "6.9.18" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz" - integrity sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA== - -"@types/range-parser@*": - version "1.2.7" - resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" - integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== - -"@types/react-router-config@*", "@types/react-router-config@^5.0.7": - version "5.0.11" - resolved "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz" - integrity sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "^5.1.0" - -"@types/react-router-dom@*": - version "5.3.3" - resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*", "@types/react-router@^5.1.0": - version "5.1.20" - resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz" - integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - -"@types/react@*": - version "18.3.18" - resolved "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz" - integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/retry@0.12.0": - version "0.12.0" - resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== - -"@types/sax@^1.2.1": - version "1.2.7" - resolved "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz" - integrity sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A== - dependencies: - "@types/node" "*" - -"@types/send@*": - version "0.17.4" - resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" - integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== - dependencies: - "@types/mime" "^1" - "@types/node" "*" - -"@types/serve-index@^1.9.1": - version "1.9.4" - resolved "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz" - integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== - dependencies: - "@types/express" "*" - -"@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.7" - resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" - integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== - dependencies: - "@types/http-errors" "*" - "@types/node" "*" - "@types/send" "*" - -"@types/sockjs@^0.3.33": - version "0.3.36" - resolved "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz" - integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== - dependencies: - "@types/node" "*" - -"@types/unist@*", "@types/unist@^3.0.0": - version "3.0.3" - resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz" - integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== - -"@types/unist@^2.0.0": - version "2.0.11" - resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz" - integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== - -"@types/ws@^8.5.5": - version "8.5.14" - resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz" - integrity sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^17.0.8": - version "17.0.33" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz" - integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== - dependencies: - "@types/yargs-parser" "*" - -"@ungap/structured-clone@^1.0.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" - integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== - -"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz" - integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== - dependencies: - "@webassemblyjs/helper-numbers" "1.13.2" - "@webassemblyjs/helper-wasm-bytecode" "1.13.2" - -"@webassemblyjs/floating-point-hex-parser@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz" - integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== - -"@webassemblyjs/helper-api-error@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz" - integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== - -"@webassemblyjs/helper-buffer@1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz" - integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== - -"@webassemblyjs/helper-numbers@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz" - integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.13.2" - "@webassemblyjs/helper-api-error" "1.13.2" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz" - integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== - -"@webassemblyjs/helper-wasm-section@1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz" - integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@webassemblyjs/helper-buffer" "1.14.1" - "@webassemblyjs/helper-wasm-bytecode" "1.13.2" - "@webassemblyjs/wasm-gen" "1.14.1" - -"@webassemblyjs/ieee754@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz" - integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz" - integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.13.2": - version "1.13.2" - resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz" - integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== - -"@webassemblyjs/wasm-edit@^1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz" - integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@webassemblyjs/helper-buffer" "1.14.1" - "@webassemblyjs/helper-wasm-bytecode" "1.13.2" - "@webassemblyjs/helper-wasm-section" "1.14.1" - "@webassemblyjs/wasm-gen" "1.14.1" - "@webassemblyjs/wasm-opt" "1.14.1" - "@webassemblyjs/wasm-parser" "1.14.1" - "@webassemblyjs/wast-printer" "1.14.1" - -"@webassemblyjs/wasm-gen@1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz" - integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@webassemblyjs/helper-wasm-bytecode" "1.13.2" - "@webassemblyjs/ieee754" "1.13.2" - "@webassemblyjs/leb128" "1.13.2" - "@webassemblyjs/utf8" "1.13.2" - -"@webassemblyjs/wasm-opt@1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz" - integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@webassemblyjs/helper-buffer" "1.14.1" - "@webassemblyjs/wasm-gen" "1.14.1" - "@webassemblyjs/wasm-parser" "1.14.1" - -"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz" - integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@webassemblyjs/helper-api-error" "1.13.2" - "@webassemblyjs/helper-wasm-bytecode" "1.13.2" - "@webassemblyjs/ieee754" "1.13.2" - "@webassemblyjs/leb128" "1.13.2" - "@webassemblyjs/utf8" "1.13.2" - -"@webassemblyjs/wast-printer@1.14.1": - version "1.14.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz" - integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== - dependencies: - "@webassemblyjs/ast" "1.14.1" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -accepts@~1.3.4, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-jsx@^5.0.0: - version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.0.0: - version "8.3.4" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" - -acorn@^8.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.2: - version "8.14.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz" - integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== - -address@^1.0.1, address@^1.1.2: - version "1.2.2" - resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz" - integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - -ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv-keywords@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz" - integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== - dependencies: - fast-deep-equal "^3.1.3" - -ajv@^6.12.2, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.0, ajv@^8.9.0: - version "8.17.1" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== - dependencies: - fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - -algoliasearch-helper@^3.22.6: - version "3.23.1" - resolved "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.23.1.tgz" - integrity sha512-j/dF2ZELJBm4SJTK5ECsMuCDJpBB8ITiWKRjd3S15bK2bqrXKLWqDiA5A96WhVvCpZ2NmgNlUYmFbKOfcqivbg== - dependencies: - "@algolia/events" "^4.0.1" - -algoliasearch@^5.14.2, algoliasearch@^5.17.1: - version "5.20.0" - resolved "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.20.0.tgz" - integrity sha512-groO71Fvi5SWpxjI9Ia+chy0QBwT61mg6yxJV27f5YFf+Mw+STT75K6SHySpP8Co5LsCrtsbCH5dJZSRtkSKaQ== - dependencies: - "@algolia/client-abtesting" "5.20.0" - "@algolia/client-analytics" "5.20.0" - "@algolia/client-common" "5.20.0" - "@algolia/client-insights" "5.20.0" - "@algolia/client-personalization" "5.20.0" - "@algolia/client-query-suggestions" "5.20.0" - "@algolia/client-search" "5.20.0" - "@algolia/ingestion" "1.20.0" - "@algolia/monitoring" "1.20.0" - "@algolia/recommend" "5.20.0" - "@algolia/requester-browser-xhr" "5.20.0" - "@algolia/requester-fetch" "5.20.0" - "@algolia/requester-node-http" "5.20.0" - -ansi-align@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - -ansi-escapes@^4.3.2: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-html-community@^0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz" - integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^5.0.0, arg@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -astring@^1.8.0: - version "1.9.0" - resolved "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz" - integrity sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg== - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -autoprefixer@^10.4.17, autoprefixer@^10.4.19: - version "10.4.20" - resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz" - integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g== - dependencies: - browserslist "^4.23.3" - caniuse-lite "^1.0.30001646" - fraction.js "^4.3.7" - normalize-range "^0.1.2" - picocolors "^1.0.1" - postcss-value-parser "^4.2.0" - -babel-loader@^9.2.1: - version "9.2.1" - resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz" - integrity sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA== - dependencies: - find-cache-dir "^4.0.0" - schema-utils "^4.0.0" - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-polyfill-corejs2@^0.4.10: - version "0.4.12" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz" - integrity sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og== - dependencies: - "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.6.3" - semver "^6.3.1" - -babel-plugin-polyfill-corejs3@^0.10.6: - version "0.10.6" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz" - integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.2" - core-js-compat "^3.38.0" - -babel-plugin-polyfill-regenerator@^0.6.1: - version "0.6.3" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz" - integrity sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.3" - -bail@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz" - integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" - integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - -body-parser@1.20.3: - version "1.20.3" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== - dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.13.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" - -bonjour-service@^1.0.11: - version "1.3.0" - resolved "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz" - integrity sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA== - dependencies: - fast-deep-equal "^3.1.3" - multicast-dns "^7.2.5" - -boolbase@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" - integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== - -boxen@^6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz" - integrity sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw== - dependencies: - ansi-align "^3.0.1" - camelcase "^6.2.0" - chalk "^4.1.2" - cli-boxes "^3.0.0" - string-width "^5.0.1" - type-fest "^2.5.0" - widest-line "^4.0.1" - wrap-ansi "^8.0.1" - -boxen@^7.0.0: - version "7.1.1" - resolved "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz" - integrity sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog== - dependencies: - ansi-align "^3.0.1" - camelcase "^7.0.1" - chalk "^5.2.0" - cli-boxes "^3.0.0" - string-width "^5.1.2" - type-fest "^2.13.0" - widest-line "^4.0.1" - wrap-ansi "^8.1.0" - -brace-expansion@^1.1.7: - version "1.1.12" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" - integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz" - integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.3, braces@~3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.23.0, browserslist@^4.23.1, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.3: - version "4.24.4" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz" - integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== - dependencies: - caniuse-lite "^1.0.30001688" - electron-to-chromium "^1.5.73" - node-releases "^2.0.19" - update-browserslist-db "^1.1.1" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - -cacheable-lookup@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz" - integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== - -cacheable-request@^10.2.8: - version "10.2.14" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz" - integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== - dependencies: - "@types/http-cache-semantics" "^4.0.2" - get-stream "^6.0.1" - http-cache-semantics "^4.1.1" - keyv "^4.5.3" - mimic-response "^4.0.0" - normalize-url "^8.0.0" - responselike "^3.0.0" - -call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz" - integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - -call-bind@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz" - integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== - dependencies: - call-bind-apply-helpers "^1.0.0" - es-define-property "^1.0.0" - get-intrinsic "^1.2.4" - set-function-length "^1.2.2" - -call-bound@^1.0.2, call-bound@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz" - integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== - dependencies: - call-bind-apply-helpers "^1.0.1" - get-intrinsic "^1.2.6" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camel-case@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz" - integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - -camelcase-css@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - -camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -camelcase@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz" - integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688: - version "1.0.30001695" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz" - integrity sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw== - -ccount@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz" - integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== - -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^5.0.1, chalk@^5.2.0: - version "5.4.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz" - integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -character-entities-html4@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz" - integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== - -character-entities-legacy@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz" - integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - -character-entities@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz" - integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== - -character-reference-invalid@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz" - integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== - -cheerio-select@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz" - integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== - dependencies: - boolbase "^1.0.0" - css-select "^5.1.0" - css-what "^6.1.0" - domelementtype "^2.3.0" - domhandler "^5.0.3" - domutils "^3.0.1" - -cheerio@1.0.0-rc.12: - version "1.0.0-rc.12" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz" - integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== - dependencies: - cheerio-select "^2.1.0" - dom-serializer "^2.0.0" - domhandler "^5.0.3" - domutils "^3.0.1" - htmlparser2 "^8.0.1" - parse5 "^7.0.0" - parse5-htmlparser2-tree-adapter "^7.0.0" - -chokidar@^3.4.2, chokidar@^3.5.3, chokidar@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chrome-trace-event@^1.0.2: - version "1.0.4" - resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz" - integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== - -ci-info@^3.2.0: - version "3.9.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" - integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== - -clean-css@^5.2.2, clean-css@^5.3.2, clean-css@~5.3.2: - version "5.3.3" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz" - integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg== - dependencies: - source-map "~0.6.0" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-boxes@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz" - integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== - -cli-table3@^0.6.3: - version "0.6.5" - resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz" - integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== - dependencies: - string-width "^4.2.0" - optionalDependencies: - "@colors/colors" "1.5.0" - -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clsx@^2.0.0, clsx@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" - integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== - -collapse-white-space@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz" - integrity sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colord@^2.9.3: - version "2.9.3" - resolved "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz" - integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== - -colorette@^2.0.10: - version "2.0.20" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz" - integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== - -combine-promises@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz" - integrity sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ== - -comma-separated-tokens@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz" - integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== - -commander@^10.0.0: - version "10.0.1" - resolved "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz" - integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - -commander@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - -commander@^7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - -common-path-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz" - integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== - -compressible@~2.0.18: - version "2.0.18" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.8.1" - resolved "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz" - integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w== - 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" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -config-chain@^1.1.11: - version "1.1.13" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -configstore@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz" - integrity sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA== - dependencies: - dot-prop "^6.0.1" - graceful-fs "^4.2.6" - unique-string "^3.0.0" - write-file-atomic "^3.0.3" - xdg-basedir "^5.0.1" - -connect-history-api-fallback@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz" - integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== - -consola@^3.2.3: - version "3.4.0" - resolved "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz" - integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== - -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz" - integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== - -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4, content-type@~1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz" - integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== - -copy-text-to-clipboard@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz" - integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q== - -copy-webpack-plugin@^11.0.0: - version "11.0.0" - resolved "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz" - integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== - dependencies: - fast-glob "^3.2.11" - glob-parent "^6.0.1" - globby "^13.1.1" - normalize-path "^3.0.0" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" - -core-js-compat@^3.38.0, core-js-compat@^3.38.1: - version "3.40.0" - resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz" - integrity sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ== - dependencies: - browserslist "^4.24.3" - -core-js-pure@^3.30.2: - version "3.40.0" - resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.40.0.tgz" - integrity sha512-AtDzVIgRrmRKQai62yuSIN5vNiQjcJakJb4fbhVw3ehxx7Lohphvw9SGNWKhLFqSxC4ilD0g/L1huAYFQU3Q6A== - -core-js@^3.31.1: - version "3.40.0" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz" - integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -cosmiconfig@^8.1.3, cosmiconfig@^8.3.5: - version "8.3.6" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz" - integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== - dependencies: - import-fresh "^3.3.0" - js-yaml "^4.1.0" - parse-json "^5.2.0" - path-type "^4.0.0" - -cross-spawn@^7.0.3, cross-spawn@^7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-random-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz" - integrity sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA== - dependencies: - type-fest "^1.0.1" - -css-blank-pseudo@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz" - integrity sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag== - dependencies: - postcss-selector-parser "^7.0.0" - -css-declaration-sorter@^7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz" - integrity sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow== - -css-has-pseudo@^7.0.2: - version "7.0.2" - resolved "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.2.tgz" - integrity sha512-nzol/h+E0bId46Kn2dQH5VElaknX2Sr0hFuB/1EomdC7j+OISt2ZzK7EHX9DZDY53WbIVAR7FYKSO2XnSf07MQ== - dependencies: - "@csstools/selector-specificity" "^5.0.0" - postcss-selector-parser "^7.0.0" - postcss-value-parser "^4.2.0" - -css-loader@^6.8.1: - version "6.11.0" - resolved "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz" - integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g== - dependencies: - icss-utils "^5.1.0" - postcss "^8.4.33" - postcss-modules-extract-imports "^3.1.0" - postcss-modules-local-by-default "^4.0.5" - postcss-modules-scope "^3.2.0" - postcss-modules-values "^4.0.0" - postcss-value-parser "^4.2.0" - semver "^7.5.4" - -css-minimizer-webpack-plugin@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz" - integrity sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - cssnano "^6.0.1" - jest-worker "^29.4.3" - postcss "^8.4.24" - schema-utils "^4.0.1" - serialize-javascript "^6.0.1" - -css-prefers-color-scheme@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz" - integrity sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ== - -css-select@^4.1.3: - version "4.3.0" - resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" - integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== - dependencies: - boolbase "^1.0.0" - css-what "^6.0.1" - domhandler "^4.3.1" - domutils "^2.8.0" - nth-check "^2.0.1" - -css-select@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz" - integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== - dependencies: - boolbase "^1.0.0" - css-what "^6.1.0" - domhandler "^5.0.2" - domutils "^3.0.1" - nth-check "^2.0.1" - -css-tree@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz" - integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== - dependencies: - mdn-data "2.0.30" - source-map-js "^1.0.1" - -css-tree@~2.2.0: - version "2.2.1" - resolved "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz" - integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== - dependencies: - mdn-data "2.0.28" - source-map-js "^1.0.1" - -css-what@^6.0.1, css-what@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" - integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== - -cssdb@^8.2.3: - version "8.2.3" - resolved "https://registry.npmjs.org/cssdb/-/cssdb-8.2.3.tgz" - integrity sha512-9BDG5XmJrJQQnJ51VFxXCAtpZ5ebDlAREmO8sxMOVU0aSxN/gocbctjIG5LMh3WBUq+xTlb/jw2LoljBEqraTA== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-advanced@^6.1.2: - version "6.1.2" - resolved "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz" - integrity sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ== - dependencies: - autoprefixer "^10.4.19" - browserslist "^4.23.0" - cssnano-preset-default "^6.1.2" - postcss-discard-unused "^6.0.5" - postcss-merge-idents "^6.0.3" - postcss-reduce-idents "^6.0.3" - postcss-zindex "^6.0.2" - -cssnano-preset-default@^6.1.2: - version "6.1.2" - resolved "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz" - integrity sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg== - dependencies: - browserslist "^4.23.0" - css-declaration-sorter "^7.2.0" - cssnano-utils "^4.0.2" - postcss-calc "^9.0.1" - postcss-colormin "^6.1.0" - postcss-convert-values "^6.1.0" - postcss-discard-comments "^6.0.2" - postcss-discard-duplicates "^6.0.3" - postcss-discard-empty "^6.0.3" - postcss-discard-overridden "^6.0.2" - postcss-merge-longhand "^6.0.5" - postcss-merge-rules "^6.1.1" - postcss-minify-font-values "^6.1.0" - postcss-minify-gradients "^6.0.3" - postcss-minify-params "^6.1.0" - postcss-minify-selectors "^6.0.4" - postcss-normalize-charset "^6.0.2" - postcss-normalize-display-values "^6.0.2" - postcss-normalize-positions "^6.0.2" - postcss-normalize-repeat-style "^6.0.2" - postcss-normalize-string "^6.0.2" - postcss-normalize-timing-functions "^6.0.2" - postcss-normalize-unicode "^6.1.0" - postcss-normalize-url "^6.0.2" - postcss-normalize-whitespace "^6.0.2" - postcss-ordered-values "^6.0.2" - postcss-reduce-initial "^6.1.0" - postcss-reduce-transforms "^6.0.2" - postcss-svgo "^6.0.3" - postcss-unique-selectors "^6.0.4" - -cssnano-utils@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz" - integrity sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ== - -cssnano@^6.0.1, cssnano@^6.1.2: - version "6.1.2" - resolved "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz" - integrity sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA== - dependencies: - cssnano-preset-default "^6.1.2" - lilconfig "^3.1.1" - -csso@^5.0.5: - version "5.0.5" - resolved "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz" - integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== - dependencies: - css-tree "~2.2.0" - -csstype@^3.0.2, csstype@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -debounce@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - -debug@2.6.9, debug@^2.6.0: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.4.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - -decode-named-character-reference@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz" - integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== - dependencies: - character-entities "^2.0.0" - -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deepmerge@^4.2.2, deepmerge@^4.3.1: - version "4.3.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -default-gateway@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== - dependencies: - execa "^5.0.0" - -defer-to-connect@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== - -define-data-property@^1.0.1, define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - -define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -del@^6.1.1: - version "6.1.1" - resolved "https://registry.npmjs.org/del/-/del-6.1.1.tgz" - integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== - dependencies: - globby "^11.0.1" - graceful-fs "^4.2.4" - is-glob "^4.0.1" - is-path-cwd "^2.2.0" - is-path-inside "^3.0.2" - p-map "^4.0.0" - rimraf "^3.0.2" - slash "^3.0.0" - -depd@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -dequal@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" - integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== - -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-node@^2.0.4: - version "2.1.0" - resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz" - integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== - -detect-port-alt@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz" - integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== - dependencies: - address "^1.0.1" - debug "^2.6.0" - -detect-port@^1.5.1: - version "1.6.1" - resolved "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz" - integrity sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q== - dependencies: - address "^1.0.1" - debug "4" - -devlop@^1.0.0, devlop@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz" - integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== - dependencies: - dequal "^2.0.0" - -didyoumean@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" - integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -dlv@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" - integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== - -dns-packet@^5.2.2: - version "5.6.1" - resolved "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz" - integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw== - dependencies: - "@leichtgewicht/ip-codec" "^2.0.1" - -dom-converter@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - -dom-serializer@^1.0.1: - version "1.4.1" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" - integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -dom-serializer@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz" - integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - entities "^4.2.0" - -domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - -domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: - version "4.3.1" - resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz" - integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== - dependencies: - domelementtype "^2.2.0" - -domhandler@^5.0.2, domhandler@^5.0.3: - version "5.0.3" - resolved "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz" - integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== - dependencies: - domelementtype "^2.3.0" - -domutils@^2.5.2, domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -domutils@^3.0.1: - version "3.2.2" - resolved "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz" - integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== - dependencies: - dom-serializer "^2.0.0" - domelementtype "^2.3.0" - domhandler "^5.0.3" - -dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - -dotenv@^16.4.7: - version "16.4.7" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz" - integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== - -dunder-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" - integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-errors "^1.3.0" - gopd "^1.2.0" - -duplexer@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.5.73: - version "1.5.87" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.87.tgz" - integrity sha512-mPFwmEWmRivw2F8x3w3l2m6htAUN97Gy0kwpO++2m9iT1Gt8RCFVUfv9U/sIbHJ6rY4P6/ooqFL/eL7ock+pPg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -emojilib@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz" - integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw== - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -emoticon@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz" - integrity sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz" - integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== - -enhanced-resolve@^5.17.1: - version "5.18.0" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz" - integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-define-property@^1.0.0, es-define-property@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" - integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-module-lexer@^1.2.1: - version "1.6.0" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz" - integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== - -es-object-atoms@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== - dependencies: - es-errors "^1.3.0" - -esast-util-from-estree@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz" - integrity sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ== - dependencies: - "@types/estree-jsx" "^1.0.0" - devlop "^1.0.0" - estree-util-visit "^2.0.0" - unist-util-position-from-estree "^2.0.0" - -esast-util-from-js@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz" - integrity sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw== - dependencies: - "@types/estree-jsx" "^1.0.0" - acorn "^8.0.0" - esast-util-from-estree "^2.0.0" - vfile-message "^4.0.0" - -escalade@^3.1.1, escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-goat@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz" - integrity sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg== - -escape-html@^1.0.3, escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escape-string-regexp@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz" - integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== - -eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estree-util-attach-comments@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz" - integrity sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw== - dependencies: - "@types/estree" "^1.0.0" - -estree-util-build-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz" - integrity sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ== - dependencies: - "@types/estree-jsx" "^1.0.0" - devlop "^1.0.0" - estree-util-is-identifier-name "^3.0.0" - estree-walker "^3.0.0" - -estree-util-is-identifier-name@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz" - integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== - -estree-util-scope@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz" - integrity sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ== - dependencies: - "@types/estree" "^1.0.0" - devlop "^1.0.0" - -estree-util-to-js@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz" - integrity sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg== - dependencies: - "@types/estree-jsx" "^1.0.0" - astring "^1.8.0" - source-map "^0.7.0" - -estree-util-value-to-estree@^3.0.1: - version "3.4.0" - resolved "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.4.0.tgz" - integrity sha512-Zlp+gxis+gCfK12d3Srl2PdX2ybsEA8ZYy6vQGVQTNNYLEGRQQ56XB64bjemN8kxIKXP1nC9ip4Z+ILy9LGzvQ== - dependencies: - "@types/estree" "^1.0.0" - -estree-util-visit@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz" - integrity sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/unist" "^3.0.0" - -estree-walker@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz" - integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== - dependencies: - "@types/estree" "^1.0.0" - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eta@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz" - integrity sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -eval@^0.1.8: - version "0.1.8" - resolved "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz" - integrity sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw== - dependencies: - "@types/node" "*" - require-like ">= 0.1.1" - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -events@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -express@^4.17.3: - version "4.21.2" - resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz" - integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.3" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.7.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~2.0.0" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.3.1" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.3" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.12" - proxy-addr "~2.0.7" - qs "6.13.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: - version "3.3.3" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz" - integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.8" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-uri@^3.0.1: - version "3.0.6" - resolved "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz" - integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== - -fastq@^1.6.0: - version "1.18.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz" - integrity sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw== - dependencies: - reusify "^1.0.4" - -fault@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz" - integrity sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ== - dependencies: - format "^0.2.0" - -faye-websocket@^0.11.3: - version "0.11.4" - resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - -feed@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz" - integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ== - dependencies: - xml-js "^1.6.11" - -figures@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-loader@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" - integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -filesize@^8.0.6: - version "8.0.7" - resolved "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz" - integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== - dependencies: - debug "2.6.9" - encodeurl "~2.0.0" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - -find-cache-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz" - integrity sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg== - dependencies: - common-path-prefix "^3.0.0" - pkg-dir "^7.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz" - integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw== - dependencies: - locate-path "^7.1.0" - path-exists "^5.0.0" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -follow-redirects@^1.0.0: - version "1.15.9" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== - -foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== - dependencies: - cross-spawn "^7.0.6" - signal-exit "^4.0.1" - -fork-ts-checker-webpack-plugin@^6.5.0: - version "6.5.3" - resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz" - integrity sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ== - dependencies: - "@babel/code-frame" "^7.8.3" - "@types/json-schema" "^7.0.5" - chalk "^4.1.0" - chokidar "^3.4.2" - cosmiconfig "^6.0.0" - deepmerge "^4.2.2" - fs-extra "^9.0.0" - glob "^7.1.6" - memfs "^3.1.2" - minimatch "^3.0.4" - schema-utils "2.7.0" - semver "^7.3.2" - tapable "^1.0.0" - -form-data-encoder@^2.1.2: - version "2.1.4" - resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz" - integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== - -format@^0.2.0: - version "0.2.2" - resolved "https://registry.npmjs.org/format/-/format-0.2.2.tgz" - integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fraction.js@^4.3.7: - version "4.3.7" - resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz" - integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== - -framer-motion@^11.0.0: - version "11.18.2" - resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz" - integrity sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w== - dependencies: - motion-dom "^11.18.1" - motion-utils "^11.18.1" - tslib "^2.4.0" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -fs-extra@^11.1.1, fs-extra@^11.2.0: - version "11.3.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz" - integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^9.0.0: - version "9.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-monkey@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz" - integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: - version "1.2.7" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz" - integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== - dependencies: - call-bind-apply-helpers "^1.0.1" - es-define-property "^1.0.1" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - function-bind "^1.1.2" - get-proto "^1.0.0" - gopd "^1.2.0" - has-symbols "^1.1.0" - hasown "^2.0.2" - math-intrinsics "^1.1.0" - -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - -get-proto@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" - integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== - dependencies: - dunder-proto "^1.0.1" - es-object-atoms "^1.0.0" - -get-stream@^6.0.0, get-stream@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -github-slugger@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz" - integrity sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw== - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1, glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@^10.3.10: - version "10.4.5" - resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz" - integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== - dependencies: - ini "2.0.0" - -global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -globby@^13.1.1: - version "13.2.2" - resolved "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz" - integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== - dependencies: - dir-glob "^3.0.1" - fast-glob "^3.3.0" - ignore "^5.2.4" - merge2 "^1.4.1" - slash "^4.0.0" - -goober@^2.1.16: - version "2.1.16" - resolved "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz" - integrity sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g== - -gopd@^1.0.1, gopd@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" - integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== - -got@^12.1.0: - version "12.6.1" - resolved "https://registry.npmjs.org/got/-/got-12.6.1.tgz" - integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== - dependencies: - "@sindresorhus/is" "^5.2.0" - "@szmarczak/http-timer" "^5.0.1" - cacheable-lookup "^7.0.0" - cacheable-request "^10.2.8" - decompress-response "^6.0.0" - form-data-encoder "^2.1.2" - get-stream "^6.0.1" - http2-wrapper "^2.1.10" - lowercase-keys "^3.0.0" - p-cancelable "^3.0.0" - responselike "^3.0.0" - -graceful-fs@4.2.10: - version "4.2.10" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -gray-matter@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz" - integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== - dependencies: - js-yaml "^3.13.1" - kind-of "^6.0.2" - section-matter "^1.0.0" - strip-bom-string "^1.0.0" - -gzip-size@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz" - integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== - dependencies: - duplexer "^0.1.2" - -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz" - integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" - integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== - -has-yarn@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz" - integrity sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA== - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -hast-util-from-parse5@^8.0.0: - version "8.0.2" - resolved "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz" - integrity sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - devlop "^1.0.0" - hastscript "^9.0.0" - property-information "^6.0.0" - vfile "^6.0.0" - vfile-location "^5.0.0" - web-namespaces "^2.0.0" - -hast-util-parse-selector@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz" - integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== - dependencies: - "@types/hast" "^3.0.0" - -hast-util-raw@^9.0.0: - version "9.1.0" - resolved "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz" - integrity sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw== - dependencies: - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - "@ungap/structured-clone" "^1.0.0" - hast-util-from-parse5 "^8.0.0" - hast-util-to-parse5 "^8.0.0" - html-void-elements "^3.0.0" - mdast-util-to-hast "^13.0.0" - parse5 "^7.0.0" - unist-util-position "^5.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - web-namespaces "^2.0.0" - zwitch "^2.0.0" - -hast-util-to-estree@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.1.tgz" - integrity sha512-IWtwwmPskfSmma9RpzCappDUitC8t5jhAynHhc1m2+5trOgsrp7txscUSavc5Ic8PATyAjfrCK1wgtxh2cICVQ== - dependencies: - "@types/estree" "^1.0.0" - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - devlop "^1.0.0" - estree-util-attach-comments "^3.0.0" - estree-util-is-identifier-name "^3.0.0" - hast-util-whitespace "^3.0.0" - mdast-util-mdx-expression "^2.0.0" - mdast-util-mdx-jsx "^3.0.0" - mdast-util-mdxjs-esm "^2.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - style-to-object "^1.0.0" - unist-util-position "^5.0.0" - zwitch "^2.0.0" - -hast-util-to-jsx-runtime@^2.0.0: - version "2.3.2" - resolved "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz" - integrity sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg== - dependencies: - "@types/estree" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/unist" "^3.0.0" - comma-separated-tokens "^2.0.0" - devlop "^1.0.0" - estree-util-is-identifier-name "^3.0.0" - hast-util-whitespace "^3.0.0" - mdast-util-mdx-expression "^2.0.0" - mdast-util-mdx-jsx "^3.0.0" - mdast-util-mdxjs-esm "^2.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - style-to-object "^1.0.0" - unist-util-position "^5.0.0" - vfile-message "^4.0.0" - -hast-util-to-parse5@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz" - integrity sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw== - dependencies: - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - devlop "^1.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - web-namespaces "^2.0.0" - zwitch "^2.0.0" - -hast-util-whitespace@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz" - integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== - dependencies: - "@types/hast" "^3.0.0" - -hastscript@^9.0.0: - version "9.0.0" - resolved "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz" - integrity sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw== - dependencies: - "@types/hast" "^3.0.0" - comma-separated-tokens "^2.0.0" - hast-util-parse-selector "^4.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - -he@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -history@^4.9.0: - version "4.10.1" - resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - -hoist-non-react-statics@^3.1.0: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz" - integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -html-entities@^2.3.2: - version "2.5.2" - resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz" - integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== - -html-escaper@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -html-minifier-terser@^6.0.2: - version "6.1.0" - resolved "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" - integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== - dependencies: - camel-case "^4.1.2" - clean-css "^5.2.2" - commander "^8.3.0" - he "^1.2.0" - param-case "^3.0.4" - relateurl "^0.2.7" - terser "^5.10.0" - -html-minifier-terser@^7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz" - integrity sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA== - dependencies: - camel-case "^4.1.2" - clean-css "~5.3.2" - commander "^10.0.0" - entities "^4.4.0" - param-case "^3.0.4" - relateurl "^0.2.7" - terser "^5.15.1" - -html-tags@^3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz" - integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== - -html-url-attributes@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz" - integrity sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ== - -html-void-elements@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz" - integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== - -html-webpack-plugin@^5.6.0: - version "5.6.3" - resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz" - integrity sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg== - dependencies: - "@types/html-minifier-terser" "^6.0.0" - html-minifier-terser "^6.0.2" - lodash "^4.17.21" - pretty-error "^4.0.0" - tapable "^2.0.0" - -htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - -htmlparser2@^8.0.1: - version "8.0.2" - resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz" - integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.3" - domutils "^3.0.1" - entities "^4.4.0" - -http-cache-semantics@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" - integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-parser-js@>=0.5.1: - version "0.5.9" - resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz" - integrity sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw== - -http-proxy-middleware@^2.0.3: - version "2.0.9" - resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz" - integrity sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q== - dependencies: - "@types/http-proxy" "^1.17.8" - http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.2" - -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http2-wrapper@^2.1.10: - version "2.2.1" - resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz" - integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.2.0" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-utils@^5.0.0, icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - -ignore@^5.2.0, ignore@^5.2.4: - version "5.3.2" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -image-size@^1.0.2: - version "1.2.1" - resolved "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz" - integrity sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw== - dependencies: - queue "6.0.2" - -immer@^9.0.7: - version "9.0.21" - resolved "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz" - integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== - -import-fresh@^3.1.0, import-fresh@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-lazy@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz" - integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -infima@0.2.0-alpha.45: - version "0.2.0-alpha.45" - resolved "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz" - integrity sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - -ini@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz" - integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== - -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: - version "1.3.8" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -inline-style-parser@0.2.4: - version "0.2.4" - resolved "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz" - integrity sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q== - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -ipaddr.js@^2.0.1: - version "2.2.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz" - integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== - -is-alphabetical@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz" - integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== - -is-alphanumerical@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz" - integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== - dependencies: - is-alphabetical "^2.0.0" - is-decimal "^2.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-ci@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz" - integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== - dependencies: - ci-info "^3.2.0" - -is-core-module@^2.16.0: - version "2.16.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== - dependencies: - hasown "^2.0.2" - -is-decimal@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz" - integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== - -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz" - integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== - -is-installed-globally@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz" - integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== - dependencies: - global-dirs "^3.0.0" - is-path-inside "^3.0.2" - -is-npm@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz" - integrity sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz" - integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-cwd@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - -is-plain-obj@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz" - integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== - -is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz" - integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== - -is-root@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz" - integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -is-yarn-global@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz" - integrity sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -javascript-stringify@^2.0.1: - version "2.1.0" - resolved "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz" - integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== - -jest-util@^29.7.0: - version "29.7.0" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" - integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest-worker@^29.4.3: - version "29.7.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== - dependencies: - "@types/node" "*" - jest-util "^29.7.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jiti@^1.20.0, jiti@^1.21.6: - version "1.21.7" - resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz" - integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== - -joi@^17.9.2: - version "17.13.3" - resolved "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz" - integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== - 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@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsesc@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz" - integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== - -jsesc@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json5@^2.1.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -latest-version@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz" - integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== - dependencies: - package-json "^8.1.0" - -launch-editor@^2.6.0: - version "2.9.1" - resolved "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz" - integrity sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w== - dependencies: - picocolors "^1.0.0" - shell-quote "^1.8.1" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -lilconfig@^3.0.0, lilconfig@^3.1.1, lilconfig@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz" - integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== - -loader-utils@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz" - integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -loader-utils@^3.2.0: - version "3.3.1" - resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz" - integrity sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg== - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -locate-path@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz" - integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== - dependencies: - p-locate "^6.0.0" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" - integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== - -lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -longest-streak@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz" - integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== - -loose-envify@^1.0.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - -lowercase-keys@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz" - integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lucide-react@^0.475.0: - version "0.475.0" - resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.475.0.tgz" - integrity sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg== - -markdown-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz" - integrity sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q== - -markdown-table@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz" - integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== - dependencies: - repeat-string "^1.0.0" - -markdown-table@^3.0.0: - version "3.0.4" - resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz" - integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== - -math-intrinsics@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" - integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== - -mdast-util-directive@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz" - integrity sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q== - dependencies: - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - ccount "^2.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - parse-entities "^4.0.0" - stringify-entities "^4.0.0" - unist-util-visit-parents "^6.0.0" - -mdast-util-find-and-replace@^3.0.0, mdast-util-find-and-replace@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz" - integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg== - dependencies: - "@types/mdast" "^4.0.0" - escape-string-regexp "^5.0.0" - unist-util-is "^6.0.0" - unist-util-visit-parents "^6.0.0" - -mdast-util-from-markdown@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz" - integrity sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== - dependencies: - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - mdast-util-to-string "^4.0.0" - micromark "^4.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-decode-string "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - unist-util-stringify-position "^4.0.0" - -mdast-util-frontmatter@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz" - integrity sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA== - dependencies: - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - escape-string-regexp "^5.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - micromark-extension-frontmatter "^2.0.0" - -mdast-util-gfm-autolink-literal@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz" - integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== - dependencies: - "@types/mdast" "^4.0.0" - ccount "^2.0.0" - devlop "^1.0.0" - mdast-util-find-and-replace "^3.0.0" - micromark-util-character "^2.0.0" - -mdast-util-gfm-footnote@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz" - integrity sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ== - dependencies: - "@types/mdast" "^4.0.0" - devlop "^1.1.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - -mdast-util-gfm-strikethrough@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz" - integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-gfm-table@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz" - integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== - dependencies: - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - markdown-table "^3.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-gfm-task-list-item@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz" - integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== - dependencies: - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-gfm@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz" - integrity sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw== - dependencies: - mdast-util-from-markdown "^2.0.0" - mdast-util-gfm-autolink-literal "^2.0.0" - mdast-util-gfm-footnote "^2.0.0" - mdast-util-gfm-strikethrough "^2.0.0" - mdast-util-gfm-table "^2.0.0" - mdast-util-gfm-task-list-item "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-mdx-expression@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz" - integrity sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-mdx-jsx@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz" - integrity sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - ccount "^2.0.0" - devlop "^1.1.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - parse-entities "^4.0.0" - stringify-entities "^4.0.0" - unist-util-stringify-position "^4.0.0" - vfile-message "^4.0.0" - -mdast-util-mdx@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz" - integrity sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w== - dependencies: - mdast-util-from-markdown "^2.0.0" - mdast-util-mdx-expression "^2.0.0" - mdast-util-mdx-jsx "^3.0.0" - mdast-util-mdxjs-esm "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-mdxjs-esm@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz" - integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== - dependencies: - "@types/estree-jsx" "^1.0.0" - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - mdast-util-from-markdown "^2.0.0" - mdast-util-to-markdown "^2.0.0" - -mdast-util-phrasing@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz" - integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== - dependencies: - "@types/mdast" "^4.0.0" - unist-util-is "^6.0.0" - -mdast-util-to-hast@^13.0.0: - version "13.2.0" - resolved "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz" - integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - "@ungap/structured-clone" "^1.0.0" - devlop "^1.0.0" - micromark-util-sanitize-uri "^2.0.0" - trim-lines "^3.0.0" - unist-util-position "^5.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -mdast-util-to-markdown@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz" - integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== - dependencies: - "@types/mdast" "^4.0.0" - "@types/unist" "^3.0.0" - longest-streak "^3.0.0" - mdast-util-phrasing "^4.0.0" - mdast-util-to-string "^4.0.0" - micromark-util-classify-character "^2.0.0" - micromark-util-decode-string "^2.0.0" - unist-util-visit "^5.0.0" - zwitch "^2.0.0" - -mdast-util-to-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz" - integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== - dependencies: - "@types/mdast" "^4.0.0" - -mdn-data@2.0.28: - version "2.0.28" - resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz" - integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== - -mdn-data@2.0.30: - version "2.0.30" - resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz" - integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memfs@^3.1.2, memfs@^3.4.3: - version "3.5.3" - resolved "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz" - integrity sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw== - dependencies: - fs-monkey "^1.0.4" - -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -micromark-core-commonmark@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz" - integrity sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w== - dependencies: - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - micromark-factory-destination "^2.0.0" - micromark-factory-label "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-factory-title "^2.0.0" - micromark-factory-whitespace "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-classify-character "^2.0.0" - micromark-util-html-tag-name "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-resolve-all "^2.0.0" - micromark-util-subtokenize "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-directive@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz" - integrity sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA== - dependencies: - devlop "^1.0.0" - micromark-factory-space "^2.0.0" - micromark-factory-whitespace "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - parse-entities "^4.0.0" - -micromark-extension-frontmatter@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz" - integrity sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg== - dependencies: - fault "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm-autolink-literal@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz" - integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-sanitize-uri "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm-footnote@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz" - integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== - dependencies: - devlop "^1.0.0" - micromark-core-commonmark "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-sanitize-uri "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm-strikethrough@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz" - integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== - dependencies: - devlop "^1.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-classify-character "^2.0.0" - micromark-util-resolve-all "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm-table@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz" - integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg== - dependencies: - devlop "^1.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm-tagfilter@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz" - integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg== - dependencies: - micromark-util-types "^2.0.0" - -micromark-extension-gfm-task-list-item@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz" - integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== - dependencies: - devlop "^1.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-gfm@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz" - integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w== - dependencies: - micromark-extension-gfm-autolink-literal "^2.0.0" - micromark-extension-gfm-footnote "^2.0.0" - micromark-extension-gfm-strikethrough "^2.0.0" - micromark-extension-gfm-table "^2.0.0" - micromark-extension-gfm-tagfilter "^2.0.0" - micromark-extension-gfm-task-list-item "^2.0.0" - micromark-util-combine-extensions "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-mdx-expression@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz" - integrity sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ== - dependencies: - "@types/estree" "^1.0.0" - devlop "^1.0.0" - micromark-factory-mdx-expression "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-events-to-acorn "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-extension-mdx-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz" - integrity sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg== - dependencies: - "@types/acorn" "^4.0.0" - "@types/estree" "^1.0.0" - devlop "^1.0.0" - estree-util-is-identifier-name "^3.0.0" - micromark-factory-mdx-expression "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-events-to-acorn "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - vfile-message "^4.0.0" - -micromark-extension-mdx-md@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz" - integrity sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ== - dependencies: - micromark-util-types "^2.0.0" - -micromark-extension-mdxjs-esm@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz" - integrity sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A== - dependencies: - "@types/estree" "^1.0.0" - devlop "^1.0.0" - micromark-core-commonmark "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-events-to-acorn "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - unist-util-position-from-estree "^2.0.0" - vfile-message "^4.0.0" - -micromark-extension-mdxjs@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz" - integrity sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ== - dependencies: - acorn "^8.0.0" - acorn-jsx "^5.0.0" - micromark-extension-mdx-expression "^3.0.0" - micromark-extension-mdx-jsx "^3.0.0" - micromark-extension-mdx-md "^2.0.0" - micromark-extension-mdxjs-esm "^3.0.0" - micromark-util-combine-extensions "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-destination@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz" - integrity sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-label@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz" - integrity sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== - dependencies: - devlop "^1.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-mdx-expression@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz" - integrity sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw== - dependencies: - "@types/estree" "^1.0.0" - devlop "^1.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-events-to-acorn "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - unist-util-position-from-estree "^2.0.0" - vfile-message "^4.0.0" - -micromark-factory-space@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz" - integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-factory-space@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz" - integrity sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-title@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz" - integrity sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== - dependencies: - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-factory-whitespace@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz" - integrity sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== - dependencies: - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-character@^1.0.0, micromark-util-character@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz" - integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - -micromark-util-character@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz" - integrity sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== - dependencies: - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-chunked@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz" - integrity sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-classify-character@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz" - integrity sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-combine-extensions@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz" - integrity sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== - dependencies: - micromark-util-chunked "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-decode-numeric-character-reference@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz" - integrity sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-decode-string@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz" - integrity sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-util-character "^2.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-symbol "^2.0.0" - -micromark-util-encode@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz" - integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== - -micromark-util-events-to-acorn@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz" - integrity sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA== - dependencies: - "@types/acorn" "^4.0.0" - "@types/estree" "^1.0.0" - "@types/unist" "^3.0.0" - devlop "^1.0.0" - estree-util-visit "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - vfile-message "^4.0.0" - -micromark-util-html-tag-name@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz" - integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== - -micromark-util-normalize-identifier@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz" - integrity sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== - dependencies: - micromark-util-symbol "^2.0.0" - -micromark-util-resolve-all@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz" - integrity sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== - dependencies: - micromark-util-types "^2.0.0" - -micromark-util-sanitize-uri@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz" - integrity sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== - dependencies: - micromark-util-character "^2.0.0" - micromark-util-encode "^2.0.0" - micromark-util-symbol "^2.0.0" - -micromark-util-subtokenize@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.4.tgz" - integrity sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ== - dependencies: - devlop "^1.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromark-util-symbol@^1.0.0, micromark-util-symbol@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz" - integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== - -micromark-util-symbol@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz" - integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== - -micromark-util-types@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz" - integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== - -micromark-util-types@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz" - integrity sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ== - -micromark@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz" - integrity sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw== - dependencies: - "@types/debug" "^4.0.0" - debug "^4.0.0" - decode-named-character-reference "^1.0.0" - devlop "^1.0.0" - micromark-core-commonmark "^2.0.0" - micromark-factory-space "^2.0.0" - micromark-util-character "^2.0.0" - micromark-util-chunked "^2.0.0" - micromark-util-combine-extensions "^2.0.0" - micromark-util-decode-numeric-character-reference "^2.0.0" - micromark-util-encode "^2.0.0" - micromark-util-normalize-identifier "^2.0.0" - micromark-util-resolve-all "^2.0.0" - micromark-util-sanitize-uri "^2.0.0" - micromark-util-subtokenize "^2.0.0" - micromark-util-symbol "^2.0.0" - micromark-util-types "^2.0.0" - -micromatch@^4.0.2, micromatch@^4.0.5, micromatch@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -"mime-db@>= 1.43.0 < 2": - version "1.53.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz" - integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@2.1.18, mime-types@~2.1.17: - version "2.1.18" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - -mimic-response@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz" - integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== - -mini-css-extract-plugin@^2.9.1: - version "2.9.2" - resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz" - integrity sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w== - dependencies: - schema-utils "^4.0.0" - tapable "^2.2.1" - -minimalistic-assert@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0: - version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -motion-dom@^11.18.1: - version "11.18.1" - resolved "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz" - integrity sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw== - dependencies: - motion-utils "^11.18.1" - -motion-utils@^11.18.1: - version "11.18.1" - resolved "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz" - integrity sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA== - -mrmime@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz" - integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.3, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multicast-dns@^7.2.5: - version "7.2.5" - resolved "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz" - integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== - dependencies: - dns-packet "^5.2.2" - thunky "^1.0.2" - -mz@^2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -nanoid@^3.3.8: - version "3.3.8" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -negotiator@~0.6.4: - version "0.6.4" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz" - integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== - -neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - -node-emoji@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz" - integrity sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw== - dependencies: - "@sindresorhus/is" "^4.6.0" - char-regex "^1.0.2" - emojilib "^2.4.0" - skin-tone "^2.0.0" - -node-forge@^1: - version "1.3.1" - resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - -node-releases@^2.0.19: - version "2.0.19" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" - integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" - integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== - -normalize-url@^8.0.0: - version "8.0.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz" - integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -nprogress@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz" - integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA== - -nth-check@^2.0.1: - version "2.1.1" - resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz" - integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== - dependencies: - boolbase "^1.0.0" - -null-loader@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz" - integrity sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg== - dependencies: - loader-utils "^2.0.0" - schema-utils "^3.0.0" - -object-assign@^4.0.1, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-hash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" - integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== - -object-inspect@^1.13.3: - version "1.13.3" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz" - integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.0: - version "4.1.7" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz" - integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== - dependencies: - call-bind "^1.0.8" - call-bound "^1.0.3" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - has-symbols "^1.1.0" - object-keys "^1.1.1" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-headers@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz" - integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^8.0.9, open@^8.4.0: - version "8.4.2" - resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - -opener@^1.5.2: - version "1.5.2" - resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - -p-cancelable@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz" - integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== - -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-limit@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz" - integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== - dependencies: - yocto-queue "^1.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-locate@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz" - integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== - dependencies: - p-limit "^4.0.0" - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-retry@^4.5.0: - version "4.6.2" - resolved "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz" - integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== - dependencies: - "@types/retry" "0.12.0" - retry "^0.13.1" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - -package-json@^8.1.0: - version "8.1.1" - resolved "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz" - integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== - dependencies: - got "^12.1.0" - registry-auth-token "^5.0.1" - registry-url "^6.0.0" - semver "^7.3.7" - -param-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz" - integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-entities@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz" - integrity sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw== - dependencies: - "@types/unist" "^2.0.0" - character-entities-legacy "^3.0.0" - character-reference-invalid "^2.0.0" - decode-named-character-reference "^1.0.0" - is-alphanumerical "^2.0.0" - is-decimal "^2.0.0" - is-hexadecimal "^2.0.0" - -parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse-numeric-range@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz" - integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== - -parse5-htmlparser2-tree-adapter@^7.0.0: - version "7.1.0" - resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz" - integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g== - dependencies: - domhandler "^5.0.3" - parse5 "^7.0.0" - -parse5@^7.0.0: - version "7.2.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz" - integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== - dependencies: - entities "^4.5.0" - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-exists@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz" - integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-is-inside@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -path-to-regexp@0.1.12: - version "0.1.12" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz" - integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== - -path-to-regexp@3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz" - integrity sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw== - -path-to-regexp@^1.7.0: - version "1.9.0" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz" - integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== - dependencies: - isarray "0.0.1" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== - -pirates@^4.0.1: - version "4.0.6" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== - -pkg-dir@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz" - integrity sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA== - dependencies: - find-up "^6.3.0" - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -postcss-attribute-case-insensitive@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz" - integrity sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-calc@^9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz" - integrity sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ== - dependencies: - postcss-selector-parser "^6.0.11" - postcss-value-parser "^4.2.0" - -postcss-clamp@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz" - integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-color-functional-notation@^7.0.7: - version "7.0.7" - resolved "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.7.tgz" - integrity sha512-EZvAHsvyASX63vXnyXOIynkxhaHRSsdb7z6yiXKIovGXAolW4cMZ3qoh7k3VdTsLBS6VGdksGfIo3r6+waLoOw== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -postcss-color-hex-alpha@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz" - integrity sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w== - dependencies: - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -postcss-color-rebeccapurple@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz" - integrity sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ== - dependencies: - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -postcss-colormin@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz" - integrity sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw== - dependencies: - browserslist "^4.23.0" - caniuse-api "^3.0.0" - colord "^2.9.3" - postcss-value-parser "^4.2.0" - -postcss-convert-values@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz" - integrity sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w== - dependencies: - browserslist "^4.23.0" - postcss-value-parser "^4.2.0" - -postcss-custom-media@^11.0.5: - version "11.0.5" - resolved "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz" - integrity sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ== - dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.4" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/media-query-list-parser" "^4.0.2" - -postcss-custom-properties@^14.0.4: - version "14.0.4" - resolved "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz" - integrity sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A== - dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.4" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -postcss-custom-selectors@^8.0.4: - version "8.0.4" - resolved "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz" - integrity sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg== - dependencies: - "@csstools/cascade-layer-name-parser" "^2.0.4" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - postcss-selector-parser "^7.0.0" - -postcss-dir-pseudo-class@^9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz" - integrity sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-discard-comments@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz" - integrity sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw== - -postcss-discard-duplicates@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz" - integrity sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw== - -postcss-discard-empty@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz" - integrity sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ== - -postcss-discard-overridden@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz" - integrity sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ== - -postcss-discard-unused@^6.0.5: - version "6.0.5" - resolved "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz" - integrity sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA== - dependencies: - postcss-selector-parser "^6.0.16" - -postcss-double-position-gradients@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz" - integrity sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg== - dependencies: - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -postcss-focus-visible@^10.0.1: - version "10.0.1" - resolved "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz" - integrity sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-focus-within@^9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz" - integrity sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-font-variant@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz" - integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== - -postcss-gap-properties@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz" - integrity sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw== - -postcss-image-set-function@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz" - integrity sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA== - dependencies: - "@csstools/utilities" "^2.0.0" - postcss-value-parser "^4.2.0" - -postcss-import@^15.1.0: - version "15.1.0" - resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz" - integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - -postcss-import@^16.1.0: - version "16.1.0" - resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz" - integrity sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg== - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - -postcss-js@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz" - integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== - dependencies: - camelcase-css "^2.0.1" - -postcss-lab-function@^7.0.7: - version "7.0.7" - resolved "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.7.tgz" - integrity sha512-+ONj2bpOQfsCKZE2T9VGMyVVdGcGUpr7u3SVfvkJlvhTRmDCfY25k4Jc8fubB9DclAPR4+w8uVtDZmdRgdAHig== - dependencies: - "@csstools/css-color-parser" "^3.0.7" - "@csstools/css-parser-algorithms" "^3.0.4" - "@csstools/css-tokenizer" "^3.0.3" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/utilities" "^2.0.0" - -postcss-load-config@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz" - integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== - dependencies: - lilconfig "^3.0.0" - yaml "^2.3.4" - -postcss-loader@^7.3.3: - version "7.3.4" - resolved "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz" - integrity sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A== - dependencies: - cosmiconfig "^8.3.5" - jiti "^1.20.0" - semver "^7.5.4" - -postcss-logical@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz" - integrity sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-merge-idents@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz" - integrity sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g== - dependencies: - cssnano-utils "^4.0.2" - postcss-value-parser "^4.2.0" - -postcss-merge-longhand@^6.0.5: - version "6.0.5" - resolved "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz" - integrity sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w== - dependencies: - postcss-value-parser "^4.2.0" - stylehacks "^6.1.1" - -postcss-merge-rules@^6.1.1: - version "6.1.1" - resolved "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz" - integrity sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ== - dependencies: - browserslist "^4.23.0" - caniuse-api "^3.0.0" - cssnano-utils "^4.0.2" - postcss-selector-parser "^6.0.16" - -postcss-minify-font-values@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz" - integrity sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-minify-gradients@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz" - integrity sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q== - dependencies: - colord "^2.9.3" - cssnano-utils "^4.0.2" - postcss-value-parser "^4.2.0" - -postcss-minify-params@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz" - integrity sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA== - dependencies: - browserslist "^4.23.0" - cssnano-utils "^4.0.2" - postcss-value-parser "^4.2.0" - -postcss-minify-selectors@^6.0.4: - version "6.0.4" - resolved "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz" - integrity sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ== - dependencies: - postcss-selector-parser "^6.0.16" - -postcss-modules-extract-imports@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz" - integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q== - -postcss-modules-local-by-default@^4.0.5: - version "4.2.0" - resolved "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz" - integrity sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^7.0.0" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^3.2.0: - version "3.2.1" - resolved "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz" - integrity sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-nested@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz" - integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== - dependencies: - postcss-selector-parser "^6.1.1" - -postcss-nesting@^13.0.1: - version "13.0.1" - resolved "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz" - integrity sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ== - dependencies: - "@csstools/selector-resolve-nested" "^3.0.0" - "@csstools/selector-specificity" "^5.0.0" - postcss-selector-parser "^7.0.0" - -postcss-normalize-charset@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz" - integrity sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ== - -postcss-normalize-display-values@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz" - integrity sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-positions@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz" - integrity sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-repeat-style@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz" - integrity sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-string@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz" - integrity sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-timing-functions@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz" - integrity sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-unicode@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz" - integrity sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg== - dependencies: - browserslist "^4.23.0" - postcss-value-parser "^4.2.0" - -postcss-normalize-url@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz" - integrity sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-normalize-whitespace@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz" - integrity sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-opacity-percentage@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz" - integrity sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ== - -postcss-ordered-values@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz" - integrity sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q== - dependencies: - cssnano-utils "^4.0.2" - postcss-value-parser "^4.2.0" - -postcss-overflow-shorthand@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz" - integrity sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-page-break@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz" - integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== - -postcss-place@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz" - integrity sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-preset-env@^10.1.0: - version "10.1.3" - resolved "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.3.tgz" - integrity sha512-9qzVhcMFU/MnwYHyYpJz4JhGku/4+xEiPTmhn0hj3IxnUYlEF9vbh7OC1KoLAnenS6Fgg43TKNp9xcuMeAi4Zw== - dependencies: - "@csstools/postcss-cascade-layers" "^5.0.1" - "@csstools/postcss-color-function" "^4.0.7" - "@csstools/postcss-color-mix-function" "^3.0.7" - "@csstools/postcss-content-alt-text" "^2.0.4" - "@csstools/postcss-exponential-functions" "^2.0.6" - "@csstools/postcss-font-format-keywords" "^4.0.0" - "@csstools/postcss-gamut-mapping" "^2.0.7" - "@csstools/postcss-gradients-interpolation-method" "^5.0.7" - "@csstools/postcss-hwb-function" "^4.0.7" - "@csstools/postcss-ic-unit" "^4.0.0" - "@csstools/postcss-initial" "^2.0.0" - "@csstools/postcss-is-pseudo-class" "^5.0.1" - "@csstools/postcss-light-dark-function" "^2.0.7" - "@csstools/postcss-logical-float-and-clear" "^3.0.0" - "@csstools/postcss-logical-overflow" "^2.0.0" - "@csstools/postcss-logical-overscroll-behavior" "^2.0.0" - "@csstools/postcss-logical-resize" "^3.0.0" - "@csstools/postcss-logical-viewport-units" "^3.0.3" - "@csstools/postcss-media-minmax" "^2.0.6" - "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.4" - "@csstools/postcss-nested-calc" "^4.0.0" - "@csstools/postcss-normalize-display-values" "^4.0.0" - "@csstools/postcss-oklab-function" "^4.0.7" - "@csstools/postcss-progressive-custom-properties" "^4.0.0" - "@csstools/postcss-random-function" "^1.0.2" - "@csstools/postcss-relative-color-syntax" "^3.0.7" - "@csstools/postcss-scope-pseudo-class" "^4.0.1" - "@csstools/postcss-sign-functions" "^1.1.1" - "@csstools/postcss-stepped-value-functions" "^4.0.6" - "@csstools/postcss-text-decoration-shorthand" "^4.0.1" - "@csstools/postcss-trigonometric-functions" "^4.0.6" - "@csstools/postcss-unset-value" "^4.0.0" - autoprefixer "^10.4.19" - browserslist "^4.23.1" - css-blank-pseudo "^7.0.1" - css-has-pseudo "^7.0.2" - css-prefers-color-scheme "^10.0.0" - cssdb "^8.2.3" - postcss-attribute-case-insensitive "^7.0.1" - postcss-clamp "^4.1.0" - postcss-color-functional-notation "^7.0.7" - postcss-color-hex-alpha "^10.0.0" - postcss-color-rebeccapurple "^10.0.0" - postcss-custom-media "^11.0.5" - postcss-custom-properties "^14.0.4" - postcss-custom-selectors "^8.0.4" - postcss-dir-pseudo-class "^9.0.1" - postcss-double-position-gradients "^6.0.0" - postcss-focus-visible "^10.0.1" - postcss-focus-within "^9.0.1" - postcss-font-variant "^5.0.0" - postcss-gap-properties "^6.0.0" - postcss-image-set-function "^7.0.0" - postcss-lab-function "^7.0.7" - postcss-logical "^8.0.0" - postcss-nesting "^13.0.1" - postcss-opacity-percentage "^3.0.0" - postcss-overflow-shorthand "^6.0.0" - postcss-page-break "^3.0.4" - postcss-place "^10.0.0" - postcss-pseudo-class-any-link "^10.0.1" - postcss-replace-overflow-wrap "^4.0.0" - postcss-selector-not "^8.0.1" - -postcss-pseudo-class-any-link@^10.0.1: - version "10.0.1" - resolved "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz" - integrity sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-reduce-idents@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz" - integrity sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-reduce-initial@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz" - integrity sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw== - dependencies: - browserslist "^4.23.0" - caniuse-api "^3.0.0" - -postcss-reduce-transforms@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz" - integrity sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA== - dependencies: - postcss-value-parser "^4.2.0" - -postcss-replace-overflow-wrap@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz" - integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== - -postcss-selector-not@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz" - integrity sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA== - dependencies: - postcss-selector-parser "^7.0.0" - -postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.16, postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: - version "6.1.2" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz" - integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-selector-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz" - integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-sort-media-queries@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz" - integrity sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA== - dependencies: - sort-css-media-queries "2.2.0" - -postcss-svgo@^6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz" - integrity sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g== - dependencies: - postcss-value-parser "^4.2.0" - svgo "^3.2.0" - -postcss-unique-selectors@^6.0.4: - version "6.0.4" - resolved "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz" - integrity sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg== - dependencies: - postcss-selector-parser "^6.0.16" - -postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss-zindex@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz" - integrity sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg== - -postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.33, postcss@^8.4.35, postcss@^8.4.38, postcss@^8.4.47: - version "8.5.2" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz" - integrity sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA== - dependencies: - nanoid "^3.3.8" - picocolors "^1.1.1" - source-map-js "^1.2.1" - -pretty-error@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz" - integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== - dependencies: - lodash "^4.17.20" - renderkid "^3.0.0" - -pretty-time@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz" - integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== - -prism-react-renderer@^2.3.0: - version "2.4.1" - resolved "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz" - integrity sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig== - dependencies: - "@types/prismjs" "^1.26.0" - clsx "^2.0.0" - -prismjs@^1.29.0: - version "1.30.0" - resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz" - integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -prompts@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -prop-types@^15.6.2, prop-types@^15.7.2: - version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -property-information@^6.0.0: - version "6.5.0" - resolved "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz" - integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" - integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== - -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -pupa@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz" - integrity sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug== - dependencies: - escape-goat "^4.0.0" - -qs@6.13.0: - version "6.13.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -queue@6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz" - integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA== - dependencies: - inherits "~2.0.3" - -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -range-parser@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz" - integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - -rc@1.2.8: - version "1.2.8" - resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -react-dev-utils@^12.0.1: - version "12.0.1" - resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz" - integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== - dependencies: - "@babel/code-frame" "^7.16.0" - address "^1.1.2" - browserslist "^4.18.1" - chalk "^4.1.2" - cross-spawn "^7.0.3" - detect-port-alt "^1.1.6" - escape-string-regexp "^4.0.0" - filesize "^8.0.6" - find-up "^5.0.0" - fork-ts-checker-webpack-plugin "^6.5.0" - global-modules "^2.0.0" - globby "^11.0.4" - gzip-size "^6.0.0" - immer "^9.0.7" - is-root "^2.1.0" - loader-utils "^3.2.0" - open "^8.4.0" - pkg-up "^3.1.0" - prompts "^2.4.2" - react-error-overlay "^6.0.11" - recursive-readdir "^2.2.2" - shell-quote "^1.7.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -react-dom@^19.0.0: - version "19.0.0" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz" - integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ== - dependencies: - scheduler "^0.25.0" - -react-error-overlay@^6.0.11: - version "6.0.11" - resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz" - integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== - -react-fast-compare@^3.2.0: - version "3.2.2" - resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz" - integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== - -"react-helmet-async@npm:@slorber/react-helmet-async@*", "react-helmet-async@npm:@slorber/react-helmet-async@1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz" - integrity sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A== - dependencies: - "@babel/runtime" "^7.12.5" - invariant "^2.2.4" - prop-types "^15.7.2" - react-fast-compare "^3.2.0" - shallowequal "^1.1.0" - -react-hot-toast@^2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz" - integrity sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw== - dependencies: - csstype "^3.1.3" - goober "^2.1.16" - -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-json-view-lite@^1.2.0: - version "1.5.0" - resolved "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz" - integrity sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw== - -react-loadable-ssr-addon-v5-slorber@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz" - integrity sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A== - dependencies: - "@babel/runtime" "^7.10.3" - -"react-loadable@npm:@docusaurus/react-loadable@6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz" - integrity sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ== - dependencies: - "@types/react" "*" - -react-markdown@^10.1.0: - version "10.1.0" - resolved "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz" - integrity sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - devlop "^1.0.0" - hast-util-to-jsx-runtime "^2.0.0" - html-url-attributes "^3.0.0" - mdast-util-to-hast "^13.0.0" - remark-parse "^11.0.0" - remark-rehype "^11.0.0" - unified "^11.0.0" - unist-util-visit "^5.0.0" - vfile "^6.0.0" - -react-router-config@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz" - integrity sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg== - dependencies: - "@babel/runtime" "^7.1.2" - -react-router-dom@^5.3.4: - version "5.3.4" - resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz" - integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.3.4" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@5.3.4, react-router@^5.3.4: - version "5.3.4" - resolved "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz" - integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react@^19.0.0: - version "19.0.0" - resolved "https://registry.npmjs.org/react/-/react-19.0.0.tgz" - integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ== - -read-cache@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" - integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== - dependencies: - pify "^2.3.0" - -readable-stream@^2.0.1: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -reading-time@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz" - integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg== - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" - integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== - dependencies: - resolve "^1.1.6" - -recma-build-jsx@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz" - integrity sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew== - dependencies: - "@types/estree" "^1.0.0" - estree-util-build-jsx "^3.0.0" - vfile "^6.0.0" - -recma-jsx@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz" - integrity sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q== - dependencies: - acorn-jsx "^5.0.0" - estree-util-to-js "^2.0.0" - recma-parse "^1.0.0" - recma-stringify "^1.0.0" - unified "^11.0.0" - -recma-parse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz" - integrity sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ== - dependencies: - "@types/estree" "^1.0.0" - esast-util-from-js "^2.0.0" - unified "^11.0.0" - vfile "^6.0.0" - -recma-stringify@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz" - integrity sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g== - dependencies: - "@types/estree" "^1.0.0" - estree-util-to-js "^2.0.0" - unified "^11.0.0" - vfile "^6.0.0" - -recursive-readdir@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz" - integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== - dependencies: - minimatch "^3.0.5" - -regenerate-unicode-properties@^10.2.0: - version "10.2.0" - resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz" - integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regenerator-transform@^0.15.2: - version "0.15.2" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz" - integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== - dependencies: - "@babel/runtime" "^7.8.4" - -regexpu-core@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz" - integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.2.0" - regjsgen "^0.8.0" - regjsparser "^0.12.0" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.1.0" - -registry-auth-token@^5.0.1: - version "5.0.3" - resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz" - integrity sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA== - dependencies: - "@pnpm/npm-conf" "^2.1.0" - -registry-url@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz" - integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== - dependencies: - rc "1.2.8" - -regjsgen@^0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz" - integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== - -regjsparser@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz" - integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== - dependencies: - jsesc "~3.0.2" - -rehype-raw@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz" - integrity sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww== - dependencies: - "@types/hast" "^3.0.0" - hast-util-raw "^9.0.0" - vfile "^6.0.0" - -rehype-recma@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz" - integrity sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw== - dependencies: - "@types/estree" "^1.0.0" - "@types/hast" "^3.0.0" - hast-util-to-estree "^3.0.0" - -relateurl@^0.2.7: - version "0.2.7" - resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz" - integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== - -remark-directive@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz" - integrity sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-directive "^3.0.0" - micromark-extension-directive "^3.0.0" - unified "^11.0.0" - -remark-emoji@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz" - integrity sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg== - dependencies: - "@types/mdast" "^4.0.2" - emoticon "^4.0.1" - mdast-util-find-and-replace "^3.0.1" - node-emoji "^2.1.0" - unified "^11.0.4" - -remark-frontmatter@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz" - integrity sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-frontmatter "^2.0.0" - micromark-extension-frontmatter "^2.0.0" - unified "^11.0.0" - -remark-gfm@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz" - integrity sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-gfm "^3.0.0" - micromark-extension-gfm "^3.0.0" - remark-parse "^11.0.0" - remark-stringify "^11.0.0" - unified "^11.0.0" - -remark-mdx@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz" - integrity sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA== - dependencies: - mdast-util-mdx "^3.0.0" - micromark-extension-mdxjs "^3.0.0" - -remark-parse@^11.0.0: - version "11.0.0" - resolved "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz" - integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-from-markdown "^2.0.0" - micromark-util-types "^2.0.0" - unified "^11.0.0" - -remark-rehype@^11.0.0: - version "11.1.1" - resolved "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz" - integrity sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ== - dependencies: - "@types/hast" "^3.0.0" - "@types/mdast" "^4.0.0" - mdast-util-to-hast "^13.0.0" - unified "^11.0.0" - vfile "^6.0.0" - -remark-stringify@^11.0.0: - version "11.0.0" - resolved "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz" - integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== - dependencies: - "@types/mdast" "^4.0.0" - mdast-util-to-markdown "^2.0.0" - unified "^11.0.0" - -renderkid@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz" - integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^6.0.1" - -repeat-string@^1.0.0: - version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -"require-like@>= 0.1.1": - version "0.1.2" - resolved "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz" - integrity sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -resolve-alpn@^1.2.0: - version "1.2.1" - resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" - integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.8: - version "1.22.10" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz" - integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== - dependencies: - is-core-module "^2.16.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -responselike@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz" - integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== - dependencies: - lowercase-keys "^3.0.0" - -retry@^0.13.1: - version "0.13.1" - resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rtlcss@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz" - integrity sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - postcss "^8.4.21" - strip-json-comments "^3.1.1" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@^1.2.4: - version "1.4.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz" - integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== - -scheduler@^0.25.0: - version "0.25.0" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz" - integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA== - -schema-utils@2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== - dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" - -schema-utils@^3.0.0, schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^4.0.0, schema-utils@^4.0.1, schema-utils@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz" - integrity sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.9.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.1.0" - -section-matter@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz" - integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== - dependencies: - extend-shallow "^2.0.1" - kind-of "^6.0.0" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz" - integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== - -selfsigned@^2.1.1: - version "2.4.1" - resolved "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz" - integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== - dependencies: - "@types/node-forge" "^1.3.0" - node-forge "^1" - -semver-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz" - integrity sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA== - dependencies: - semver "^7.3.5" - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.4: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -send@0.19.0: - version "0.19.0" - resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - -serve-handler@^6.1.6: - version "6.1.6" - resolved "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz" - integrity sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ== - dependencies: - bytes "3.0.0" - content-disposition "0.5.2" - mime-types "2.1.18" - minimatch "3.1.2" - path-is-inside "1.0.2" - path-to-regexp "3.3.0" - range-parser "1.2.0" - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz" - integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== - dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" - -set-function-length@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shallow-clone@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - -shallowequal@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.7.3, shell-quote@^1.8.1: - version "1.8.2" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz" - integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== - -shelljs@^0.8.5: - version "0.8.5" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - -side-channel-map@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz" - integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - -side-channel-weakmap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" - integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== - dependencies: - call-bound "^1.0.2" - es-errors "^1.3.0" - get-intrinsic "^1.2.5" - object-inspect "^1.13.3" - side-channel-map "^1.0.1" - -side-channel@^1.0.6: - version "1.1.0" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== - dependencies: - es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" - side-channel-map "^1.0.1" - side-channel-weakmap "^1.0.2" - -signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -sirv@^2.0.3: - version "2.0.4" - resolved "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz" - integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== - dependencies: - "@polka/url" "^1.0.0-next.24" - mrmime "^2.0.0" - totalist "^3.0.0" - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -sitemap@^7.1.1: - version "7.1.2" - resolved "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz" - integrity sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw== - dependencies: - "@types/node" "^17.0.5" - "@types/sax" "^1.2.1" - arg "^5.0.0" - sax "^1.2.4" - -skin-tone@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz" - integrity sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA== - dependencies: - unicode-emoji-modifier-base "^1.0.0" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - -snake-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz" - integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -sockjs@^0.3.24: - version "0.3.24" - resolved "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz" - integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== - dependencies: - faye-websocket "^0.11.3" - uuid "^8.3.2" - websocket-driver "^0.7.4" - -sort-css-media-queries@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz" - integrity sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA== - -source-map-js@^1.0.1, source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@~0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.0: - version "0.7.4" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - -space-separated-tokens@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz" - integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz" - integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -srcset@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz" - integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== - -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -std-env@^3.7.0: - version "3.8.0" - resolved "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz" - integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== - -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -stringify-entities@^4.0.0: - version "4.0.4" - resolved "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz" - integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== - dependencies: - character-entities-html4 "^2.0.0" - character-entities-legacy "^3.0.0" - -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz" - integrity sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== - -style-to-object@^1.0.0: - version "1.0.8" - resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz" - integrity sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g== - dependencies: - inline-style-parser "0.2.4" - -stylehacks@^6.1.1: - version "6.1.1" - resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz" - integrity sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg== - dependencies: - browserslist "^4.23.0" - postcss-selector-parser "^6.0.16" - -sucrase@^3.35.0: - version "3.35.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz" - integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== - dependencies: - "@jridgewell/gen-mapping" "^0.3.2" - commander "^4.0.0" - glob "^10.3.10" - lines-and-columns "^1.1.6" - mz "^2.7.0" - pirates "^4.0.1" - ts-interface-checker "^0.1.9" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -svg-parser@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz" - integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== - -svgo@^3.0.2, svgo@^3.2.0: - version "3.3.2" - resolved "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz" - integrity sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^5.1.0" - css-tree "^2.3.1" - css-what "^6.1.0" - csso "^5.0.5" - picocolors "^1.0.0" - -swiper@^11.2.6: - version "11.2.6" - resolved "https://registry.npmjs.org/swiper/-/swiper-11.2.6.tgz" - integrity sha512-8aXpYKtjy3DjcbzZfz+/OX/GhcU5h+looA6PbAzHMZT6ESSycSp9nAjPCenczgJyslV+rUGse64LMGpWE3PX9Q== - -tailwind-merge@^3.0.2: - version "3.2.0" - resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.2.0.tgz" - integrity sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA== - -tailwindcss@^3.4.1: - version "3.4.17" - resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz" - integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og== - dependencies: - "@alloc/quick-lru" "^5.2.0" - arg "^5.0.2" - chokidar "^3.6.0" - didyoumean "^1.2.2" - dlv "^1.1.3" - fast-glob "^3.3.2" - glob-parent "^6.0.2" - is-glob "^4.0.3" - jiti "^1.21.6" - lilconfig "^3.1.3" - micromatch "^4.0.8" - normalize-path "^3.0.0" - object-hash "^3.0.0" - picocolors "^1.1.1" - postcss "^8.4.47" - postcss-import "^15.1.0" - postcss-js "^4.0.1" - postcss-load-config "^4.0.2" - postcss-nested "^6.2.0" - postcss-selector-parser "^6.1.2" - resolve "^1.22.8" - sucrase "^3.35.0" - -tapable@^1.0.0: - version "1.1.3" - resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - -terser-webpack-plugin@^5.3.10, terser-webpack-plugin@^5.3.9: - version "5.3.11" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz" - integrity sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - jest-worker "^27.4.5" - schema-utils "^4.3.0" - serialize-javascript "^6.0.2" - terser "^5.31.1" - -terser@^5.10.0, terser@^5.15.1, terser@^5.31.1: - version "5.37.0" - resolved "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz" - integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -thunky@^1.0.2: - version "1.1.0" - resolved "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz" - integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - -tiny-invariant@^1.0.2: - version "1.3.3" - resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz" - integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== - -tiny-warning@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -totalist@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz" - integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== - -trim-lines@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz" - integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== - -trough@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz" - integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== - -ts-interface-checker@^0.1.9: - version "0.1.13" - resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== - -tslib@^2.0.3, tslib@^2.4.0, tslib@^2.6.0: - version "2.8.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - -turndown@^7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.2.1.tgz#633ff4ff88951fe1db58f7dd32a25ba3f6ff2c48" - integrity sha512-7YiPJw6rLClQL3oUKN3KgMaXeJJ2lAyZItclgKDurqnH61so4k4IH/qwmMva0zpuJc/FhRExBBnk7EbeFANlgQ== - dependencies: - "@mixmark-io/domino" "^2.2.0" - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^1.0.1: - version "1.4.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - -type-fest@^2.13.0, type-fest@^2.5.0: - version "2.19.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" - integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== - -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript@~5.6.2: - version "5.6.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== - -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz" - integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== - -unicode-emoji-modifier-base@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz" - integrity sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz" - integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== - -unified@^11.0.0, unified@^11.0.3, unified@^11.0.4: - version "11.0.5" - resolved "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz" - integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== - dependencies: - "@types/unist" "^3.0.0" - bail "^2.0.0" - devlop "^1.0.0" - extend "^3.0.0" - is-plain-obj "^4.0.0" - trough "^2.0.0" - vfile "^6.0.0" - -unique-string@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz" - integrity sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ== - dependencies: - crypto-random-string "^4.0.0" - -unist-util-is@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz" - integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-position-from-estree@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz" - integrity sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-position@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz" - integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-stringify-position@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz" - integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== - dependencies: - "@types/unist" "^3.0.0" - -unist-util-visit-parents@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz" - integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - -unist-util-visit@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz" - integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== - dependencies: - "@types/unist" "^3.0.0" - unist-util-is "^6.0.0" - unist-util-visit-parents "^6.0.0" - -universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - -update-browserslist-db@^1.1.1: - version "1.1.2" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz" - integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.1" - -update-notifier@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz" - integrity sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og== - dependencies: - boxen "^7.0.0" - chalk "^5.0.1" - configstore "^6.0.0" - has-yarn "^3.0.0" - import-lazy "^4.0.0" - is-ci "^3.0.1" - is-installed-globally "^0.4.0" - is-npm "^6.0.0" - is-yarn-global "^0.4.0" - latest-version "^7.0.0" - pupa "^3.1.0" - semver "^7.3.7" - semver-diff "^4.0.0" - xdg-basedir "^5.1.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-loader@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utila@~0.4: - version "0.4.0" - resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz" - integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== - -utility-types@^3.10.0: - version "3.11.0" - resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz" - integrity sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw== - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -vfile-location@^5.0.0: - version "5.0.3" - resolved "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz" - integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== - dependencies: - "@types/unist" "^3.0.0" - vfile "^6.0.0" - -vfile-message@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz" - integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== - dependencies: - "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" - -vfile@^6.0.0, vfile@^6.0.1: - version "6.0.3" - resolved "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz" - integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== - dependencies: - "@types/unist" "^3.0.0" - vfile-message "^4.0.0" - -watchpack@^2.4.1: - version "2.4.2" - resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz" - integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - -web-namespaces@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz" - integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== - -webpack-bundle-analyzer@^4.10.2: - version "4.10.2" - resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz" - integrity sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw== - dependencies: - "@discoveryjs/json-ext" "0.5.7" - acorn "^8.0.4" - acorn-walk "^8.0.0" - commander "^7.2.0" - debounce "^1.2.1" - escape-string-regexp "^4.0.0" - gzip-size "^6.0.0" - html-escaper "^2.0.2" - opener "^1.5.2" - picocolors "^1.0.0" - sirv "^2.0.3" - ws "^7.3.1" - -webpack-dev-middleware@^5.3.4: - version "5.3.4" - resolved "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz" - integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== - dependencies: - colorette "^2.0.10" - memfs "^3.4.3" - mime-types "^2.1.31" - range-parser "^1.2.1" - schema-utils "^4.0.0" - -webpack-dev-server@^4.15.2: - version "4.15.2" - resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz" - integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/serve-static" "^1.13.10" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.5" - ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" - colorette "^2.0.10" - compression "^1.7.4" - connect-history-api-fallback "^2.0.0" - default-gateway "^6.0.3" - express "^4.17.3" - graceful-fs "^4.2.6" - html-entities "^2.3.2" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - launch-editor "^2.6.0" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.1.1" - serve-index "^1.9.1" - sockjs "^0.3.24" - spdy "^4.0.2" - webpack-dev-middleware "^5.3.4" - ws "^8.13.0" - -webpack-merge@^5.9.0: - version "5.10.0" - resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz" - integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== - dependencies: - clone-deep "^4.0.1" - flat "^5.0.2" - wildcard "^2.0.0" - -webpack-merge@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz" - integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== - dependencies: - clone-deep "^4.0.1" - flat "^5.0.2" - wildcard "^2.0.1" - -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@^5.88.1, webpack@^5.95.0: - version "5.97.1" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz" - integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg== - dependencies: - "@types/eslint-scope" "^3.7.7" - "@types/estree" "^1.0.6" - "@webassemblyjs/ast" "^1.14.1" - "@webassemblyjs/wasm-edit" "^1.14.1" - "@webassemblyjs/wasm-parser" "^1.14.1" - acorn "^8.14.0" - browserslist "^4.24.0" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.1" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.11" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.10" - watchpack "^2.4.1" - webpack-sources "^3.2.3" - -webpackbar@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz" - integrity sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q== - dependencies: - ansi-escapes "^4.3.2" - chalk "^4.1.2" - consola "^3.2.3" - figures "^3.2.0" - markdown-table "^2.0.0" - pretty-time "^1.1.0" - std-env "^3.7.0" - wrap-ansi "^7.0.0" - -websocket-driver@>=0.5.1, websocket-driver@^0.7.4: - version "0.7.4" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - -which@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -widest-line@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz" - integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== - dependencies: - string-width "^5.0.1" - -wildcard@^2.0.0, wildcard@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz" - integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@^7.3.1: - version "7.5.10" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - -ws@^8.13.0: - version "8.18.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== - -xdg-basedir@^5.0.1, xdg-basedir@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz" - integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== - -xml-js@^1.6.11: - version "1.6.11" - resolved "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz" - integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== - dependencies: - sax "^1.2.4" - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yaml-loader@^0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.1.tgz" - integrity sha512-BCEndnUoi3BaZmePkwGGe93txRxLgMhBa/gE725v1/GHnura8QvNs7c4+4C1yyhhKoj3Dg63M7IqhA++15j6ww== - dependencies: - javascript-stringify "^2.0.1" - loader-utils "^2.0.0" - yaml "^2.0.0" - -yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yaml@^2.0.0, yaml@^2.3.4: - version "2.7.0" - resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz" - integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yocto-queue@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz" - integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== - -zwitch@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== From b1c19fc3a65d6409a534b24d3cffe303ffcabd0a Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Mon, 3 Nov 2025 17:03:28 -0500 Subject: [PATCH 075/121] info: print location of sessions.db via goose info (#5557) Signed-off-by: fbalicchia --- crates/goose-cli/src/commands/info.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/goose-cli/src/commands/info.rs b/crates/goose-cli/src/commands/info.rs index 3bedde5e439a..de3b83831464 100644 --- a/crates/goose-cli/src/commands/info.rs +++ b/crates/goose-cli/src/commands/info.rs @@ -11,6 +11,7 @@ fn print_aligned(label: &str, value: &str, width: usize) { pub fn handle_info(verbose: bool) -> Result<()> { let logs_dir = Paths::in_state_dir("logs"); let sessions_dir = Paths::in_data_dir("sessions"); + let sessions_db = sessions_dir.join("sessions.db"); // Get paths using a stored reference to the global config let config = Config::global(); @@ -19,7 +20,7 @@ pub fn handle_info(verbose: bool) -> Result<()> { // Define the labels and their corresponding path values once. let paths = [ ("Config dir:", config_dir), - ("Sessions dir:", sessions_dir.display().to_string()), + ("Sessions DB (sqlite):", sessions_db.display().to_string()), ("Logs dir:", logs_dir.display().to_string()), ]; From 7ff5b154962d5e1dadd0d6671b0371e5cc149096 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Tue, 4 Nov 2025 09:06:23 +1100 Subject: [PATCH 076/121] =?UTF-8?q?we=20should=20run=20this=20on=20main=20?= =?UTF-8?q?and=20also=20test=20open=20models=20at=20least=20via=20ope?= =?UTF-8?q?=E2=80=A6=20(#5556)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adds qwen3-code and GLM 4.6 to test_providers for open model coverage Signed-off-by: fbalicchia --- .github/workflows/pr-smoke-test.yml | 5 ++++- scripts/test_providers.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-smoke-test.yml b/.github/workflows/pr-smoke-test.yml index 07ae49654feb..e301804b0390 100644 --- a/.github/workflows/pr-smoke-test.yml +++ b/.github/workflows/pr-smoke-test.yml @@ -2,6 +2,9 @@ on: pull_request: branches: - main + push: + branches: + - main workflow_dispatch: inputs: branch: @@ -16,7 +19,7 @@ jobs: check-fork: runs-on: ubuntu-latest # Skip entire workflow for PRs from forks (they don't have access to secrets) - if: github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository + if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository steps: - run: echo "Not a fork PR - proceeding with smoke tests" diff --git a/scripts/test_providers.sh b/scripts/test_providers.sh index d710ebdc8a9d..ae31e40ebac7 100755 --- a/scripts/test_providers.sh +++ b/scripts/test_providers.sh @@ -15,7 +15,7 @@ fi SCRIPT_DIR=$(pwd) PROVIDERS=( - "openrouter:google/gemini-2.5-pro:google/gemini-2.5-flash:anthropic/claude-sonnet-4.5" + "openrouter:google/gemini-2.5-pro:google/gemini-2.5-flash:anthropic/claude-sonnet-4.5:qwen/qwen3-coder:z-ai/glm-4.6" "openai:gpt-4o:gpt-4o-mini:gpt-3.5-turbo:gpt-5" "anthropic:claude-sonnet-4-5-20250929:claude-opus-4-1-20250805" "google:gemini-2.5-pro:gemini-2.5-flash" From 73582fddb9c8d02df26ca7b16532b29e7989b2d4 Mon Sep 17 00:00:00 2001 From: jom-sq Date: Mon, 3 Nov 2025 20:43:20 -0500 Subject: [PATCH 077/121] feat: add grouped extension loading notification (#5529) Signed-off-by: jom-sq <148157197+jom-sq@users.noreply.github.com> Signed-off-by: fbalicchia --- .../GroupedExtensionLoadingToast.tsx | 163 ++++++++++++++++++ .../GroupedExtensionLoadingToast.test.tsx | 80 +++++++++ .../settings/extensions/agent-api.ts | 40 ++--- .../extensions/extension-manager.test.ts | 19 +- .../settings/extensions/extension-manager.ts | 32 ++-- ui/desktop/src/toasts.tsx | 57 ++++++ ui/desktop/src/utils/extensionErrorUtils.ts | 30 ++++ ui/desktop/src/utils/providerUtils.ts | 52 +++++- 8 files changed, 422 insertions(+), 51 deletions(-) create mode 100644 ui/desktop/src/components/GroupedExtensionLoadingToast.tsx create mode 100644 ui/desktop/src/components/__tests__/GroupedExtensionLoadingToast.test.tsx create mode 100644 ui/desktop/src/utils/extensionErrorUtils.ts diff --git a/ui/desktop/src/components/GroupedExtensionLoadingToast.tsx b/ui/desktop/src/components/GroupedExtensionLoadingToast.tsx new file mode 100644 index 000000000000..01a2887518a0 --- /dev/null +++ b/ui/desktop/src/components/GroupedExtensionLoadingToast.tsx @@ -0,0 +1,163 @@ +import { useState } from 'react'; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible'; +import { ChevronDown, ChevronUp, Loader2 } from 'lucide-react'; +import { Button } from './ui/button'; +import { startNewSession } from '../sessions'; +import { useNavigation } from '../hooks/useNavigation'; +import { formatExtensionErrorMessage } from '../utils/extensionErrorUtils'; + +export interface ExtensionLoadingStatus { + name: string; + status: 'loading' | 'success' | 'error'; + error?: string; + recoverHints?: string; +} + +interface ExtensionLoadingToastProps { + extensions: ExtensionLoadingStatus[]; + totalCount: number; + isComplete: boolean; +} + +export function GroupedExtensionLoadingToast({ + extensions, + totalCount, + isComplete, +}: ExtensionLoadingToastProps) { + const [isOpen, setIsOpen] = useState(false); + const [copiedExtension, setCopiedExtension] = useState(null); + const setView = useNavigation(); + + const successCount = extensions.filter((ext) => ext.status === 'success').length; + const errorCount = extensions.filter((ext) => ext.status === 'error').length; + + const getStatusIcon = (status: 'loading' | 'success' | 'error') => { + switch (status) { + case 'loading': + return ; + case 'success': + return
; + case 'error': + return
; + } + }; + + const getSummaryText = () => { + if (!isComplete) { + return `Loading ${totalCount} extension${totalCount !== 1 ? 's' : ''}...`; + } + + if (errorCount === 0) { + return `Successfully loaded ${successCount} extension${successCount !== 1 ? 's' : ''}`; + } + + return `Loaded ${successCount}/${totalCount} extension${totalCount !== 1 ? 's' : ''}`; + }; + + const getSummaryIcon = () => { + if (!isComplete) { + return ; + } + + if (errorCount === 0) { + return
; + } + + return
; + }; + + return ( +
+ +
+ {/* Main summary section - clickable */} + +
+
+ {getSummaryIcon()} +
+
{getSummaryText()}
+ {errorCount > 0 && ( +
+ {errorCount} extension{errorCount !== 1 ? 's' : ''} failed to load +
+ )} +
+
+
+
+ + {/* Expanded details section */} + +
+
+ {extensions.map((ext) => ( +
+
+ {getStatusIcon(ext.status)} +
{ext.name}
+
+ {ext.status === 'error' && ext.error && ( +
+
+ {formatExtensionErrorMessage(ext.error, 'Failed to add extension')} +
+ {ext.recoverHints && setView ? ( + + ) : ( + + )} +
+ )} +
+ ))} +
+
+
+ + {/* Toggle button */} + {totalCount > 0 && ( + + + + )} +
+
+
+ ); +} diff --git a/ui/desktop/src/components/__tests__/GroupedExtensionLoadingToast.test.tsx b/ui/desktop/src/components/__tests__/GroupedExtensionLoadingToast.test.tsx new file mode 100644 index 000000000000..701e9e041391 --- /dev/null +++ b/ui/desktop/src/components/__tests__/GroupedExtensionLoadingToast.test.tsx @@ -0,0 +1,80 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import { GroupedExtensionLoadingToast } from '../GroupedExtensionLoadingToast'; + +const renderWithRouter = (component: React.ReactElement) => { + return render({component}); +}; + +describe('GroupedExtensionLoadingToast', () => { + it('renders loading state correctly', () => { + const extensions = [ + { name: 'developer', status: 'loading' as const }, + { name: 'memory', status: 'loading' as const }, + ]; + + renderWithRouter( + + ); + + expect(screen.getByText('Loading 2 extensions...')).toBeInTheDocument(); + expect(screen.getByText('Show details')).toBeInTheDocument(); + }); + + it('renders success state correctly', () => { + const extensions = [ + { name: 'developer', status: 'success' as const }, + { name: 'memory', status: 'success' as const }, + ]; + + renderWithRouter( + + ); + + expect(screen.getByText('Successfully loaded 2 extensions')).toBeInTheDocument(); + expect(screen.getByText('Show details')).toBeInTheDocument(); + }); + + it('renders partial failure state correctly', () => { + const extensions = [ + { name: 'developer', status: 'success' as const }, + { name: 'memory', status: 'error' as const, error: 'Failed to connect' }, + ]; + + renderWithRouter( + + ); + + expect(screen.getByText('Loaded 1/2 extensions')).toBeInTheDocument(); + expect(screen.getByText('1 extension failed to load')).toBeInTheDocument(); + expect(screen.getByText('Show details')).toBeInTheDocument(); + }); + + it('renders single extension correctly', () => { + const extensions = [{ name: 'developer', status: 'success' as const }]; + + renderWithRouter( + + ); + + expect(screen.getByText('Successfully loaded 1 extension')).toBeInTheDocument(); + }); + + it('renders mixed status states correctly', () => { + const extensions = [ + { name: 'developer', status: 'success' as const }, + { name: 'memory', status: 'loading' as const }, + { name: 'Square MCP Server', status: 'error' as const, error: 'Connection failed' }, + ]; + + renderWithRouter( + + ); + + // Summary should show loading state with error count + expect(screen.getByText('Loading 3 extensions...')).toBeInTheDocument(); + expect(screen.getByText('1 extension failed to load')).toBeInTheDocument(); + expect(screen.getByText('Show details')).toBeInTheDocument(); + }); +}); diff --git a/ui/desktop/src/components/settings/extensions/agent-api.ts b/ui/desktop/src/components/settings/extensions/agent-api.ts index d051e289dec0..bd38284873c4 100644 --- a/ui/desktop/src/components/settings/extensions/agent-api.ts +++ b/ui/desktop/src/components/settings/extensions/agent-api.ts @@ -1,6 +1,10 @@ import { toastService } from '../../../toasts'; import { agentAddExtension, ExtensionConfig, agentRemoveExtension } from '../../../api'; import { errorMessage } from '../../../utils/conversionUtils'; +import { + createExtensionRecoverHints, + formatExtensionErrorMessage, +} from '../../../utils/extensionErrorUtils'; export async function addToAgent( extensionConfig: ExtensionConfig, @@ -30,20 +34,16 @@ export async function addToAgent( } catch (error) { if (showToast) { toastService.dismiss(toastId); + const errMsg = errorMessage(error); + const recoverHints = createExtensionRecoverHints(errMsg); + const msg = formatExtensionErrorMessage(errMsg, 'Failed to add extension'); + toastService.error({ + title: extensionName, + msg: msg, + traceback: errMsg, + recoverHints, + }); } - const errMsg = errorMessage(error); - const recoverHints = - `Explain the following error: ${errMsg}. ` + - 'This happened while trying to install an extension. Look out for issues that the ' + - "extension tried to run something faulty, didn't exist or there was trouble with " + - 'the network configuration - VPNs like WARP often cause issues.'; - const msg = errMsg.length < 70 ? errMsg : `Failed to add extension`; - toastService.error({ - title: extensionName, - msg: msg, - traceback: errMsg, - recoverHints, - }); throw error; } } @@ -75,14 +75,14 @@ export async function removeFromAgent( } catch (error) { if (showToast) { toastService.dismiss(toastId); + const errMsg = errorMessage(error); + const msg = formatExtensionErrorMessage(errMsg, 'Failed to remove extension'); + toastService.error({ + title: extensionName, + msg: msg, + traceback: errMsg, + }); } - const errorMessage = error instanceof Error ? error.message : String(error); - const msg = errorMessage.length < 70 ? errorMessage : `Failed to remove extension`; - toastService.error({ - title: extensionName, - msg: msg, - traceback: errorMessage, - }); throw error; } } diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts index 785cea3ffdf9..0151ebca3658 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.test.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.test.ts @@ -70,23 +70,18 @@ describe('Extension Manager', () => { expect(mockAddToAgent).toHaveBeenCalledTimes(3); }); - it('should show error toast after max retries but keep extension enabled', async () => { + it('should throw error after max retries', async () => { const error428 = new Error('428 Precondition Required'); mockAddToAgent.mockRejectedValue(error428); - mockToastService.configure = vi.fn(); - mockToastService.error = vi.fn(); - await addToAgentOnStartup({ - sessionId: 'test-session', - extensionConfig: mockExtensionConfig, - }); + await expect( + addToAgentOnStartup({ + sessionId: 'test-session', + extensionConfig: mockExtensionConfig, + }) + ).rejects.toThrow('428 Precondition Required'); expect(mockAddToAgent).toHaveBeenCalledTimes(4); // Initial + 3 retries - expect(mockToastService.error).toHaveBeenCalledWith({ - title: 'test-extension', - msg: 'Extension failed to start and will retry on a new session.', - traceback: '428 Precondition Required', - }); }); }); diff --git a/ui/desktop/src/components/settings/extensions/extension-manager.ts b/ui/desktop/src/components/settings/extensions/extension-manager.ts index 6deb12960be0..3da183fdca58 100644 --- a/ui/desktop/src/components/settings/extensions/extension-manager.ts +++ b/ui/desktop/src/components/settings/extensions/extension-manager.ts @@ -96,25 +96,21 @@ interface AddToAgentOnStartupProps { export async function addToAgentOnStartup({ extensionConfig, sessionId, + toastOptions, }: AddToAgentOnStartupProps): Promise { - try { - await retryWithBackoff(() => addToAgent(extensionConfig, sessionId, true), { - retries: 3, - delayMs: 1000, - shouldRetry: (error: ExtensionError) => - !!error.message && - (error.message.includes('428') || - error.message.includes('Precondition Required') || - error.message.includes('Agent is not initialized')), - }); - } catch (finalError) { - toastService.configure({ silent: false }); - toastService.error({ - title: extensionConfig.name, - msg: 'Extension failed to start and will retry on a new session.', - traceback: finalError instanceof Error ? finalError.message : String(finalError), - }); - } + const showToast = !toastOptions?.silent; + + // Errors are caught by the grouped notification in providerUtils.ts + // Individual error toasts are suppressed during startup (showToast=false) + await retryWithBackoff(() => addToAgent(extensionConfig, sessionId, showToast), { + retries: 3, + delayMs: 1000, + shouldRetry: (error: ExtensionError) => + !!error.message && + (error.message.includes('428') || + error.message.includes('Precondition Required') || + error.message.includes('Agent is not initialized')), + }); } interface UpdateExtensionProps { diff --git a/ui/desktop/src/toasts.tsx b/ui/desktop/src/toasts.tsx index 2eb51dcb39c7..4f8849c828ae 100644 --- a/ui/desktop/src/toasts.tsx +++ b/ui/desktop/src/toasts.tsx @@ -2,6 +2,10 @@ import { toast, ToastOptions } from 'react-toastify'; import { Button } from './components/ui/button'; import { startNewSession } from './sessions'; import { useNavigation } from './hooks/useNavigation'; +import { + GroupedExtensionLoadingToast, + ExtensionLoadingStatus, +} from './components/GroupedExtensionLoadingToast'; export interface ToastServiceOptions { silent?: boolean; @@ -63,6 +67,56 @@ class ToastService { if (toastId) toast.dismiss(toastId); } + /** + * Create a grouped extension loading toast that can be updated as extensions load + */ + extensionLoading( + extensions: ExtensionLoadingStatus[], + totalCount: number, + isComplete: boolean = false + ): string | number { + if (this.silent) { + return 'silent'; + } + + const toastId = 'extension-loading'; + + // Check if toast already exists + if (toast.isActive(toastId)) { + // Update existing toast + toast.update(toastId, { + render: ( + + ), + autoClose: isComplete ? 5000 : false, + closeButton: true, + closeOnClick: false, + }); + } else { + // Create new toast + toast( + , + { + ...commonToastOptions, + toastId, + autoClose: false, + closeButton: true, + closeOnClick: false, // Prevent closing when clicking to expand/collapse + } + ); + } + + return toastId; + } + /** * Handle errors with consistent logging and toast notifications * Consolidates the functionality of the original handleError function @@ -80,6 +134,9 @@ class ToastService { // Export a singleton instance for use throughout the app export const toastService = ToastService.getInstance(); +// Re-export ExtensionLoadingStatus for convenience +export type { ExtensionLoadingStatus }; + const commonToastOptions: ToastOptions = { position: 'top-right', closeButton: true, diff --git a/ui/desktop/src/utils/extensionErrorUtils.ts b/ui/desktop/src/utils/extensionErrorUtils.ts new file mode 100644 index 000000000000..e707c6c0e757 --- /dev/null +++ b/ui/desktop/src/utils/extensionErrorUtils.ts @@ -0,0 +1,30 @@ +/** + * Shared constants and utilities for extension error handling + */ + +export const MAX_ERROR_MESSAGE_LENGTH = 70; + +/** + * Creates recovery hints for the "Ask goose" feature when extension loading fails + */ +export function createExtensionRecoverHints(errorMsg: string): string { + return ( + `Explain the following error: ${errorMsg}. ` + + 'This happened while trying to install an extension. Look out for issues where the ' + + "extension attempted to execute something incorrectly, didn't exist, or there was trouble with " + + 'the network configuration - VPNs like WARP often cause issues.' + ); +} + +/** + * Formats an error message for display, truncating long messages with a fallback + * @param errorMsg - The full error message + * @param fallback - The fallback message to show if the error is too long + * @returns The formatted error message + */ +export function formatExtensionErrorMessage( + errorMsg: string, + fallback: string = 'Failed to add extension' +): string { + return errorMsg.length < MAX_ERROR_MESSAGE_LENGTH ? errorMsg : fallback; +} diff --git a/ui/desktop/src/utils/providerUtils.ts b/ui/desktop/src/utils/providerUtils.ts index 9c5f5f7c2d37..8862b5c12d69 100644 --- a/ui/desktop/src/utils/providerUtils.ts +++ b/ui/desktop/src/utils/providerUtils.ts @@ -5,6 +5,9 @@ import { } from '../components/settings/extensions'; import type { ExtensionConfig, FixedExtensionEntry } from '../components/ConfigContext'; import { Recipe, updateAgentProvider, updateFromSession } from '../api'; +import { toastService, ExtensionLoadingStatus } from '../toasts'; +import { errorMessage } from './conversionUtils'; +import { createExtensionRecoverHints } from './extensionErrorUtils'; // Helper function to substitute parameters in text export const substituteParameters = (text: string, params: Record): string => { @@ -77,23 +80,70 @@ export const initializeSystem = async ( // Add enabled extensions to agent in parallel const enabledExtensions = refreshedExtensions.filter((ext) => ext.enabled); + if (enabledExtensions.length === 0) { + return; + } + options?.setIsExtensionsLoading?.(true); + // Initialize extension status tracking + const extensionStatuses: Map = new Map( + enabledExtensions.map((ext) => [ext.name, { name: ext.name, status: 'loading' as const }]) + ); + + // Show initial loading toast + const updateToast = (isComplete: boolean = false) => { + toastService.extensionLoading( + Array.from(extensionStatuses.values()), + enabledExtensions.length, + isComplete + ); + }; + + updateToast(); + + // Load extensions in parallel and update status const extensionLoadingPromises = enabledExtensions.map(async (extensionConfig) => { const extensionName = extensionConfig.name; try { await addToAgentOnStartup({ extensionConfig, - toastOptions: { silent: false }, + toastOptions: { silent: true }, // Silent since we're using grouped notification sessionId, }); + + // Update status to success + extensionStatuses.set(extensionName, { + name: extensionName, + status: 'success', + }); + updateToast(); } catch (error) { console.error(`Failed to load extension ${extensionName}:`, error); + + // Extract error message using shared utility + const errMsg = errorMessage(error); + + // Create recovery hints for "Ask goose" button + const recoverHints = createExtensionRecoverHints(errMsg); + + // Update status to error + extensionStatuses.set(extensionName, { + name: extensionName, + status: 'error', + error: errMsg, + recoverHints, + }); + updateToast(); } }); await Promise.allSettled(extensionLoadingPromises); + + // Show final completion toast + updateToast(true); + options?.setIsExtensionsLoading?.(false); } catch (error) { console.error('Failed to initialize agent:', error); From b316afa43917a8c9f652ee48039a1cdcf151eabe Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Mon, 3 Nov 2025 21:04:44 -0500 Subject: [PATCH 078/121] Sessions required (#5548) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose-cli/src/cli.rs | 31 +- crates/goose-cli/src/commands/acp.rs | 49 +- crates/goose-cli/src/commands/bench.rs | 4 +- crates/goose-cli/src/commands/schedule.rs | 1 - crates/goose-cli/src/commands/web.rs | 11 +- .../src/scenario_tests/scenario_runner.rs | 19 +- crates/goose-cli/src/session/builder.rs | 131 +- crates/goose-cli/src/session/mod.rs | 75 +- crates/goose-server/src/openapi.rs | 3 +- crates/goose-server/src/routes/agent.rs | 20 +- crates/goose-server/src/routes/reply.rs | 21 +- crates/goose-server/src/routes/schedule.rs | 1 - crates/goose/examples/agent.rs | 32 +- crates/goose/src/agents/agent.rs | 284 +-- crates/goose/src/agents/platform_tools.rs | 1 - crates/goose/src/agents/retry.rs | 7 +- crates/goose/src/agents/schedule_tool.rs | 1 - crates/goose/src/agents/subagent_handler.rs | 76 +- .../goose/src/agents/subagent_task_config.rs | 13 +- crates/goose/src/agents/tool_execution.rs | 7 +- crates/goose/src/agents/types.rs | 7 +- crates/goose/src/context_mgmt/mod.rs | 5 +- crates/goose/src/scheduler.rs | 18 +- crates/goose/src/session/mod.rs | 2 +- crates/goose/src/session/session_manager.rs | 186 +- crates/goose/tests/agent.rs | 1708 ++++------------- crates/goose/tests/private_tests.rs | 833 -------- crates/goose/tests/test_support.rs | 2 +- ui/desktop/openapi.json | 16 +- ui/desktop/package-lock.json | 40 +- ui/desktop/src/api/types.gen.ts | 4 +- 31 files changed, 943 insertions(+), 2665 deletions(-) delete mode 100644 crates/goose/tests/private_tests.rs diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index 4df791843c45..be1575cad804 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -19,6 +19,7 @@ use crate::commands::session::{handle_session_list, handle_session_remove}; use crate::recipes::extract_from_cli::extract_recipe_info_from_cli; use crate::recipes::recipe::{explain_recipe, render_recipe_as_yaml}; use crate::session::{build_session, SessionBuilderConfig, SessionSettings}; +use goose::session::session_manager::SessionType; use goose::session::SessionManager; use goose_bench::bench_config::BenchRunConfig; use goose_bench::runners::bench_runner::BenchRunner; @@ -86,9 +87,12 @@ async fn get_or_create_session_id( .ok_or_else(|| anyhow::anyhow!("No session found to resume"))?; Ok(Some(session_id)) } else { - let session = - SessionManager::create_session(std::env::current_dir()?, "CLI Session".to_string()) - .await?; + let session = SessionManager::create_session( + std::env::current_dir()?, + "CLI Session".to_string(), + SessionType::User, + ) + .await?; Ok(Some(session.id)) }; }; @@ -105,8 +109,12 @@ async fn get_or_create_session_id( .ok_or_else(|| anyhow::anyhow!("No session found with name '{}'", name))?; Ok(Some(session_id)) } else { - let session = - SessionManager::create_session(std::env::current_dir()?, name.clone()).await?; + let session = SessionManager::create_session( + std::env::current_dir()?, + name.clone(), + SessionType::User, + ) + .await?; SessionManager::update_session(&session.id) .user_provided_name(name) @@ -123,9 +131,12 @@ async fn get_or_create_session_id( .ok_or_else(|| anyhow::anyhow!("Could not extract session ID from path: {:?}", path))?; Ok(Some(session_id)) } else { - let session = - SessionManager::create_session(std::env::current_dir()?, "CLI Session".to_string()) - .await?; + let session = SessionManager::create_session( + std::env::current_dir()?, + "CLI Session".to_string(), + SessionType::User, + ) + .await?; Ok(Some(session.id)) } } @@ -977,7 +988,7 @@ pub async fn cli() -> anyhow::Result<()> { let exit_type = if result.is_ok() { "normal" } else { "error" }; let (total_tokens, message_count) = session - .get_metadata() + .get_session() .await .map(|m| (m.total_tokens.unwrap_or(0), m.message_count)) .unwrap_or((0, 0)); @@ -1198,7 +1209,7 @@ pub async fn cli() -> anyhow::Result<()> { let exit_type = if result.is_ok() { "normal" } else { "error" }; let (total_tokens, message_count) = session - .get_metadata() + .get_session() .await .map(|m| (m.total_tokens.unwrap_or(0), m.message_count)) .unwrap_or((0, 0)); diff --git a/crates/goose-cli/src/commands/acp.rs b/crates/goose-cli/src/commands/acp.rs index 95094ce7e908..dfdbe269b8da 100644 --- a/crates/goose-cli/src/commands/acp.rs +++ b/crates/goose-cli/src/commands/acp.rs @@ -3,11 +3,13 @@ use agent_client_protocol::{ ToolCallContent, }; use anyhow::Result; -use goose::agents::Agent; +use goose::agents::{Agent, SessionConfig}; use goose::config::{get_all_extensions, Config}; use goose::conversation::message::{Message, MessageContent}; use goose::conversation::Conversation; use goose::providers::create; +use goose::session::session_manager::SessionType; +use goose::session::SessionManager; use rmcp::model::{RawContent, ResourceContents}; use std::collections::{HashMap, HashSet}; use std::fs; @@ -19,17 +21,15 @@ use tokio_util::sync::CancellationToken; use tracing::{error, info, warn}; use url::Url; -/// Represents a single goose session for ACP -struct GooseSession { +struct GooseAcpSession { messages: Conversation, tool_call_ids: HashMap, // Maps internal tool IDs to ACP tool call IDs cancel_token: Option, // Active cancellation token for prompt processing } -/// goose ACP Agent implementation that connects to real goose agents struct GooseAcpAgent { - session_update_tx: mpsc::UnboundedSender<(acp::SessionNotification, oneshot::Sender<()>)>, - sessions: Arc>>, + session_update_tx: mpsc::UnboundedSender<(SessionNotification, oneshot::Sender<()>)>, + sessions: Arc>>, agent: Agent, // Shared agent instance } @@ -97,7 +97,6 @@ impl GooseAcpAgent { async fn new( session_update_tx: mpsc::UnboundedSender<(acp::SessionNotification, oneshot::Sender<()>)>, ) -> Result { - // Load config and create provider let config = Config::global(); let provider_name: String = config @@ -217,7 +216,7 @@ impl GooseAcpAgent { &self, content_item: &MessageContent, session_id: &acp::SessionId, - session: &mut GooseSession, + session: &mut GooseAcpSession, ) -> Result<(), acp::Error> { match content_item { MessageContent::Text(text) => { @@ -273,7 +272,7 @@ impl GooseAcpAgent { &self, tool_request: &goose::conversation::message::ToolRequest, session_id: &acp::SessionId, - session: &mut GooseSession, + session: &mut GooseAcpSession, ) -> Result<(), acp::Error> { // Generate ACP tool call ID and track mapping let acp_tool_id = format!("tool_{}", uuid::Uuid::new_v4()); @@ -341,7 +340,7 @@ impl GooseAcpAgent { &self, tool_response: &goose::conversation::message::ToolResponse, session_id: &acp::SessionId, - session: &mut GooseSession, + session: &mut GooseAcpSession, ) -> Result<(), acp::Error> { // Look up the ACP tool call ID if let Some(acp_tool_id) = session.tool_call_ids.get(&tool_response.id) { @@ -496,7 +495,7 @@ impl acp::Agent for GooseAcpAgent { // Generate a unique session ID let session_id = uuid::Uuid::new_v4().to_string(); - let session = GooseSession { + let session = GooseAcpSession { messages: Conversation::new_unvalidated(Vec::new()), tool_call_ids: HashMap::new(), cancel_token: None, @@ -544,30 +543,26 @@ impl acp::Agent for GooseAcpAgent { // Create and store cancellation token for this prompt let cancel_token = CancellationToken::new(); - // Convert ACP prompt to Goose message let user_message = self.convert_acp_prompt_to_message(args.prompt); - // Prepare for agent reply - let messages = { - let mut sessions = self.sessions.lock().await; - let session = sessions - .get_mut(&session_id) - .ok_or_else(acp::Error::invalid_params)?; - - // Add message to conversation - session.messages.push(user_message); - - // Store cancellation token - session.cancel_token = Some(cancel_token.clone()); + let session = SessionManager::create_session( + std::env::current_dir().unwrap_or_default(), + "ACP Session".to_string(), + SessionType::Hidden, + ) + .await?; - // Clone what we need for the reply call - session.messages.clone() + let session_config = SessionConfig { + id: session.id.clone(), + schedule_id: None, + max_turns: None, + retry_config: None, }; // Get agent's reply through the Goose agent let mut stream = self .agent - .reply(messages, None, Some(cancel_token.clone())) + .reply(user_message, session_config, Some(cancel_token.clone())) .await .map_err(|e| { error!("Error getting agent reply: {}", e); diff --git a/crates/goose-cli/src/commands/bench.rs b/crates/goose-cli/src/commands/bench.rs index d67b91913151..da6af17a78fc 100644 --- a/crates/goose-cli/src/commands/bench.rs +++ b/crates/goose-cli/src/commands/bench.rs @@ -26,9 +26,7 @@ impl BenchBaseSession for CliSession { } fn get_session_id(&self) -> anyhow::Result { - self.session_id() - .cloned() - .ok_or_else(|| anyhow::anyhow!("No session ID available")) + Ok(self.session_id().to_string()) } } pub async fn agent_generator( diff --git a/crates/goose-cli/src/commands/schedule.rs b/crates/goose-cli/src/commands/schedule.rs index 2756fa2e44c0..12f2c08684bb 100644 --- a/crates/goose-cli/src/commands/schedule.rs +++ b/crates/goose-cli/src/commands/schedule.rs @@ -98,7 +98,6 @@ pub async fn handle_schedule_add( paused: false, current_session_id: None, process_start_time: None, - execution_mode: Some("background".to_string()), // Default to background for CLI }; let scheduler_storage_path = diff --git a/crates/goose-cli/src/commands/web.rs b/crates/goose-cli/src/commands/web.rs index f49e44fa919c..8fa49a6645f9 100644 --- a/crates/goose-cli/src/commands/web.rs +++ b/crates/goose-cli/src/commands/web.rs @@ -15,6 +15,7 @@ use base64::Engine; use futures::{sink::SinkExt, stream::StreamExt}; use goose::agents::{Agent, AgentEvent}; use goose::conversation::message::Message as GooseMessage; +use goose::session::session_manager::SessionType; use goose::session::SessionManager; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -226,6 +227,7 @@ async fn serve_index() -> Result { let session = SessionManager::create_session( std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")), "Web session".to_string(), + SessionType::User, ) .await .map_err(|err| (http::StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?; @@ -467,21 +469,16 @@ async fn process_message_streaming( let session = SessionManager::get_session(&session_id, true).await?; let mut messages = session.conversation.unwrap_or_default(); - messages.push(user_message); + messages.push(user_message.clone()); let session_config = SessionConfig { id: session.id.clone(), - working_dir: session.working_dir, schedule_id: None, - execution_mode: None, max_turns: None, retry_config: None, }; - match agent - .reply(messages.clone(), Some(session_config), None) - .await - { + match agent.reply(user_message, session_config, None).await { Ok(mut stream) => { while let Some(result) = stream.next().await { match result { diff --git a/crates/goose-cli/src/scenario_tests/scenario_runner.rs b/crates/goose-cli/src/scenario_tests/scenario_runner.rs index 00a90778d3ae..df09e5ebcf2d 100644 --- a/crates/goose-cli/src/scenario_tests/scenario_runner.rs +++ b/crates/goose-cli/src/scenario_tests/scenario_runner.rs @@ -9,8 +9,10 @@ use anyhow::Result; use goose::agents::Agent; use goose::model::ModelConfig; use goose::providers::{create, testprovider::TestProvider}; +use goose::session::session_manager::SessionType; +use goose::session::SessionManager; use std::collections::{HashMap, HashSet}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -190,7 +192,6 @@ where ) }; - // Generate messages using the provider let messages = vec![message_generator(&*provider_arc)]; let mock_client = weather_client(); @@ -218,11 +219,17 @@ where .update_provider(provider_arc as Arc) .await?; - let mut session = CliSession::new(agent, None, false, None, None, None, None).await; + let session = SessionManager::create_session( + PathBuf::default(), + "scenario-runner".to_string(), + SessionType::Hidden, + ) + .await?; + let mut cli_session = CliSession::new(agent, session.id, false, None, None, None, None).await; let mut error = None; for message in &messages { - if let Err(e) = session + if let Err(e) = cli_session .process_message(message.clone(), CancellationToken::default()) .await { @@ -230,7 +237,7 @@ where break; } } - let updated_messages = session.message_history(); + let updated_messages = cli_session.message_history(); if let Some(ref err_msg) = error { if err_msg.contains("No recorded response found") { @@ -249,7 +256,7 @@ where validator(&result)?; - drop(session); + drop(cli_session); if let Some(provider) = provider_for_saving { if result.error.is_none() { diff --git a/crates/goose-cli/src/session/builder.rs b/crates/goose-cli/src/session/builder.rs index 8c0811a4b415..bc15cdbc5026 100644 --- a/crates/goose-cli/src/session/builder.rs +++ b/crates/goose-cli/src/session/builder.rs @@ -11,6 +11,7 @@ use goose::providers::create; use goose::recipe::{Response, SubRecipe}; use goose::agents::extension::PlatformExtensionContext; +use goose::session::session_manager::SessionType; use goose::session::SessionManager; use goose::session::{EnabledExtensionsState, ExtensionState}; use rustyline::EditMode; @@ -25,7 +26,7 @@ use tokio::task::JoinSet; /// including session identification, extension configuration, and debug settings. #[derive(Default, Clone, Debug)] pub struct SessionBuilderConfig { - /// Optional session ID for resuming or identifying an existing session + /// Session id, optional need to deduce from context pub session_id: Option, /// Whether to resume an existing session pub resume: bool, @@ -132,8 +133,14 @@ async fn offer_extension_debugging_help( } } - // Create the debugging session - let mut debug_session = CliSession::new(debug_agent, None, false, None, None, None, None).await; + let session = SessionManager::create_session( + std::env::current_dir()?, + "CLI Session".to_string(), + SessionType::Hidden, + ) + .await?; + let mut debug_session = + CliSession::new(debug_agent, session.id, false, None, None, None, None).await; // Process the debugging request println!("{}", style("Analyzing the extension failure...").yellow()); @@ -278,12 +285,20 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { process::exit(1); }); - let session_id: Option = if session_config.no_session { - None + let session_id: String = if session_config.no_session { + let working_dir = std::env::current_dir().expect("Could not get working directory"); + let session = SessionManager::create_session( + working_dir, + "CLI Session".to_string(), + SessionType::Hidden, + ) + .await + .expect("Could not create session"); + session.id } else if session_config.resume { if let Some(session_id) = session_config.session_id { match SessionManager::get_session(&session_id, false).await { - Ok(_) => Some(session_id), + Ok(_) => session_id, Err(_) => { output::render_error(&format!( "Cannot resume session {} - no such session exists", @@ -294,7 +309,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { } } else { match SessionManager::list_sessions().await { - Ok(sessions) if !sessions.is_empty() => Some(sessions[0].id.clone()), + Ok(sessions) if !sessions.is_empty() => sessions[0].id.clone(), _ => { output::render_error("Cannot resume - no previous sessions found"); process::exit(1); @@ -302,46 +317,44 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { } } } else { - session_config.session_id + session_config.session_id.unwrap() }; agent .extension_manager .set_context(PlatformExtensionContext { - session_id: session_id.clone(), + session_id: Some(session_id.clone()), extension_manager: Some(Arc::downgrade(&agent.extension_manager)), tool_route_manager: Some(Arc::downgrade(&agent.tool_route_manager)), }) .await; if session_config.resume { - if let Some(session_id) = session_id.as_ref() { - let metadata = SessionManager::get_session(session_id, false) - .await - .unwrap_or_else(|e| { - output::render_error(&format!("Failed to read session metadata: {}", e)); - process::exit(1); - }); + let session = SessionManager::get_session(&session_id, false) + .await + .unwrap_or_else(|e| { + output::render_error(&format!("Failed to read session metadata: {}", e)); + process::exit(1); + }); - let current_workdir = - std::env::current_dir().expect("Failed to get current working directory"); - if current_workdir != metadata.working_dir { - let change_workdir = cliclack::confirm(format!("{} The original working directory of this session was set to {}. Your current directory is {}. Do you want to switch back to the original working directory?", style("WARNING:").yellow(), style(metadata.working_dir.display()).cyan(), style(current_workdir.display()).cyan())) + let current_workdir = + std::env::current_dir().expect("Failed to get current working directory"); + if current_workdir != session.working_dir { + let change_workdir = cliclack::confirm(format!("{} The original working directory of this session was set to {}. Your current directory is {}. Do you want to switch back to the original working directory?", style("WARNING:").yellow(), style(session.working_dir.display()).cyan(), style(current_workdir.display()).cyan())) .initial_value(true) .interact().expect("Failed to get user input"); - if change_workdir { - if !metadata.working_dir.exists() { - output::render_error(&format!( - "Cannot switch to original working directory - {} no longer exists", - style(metadata.working_dir.display()).cyan() - )); - } else if let Err(e) = std::env::set_current_dir(&metadata.working_dir) { - output::render_error(&format!( - "Failed to switch to original working directory: {}", - e - )); - } + if change_workdir { + if !session.working_dir.exists() { + output::render_error(&format!( + "Cannot switch to original working directory - {} no longer exists", + style(session.working_dir.display()).cyan() + )); + } else if let Err(e) = std::env::set_current_dir(&session.working_dir) { + output::render_error(&format!( + "Failed to switch to original working directory: {}", + e + )); } } } @@ -354,22 +367,18 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { agent.disable_router_for_recipe().await; extensions.into_iter().collect() } else if session_config.resume { - if let Some(session_id) = session_id.as_ref() { - match SessionManager::get_session(session_id, false).await { - Ok(session_data) => { - if let Some(saved_state) = - EnabledExtensionsState::from_extension_data(&session_data.extension_data) - { - check_missing_extensions_or_exit(&saved_state.extensions); - saved_state.extensions - } else { - get_enabled_extensions() - } + match SessionManager::get_session(&session_id, false).await { + Ok(session_data) => { + if let Some(saved_state) = + EnabledExtensionsState::from_extension_data(&session_data.extension_data) + { + check_missing_extensions_or_exit(&saved_state.extensions); + saved_state.extensions + } else { + get_enabled_extensions() } - _ => get_enabled_extensions(), } - } else { - get_enabled_extensions() + _ => get_enabled_extensions(), } } else { get_enabled_extensions() @@ -560,23 +569,19 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { } } - if let Some(session_id) = session_id.as_ref() { - let session_config_for_save = SessionConfig { - id: session_id.clone(), - working_dir: std::env::current_dir().unwrap_or_default(), - schedule_id: None, - execution_mode: None, - max_turns: None, - retry_config: None, - }; + let session_config_for_save = SessionConfig { + id: session_id.clone(), + schedule_id: None, + max_turns: None, + retry_config: None, + }; - if let Err(e) = session - .agent - .save_extension_state(&session_config_for_save) - .await - { - tracing::warn!("Failed to save initial extension state: {}", e); - } + if let Err(e) = session + .agent + .save_extension_state(&session_config_for_save) + .await + { + tracing::warn!("Failed to save initial extension state: {}", e); } // Add CLI-specific system prompt extension @@ -603,7 +608,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { session_config.resume, &provider_name, &model_name, - &session_id, + &Some(session_id), Some(&provider_for_display), ); } diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index a8f5ce06c1b0..94192f86b655 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -58,7 +58,7 @@ pub enum RunMode { pub struct CliSession { agent: Agent, messages: Conversation, - session_id: Option, + session_id: String, completion_cache: Arc>, debug: bool, run_mode: RunMode, @@ -122,21 +122,17 @@ pub async fn classify_planner_response( impl CliSession { pub async fn new( agent: Agent, - session_id: Option, + session_id: String, debug: bool, scheduled_job_id: Option, max_turns: Option, edit_mode: Option, retry_config: Option, ) -> Self { - let messages = if let Some(session_id) = &session_id { - SessionManager::get_session(session_id, true) - .await - .map(|session| session.conversation.unwrap_or_default()) - .unwrap() - } else { - Conversation::new_unvalidated(Vec::new()) - }; + let messages = SessionManager::get_session(&session_id, true) + .await + .map(|session| session.conversation.unwrap_or_default()) + .unwrap(); CliSession { agent, @@ -152,8 +148,8 @@ impl CliSession { } } - pub fn session_id(&self) -> Option<&String> { - self.session_id.as_ref() + pub fn session_id(&self) -> &String { + &self.session_id } /// Add a stdio extension to the session @@ -359,9 +355,6 @@ impl CliSession { cancel_token: CancellationToken, ) -> Result<()> { let cancel_token = cancel_token.clone(); - - // TODO(Douwe): Make sure we generate the description here still: - self.push_message(message); self.process_agent_response(false, cancel_token).await?; Ok(()) @@ -443,7 +436,7 @@ impl CliSession { // Track the current directory and last instruction in projects.json if let Err(e) = crate::project_tracker::update_project_tracker( Some(&content), - self.session_id.as_deref(), + Some(&self.session_id), ) { eprintln!("Warning: Failed to update project tracker with instruction: {}", e); } @@ -583,16 +576,14 @@ impl CliSession { input::InputResult::Clear => { save_history(&mut editor); - if let Some(session_id) = &self.session_id { - if let Err(e) = SessionManager::replace_conversation( - session_id, - &Conversation::default(), - ) - .await - { - output::render_error(&format!("Failed to clear session: {}", e)); - continue; - } + if let Err(e) = SessionManager::replace_conversation( + &self.session_id, + &Conversation::default(), + ) + .await + { + output::render_error(&format!("Failed to clear session: {}", e)); + continue; } self.messages.clear(); @@ -671,9 +662,10 @@ impl CliSession { } } - if let Some(id) = &self.session_id { - println!("Closing session. Session ID: {}", console::style(id).cyan()); - } + println!( + "Closing session. Session ID: {}", + console::style(&self.session_id).cyan() + ); Ok(()) } @@ -768,18 +760,20 @@ impl CliSession { ) -> Result<()> { let cancel_token_clone = cancel_token.clone(); - let session_config = self.session_id.as_ref().map(|session_id| SessionConfig { - id: session_id.clone(), - working_dir: std::env::current_dir().unwrap_or_default(), + let session_config = SessionConfig { + id: self.session_id.clone(), schedule_id: self.scheduled_job_id.clone(), - execution_mode: None, max_turns: self.max_turns, retry_config: self.retry_config.clone(), - }); + }; + let user_message = self + .messages + .last() + .ok_or_else(|| anyhow::anyhow!("No user message"))?; let mut stream = self .agent .reply( - self.messages.clone(), + user_message.clone(), session_config.clone(), Some(cancel_token.clone()), ) @@ -1224,16 +1218,13 @@ impl CliSession { ); } - pub async fn get_metadata(&self) -> Result { - match &self.session_id { - Some(id) => SessionManager::get_session(id, false).await, - None => Err(anyhow::anyhow!("No session available")), - } + pub async fn get_session(&self) -> Result { + SessionManager::get_session(&self.session_id, false).await } // Get the session's total token usage pub async fn get_total_token_usage(&self) -> Result> { - let metadata = self.get_metadata().await?; + let metadata = self.get_session().await?; Ok(metadata.total_tokens) } @@ -1265,7 +1256,7 @@ impl CliSession { } } - match self.get_metadata().await { + match self.get_session().await { Ok(metadata) => { let total_tokens = metadata.total_tokens.unwrap_or(0) as usize; diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index 37fc4a77bc86..4667b93135ac 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -6,7 +6,7 @@ use goose::config::ExtensionEntry; use goose::conversation::Conversation; use goose::permission::permission_confirmation::PrincipalType; use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata, ProviderType}; -use goose::session::{Session, SessionInsights}; +use goose::session::{Session, SessionInsights, SessionType}; use rmcp::model::{ Annotations, Content, EmbeddedResource, Icon, ImageContent, JsonObject, RawAudioContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ResourceContents, Role, @@ -444,6 +444,7 @@ derive_utoipa!(Icon as IconSchema); ModelInfo, Session, SessionInsights, + SessionType, Conversation, IconSchema, goose::session::extension_data::ExtensionData, diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index 29898542b8af..031b7096b220 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -18,6 +18,7 @@ use goose::prompt_template::render_global_file; use goose::providers::{create, create_with_named_model}; use goose::recipe::Recipe; use goose::recipe_deeplink; +use goose::session::session_manager::SessionType; use goose::session::{Session, SessionManager}; use goose::{ agents::{extension::ToolInfo, extension_manager::get_parameter_names}, @@ -137,15 +138,16 @@ async fn start_agent( let counter = state.session_counter.fetch_add(1, Ordering::SeqCst) + 1; let name = format!("New session {}", counter); - let mut session = SessionManager::create_session(PathBuf::from(&working_dir), name) - .await - .map_err(|err| { - error!("Failed to create session: {}", err); - ErrorResponse { - message: format!("Failed to create session: {}", err), - status: StatusCode::BAD_REQUEST, - } - })?; + let mut session = + SessionManager::create_session(PathBuf::from(&working_dir), name, SessionType::User) + .await + .map_err(|err| { + error!("Failed to create session: {}", err); + ErrorResponse { + message: format!("Failed to create session: {}", err), + status: StatusCode::BAD_REQUEST, + } + })?; if let Some(recipe) = original_recipe { SessionManager::update_session(&session.id) diff --git a/crates/goose-server/src/routes/reply.rs b/crates/goose-server/src/routes/reply.rs index 0748399991be..6c5425d9a04e 100644 --- a/crates/goose-server/src/routes/reply.rs +++ b/crates/goose-server/src/routes/reply.rs @@ -257,17 +257,30 @@ pub async fn reply( let session_config = SessionConfig { id: session_id.clone(), - working_dir: session.working_dir.clone(), schedule_id: session.schedule_id.clone(), - execution_mode: None, max_turns: None, retry_config: None, }; + let user_message = match messages.last() { + Some(msg) => msg, + _ => { + let _ = stream_event( + MessageEvent::Error { + error: "Reply started with empty messages".to_string(), + }, + &task_tx, + &task_cancel, + ) + .await; + return; + } + }; + let mut stream = match agent .reply( - messages.clone(), - Some(session_config.clone()), + user_message.clone(), + session_config, Some(task_cancel.clone()), ) .await diff --git a/crates/goose-server/src/routes/schedule.rs b/crates/goose-server/src/routes/schedule.rs index b15e3f131481..077bf0e2c364 100644 --- a/crates/goose-server/src/routes/schedule.rs +++ b/crates/goose-server/src/routes/schedule.rs @@ -115,7 +115,6 @@ async fn create_schedule( paused: false, current_session_id: None, process_start_time: None, - execution_mode: req.execution_mode.or(Some("background".to_string())), // Default to background }; scheduler .add_scheduled_job(job.clone()) diff --git a/crates/goose/examples/agent.rs b/crates/goose/examples/agent.rs index d57226a7a797..014d63b302ad 100644 --- a/crates/goose/examples/agent.rs +++ b/crates/goose/examples/agent.rs @@ -1,11 +1,13 @@ use dotenvy::dotenv; use futures::StreamExt; -use goose::agents::{Agent, AgentEvent, ExtensionConfig}; +use goose::agents::{Agent, AgentEvent, ExtensionConfig, SessionConfig}; use goose::config::{DEFAULT_EXTENSION_DESCRIPTION, DEFAULT_EXTENSION_TIMEOUT}; use goose::conversation::message::Message; -use goose::conversation::Conversation; use goose::providers::create_with_named_model; use goose::providers::databricks::DATABRICKS_DEFAULT_MODEL; +use goose::session::session_manager::SessionType; +use goose::session::SessionManager; +use std::path::PathBuf; #[tokio::main] async fn main() { @@ -32,11 +34,29 @@ async fn main() { println!(" {}", extension); } - let conversation = Conversation::new(vec![Message::user() - .with_text("can you summarize the readme.md in this dir using just a haiku?")]) - .unwrap(); + let session = SessionManager::create_session( + PathBuf::default(), + "max-turn-test".to_string(), + SessionType::Hidden, + ) + .await + .expect("session manager creation failed"); + + let session_config = SessionConfig { + id: session.id, + schedule_id: None, + max_turns: None, + retry_config: None, + }; + + let user_message = Message::user() + .with_text("can you summarize the readme.md in this dir using just a haiku?"); + + let mut stream = agent + .reply(user_message, session_config, None) + .await + .unwrap(); - let mut stream = agent.reply(conversation, None, None).await.unwrap(); while let Some(Ok(AgentEvent::Message(message))) = stream.next().await { println!("{}", serde_json::to_string_pretty(&message).unwrap()); println!("\n"); diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index f958397046c3..9e80a08f8160 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -61,7 +61,7 @@ use super::tool_execution::{ToolCallResult, CHAT_MODE_TOOL_SKIPPED_RESPONSE, DEC use crate::agents::subagent_task_config::TaskConfig; use crate::conversation::message::{Message, MessageContent, SystemNotificationType, ToolRequest}; use crate::session::extension_data::{EnabledExtensionsState, ExtensionState}; -use crate::session::SessionManager; +use crate::session::{Session, SessionManager}; const DEFAULT_MAX_TURNS: u32 = 1000; const COMPACTION_THINKING_TEXT: &str = "goose is compacting the conversation..."; @@ -75,7 +75,6 @@ pub struct ReplyContext { pub system_prompt: String, pub goose_mode: GooseMode, pub initial_messages: Vec, - pub config: &'static Config, } pub struct ToolCategorizeResult { @@ -219,16 +218,20 @@ impl Agent { self.retry_manager.get_attempts().await } - /// Handle retry logic for the agent reply loop async fn handle_retry_logic( &self, messages: &mut Conversation, - session: &Option, + session_config: &SessionConfig, initial_messages: &[Message], ) -> Result { let result = self .retry_manager - .handle_retry_logic(messages, session, initial_messages, &self.final_output_tool) + .handle_retry_logic( + messages, + session_config, + initial_messages, + &self.final_output_tool, + ) .await?; match result { @@ -242,7 +245,6 @@ impl Agent { async fn prepare_reply_context( &self, unfixed_conversation: Conversation, - session: &Option, ) -> Result { let unfixed_messages = unfixed_conversation.messages().clone(); let (conversation, issues) = fix_conversation(unfixed_conversation.clone()); @@ -260,9 +262,8 @@ impl Agent { let config = Config::global(); let (tools, toolshim_tools, system_prompt) = self.prepare_tools_and_prompt().await?; - let goose_mode = Self::determine_goose_mode(session.as_ref(), config); + let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto); - // Update permission inspector mode to match the session mode self.tool_inspection_manager .update_permission_inspector_mode(goose_mode) .await; @@ -274,7 +275,6 @@ impl Agent { system_prompt, goose_mode, initial_messages, - config, }) } @@ -299,7 +299,7 @@ impl Agent { permission_check_result: &PermissionCheckResult, message_tool_response: Arc>, cancel_token: Option, - session: Option, + session: &Session, ) -> Result> { let mut tool_futures: Vec<(String, ToolStream)> = Vec::new(); @@ -311,7 +311,7 @@ impl Agent { tool_call, request.id.clone(), cancel_token.clone(), - session.clone(), + session, ) .await; @@ -392,7 +392,7 @@ impl Agent { tool_call: CallToolRequestParam, request_id: String, cancellation_token: Option, - session: Option, + session: &Session, ) -> (String, Result) { if tool_call.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME { let arguments = tool_call @@ -451,17 +451,13 @@ impl Agent { ); } }; - let (parent_session_id, parent_working_dir) = match session.as_ref() { - Some(s) => (Some(s.id.clone()), s.working_dir.clone()), - None => (None, std::env::current_dir().unwrap_or_default()), - }; // Get extensions from the agent's runtime state rather than global config // This ensures subagents inherit extensions that were dynamically enabled by the parent let extensions = self.get_extension_configs().await; let task_config = - TaskConfig::new(provider, parent_session_id, parent_working_dir, extensions); + TaskConfig::new(provider, &session.id, &session.working_dir, extensions); let arguments = match tool_call.arguments.clone() { Some(args) => Value::Object(args), @@ -731,117 +727,110 @@ impl Agent { } } - #[instrument(skip(self, unfixed_conversation, session), fields(user_message))] + #[instrument(skip(self, user_message, session_config), fields(user_message))] pub async fn reply( &self, - unfixed_conversation: Conversation, - session: Option, + user_message: Message, + session_config: SessionConfig, cancel_token: Option, ) -> Result>> { - let is_manual_compact = unfixed_conversation.messages().last().is_some_and(|msg| { - msg.content.iter().any(|c| { - if let MessageContent::Text(text) = c { - text.text.trim() == MANUAL_COMPACT_TRIGGER - } else { - false - } - }) + let is_manual_compact = user_message.content.iter().any(|c| { + if let MessageContent::Text(text) = c { + text.text.trim() == MANUAL_COMPACT_TRIGGER + } else { + false + } }); - if !is_manual_compact { - let session_metadata = if let Some(session_config) = &session { - SessionManager::get_session(&session_config.id, false) - .await - .ok() - } else { - None - }; + SessionManager::add_message(&session_config.id, &user_message).await?; + let session = SessionManager::get_session(&session_config.id, true).await?; - let needs_auto_compact = crate::context_mgmt::check_if_compaction_needed( - self, - &unfixed_conversation, - None, - session_metadata.as_ref(), - ) - .await?; + let conversation = session + .conversation + .clone() + .ok_or_else(|| anyhow::anyhow!("Session {} has no conversation", session_config.id))?; - if !needs_auto_compact { - return self - .reply_internal(unfixed_conversation, session, cancel_token) - .await; - } - } + let needs_auto_compact = + crate::context_mgmt::check_if_compaction_needed(self, &conversation, None, &session) + .await?; - let conversation_to_compact = unfixed_conversation.clone(); + let conversation_to_compact = conversation.clone(); Ok(Box::pin(async_stream::try_stream! { - if !is_manual_compact { - let config = crate::config::Config::global(); - let threshold = config - .get_param::("GOOSE_AUTO_COMPACT_THRESHOLD") - .unwrap_or(DEFAULT_COMPACTION_THRESHOLD); - let threshold_percentage = (threshold * 100.0) as u32; - - let inline_msg = format!( - "Exceeded auto-compact threshold of {}%. Performing auto-compaction...", - threshold_percentage - ); + let final_conversation = if !needs_auto_compact { + conversation + } else { + if !is_manual_compact { + let config = crate::config::Config::global(); + let threshold = config + .get_param::("GOOSE_AUTO_COMPACT_THRESHOLD") + .unwrap_or(DEFAULT_COMPACTION_THRESHOLD); + let threshold_percentage = (threshold * 100.0) as u32; + + let inline_msg = format!( + "Exceeded auto-compact threshold of {}%. Performing auto-compaction...", + threshold_percentage + ); + + yield AgentEvent::Message( + Message::assistant().with_system_notification( + SystemNotificationType::InlineMessage, + inline_msg, + ) + ); + } yield AgentEvent::Message( Message::assistant().with_system_notification( - SystemNotificationType::InlineMessage, - inline_msg, + SystemNotificationType::ThinkingMessage, + COMPACTION_THINKING_TEXT, ) ); - } - yield AgentEvent::Message( - Message::assistant().with_system_notification( - SystemNotificationType::ThinkingMessage, - COMPACTION_THINKING_TEXT, - ) - ); - - match crate::context_mgmt::compact_messages(self, &conversation_to_compact, false).await { - Ok((compacted_conversation, summarization_usage)) => { - if let Some(session_to_store) = &session { - SessionManager::replace_conversation(&session_to_store.id, &compacted_conversation).await?; - Self::update_session_metrics(session_to_store, &summarization_usage, true).await?; - } + match crate::context_mgmt::compact_messages(self, &conversation_to_compact, false).await { + Ok((compacted_conversation, summarization_usage)) => { + SessionManager::replace_conversation(&session_config.id, &compacted_conversation).await?; + Self::update_session_metrics(&session_config, &summarization_usage, true).await?; - yield AgentEvent::HistoryReplaced(compacted_conversation.clone()); + yield AgentEvent::HistoryReplaced(compacted_conversation.clone()); - yield AgentEvent::Message( - Message::assistant().with_system_notification( - SystemNotificationType::InlineMessage, - "Compaction complete", - ) - ); + yield AgentEvent::Message( + Message::assistant().with_system_notification( + SystemNotificationType::InlineMessage, + "Compaction complete", + ) + ); - if !is_manual_compact { - let mut reply_stream = self.reply_internal(compacted_conversation, session, cancel_token).await?; - while let Some(event) = reply_stream.next().await { - yield event?; - } + compacted_conversation + } + Err(e) => { + yield AgentEvent::Message( + Message::assistant().with_text( + format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") + ) + ); + return; } } - Err(e) => { - yield AgentEvent::Message(Message::assistant().with_text( - format!("Ran into this error trying to compact: {e}.\n\nPlease try again or create a new session") - )); + }; + + if !is_manual_compact { + let mut reply_stream = self.reply_internal(final_conversation, session_config, session, cancel_token).await?; + while let Some(event) = reply_stream.next().await { + yield event?; } } })) } - /// Main reply method that handles the actual agent processing async fn reply_internal( &self, conversation: Conversation, - session: Option, + session_config: SessionConfig, + session: Session, cancel_token: Option, ) -> Result>> { - let context = self.prepare_reply_context(conversation, &session).await?; + let context = self.prepare_reply_context(conversation).await?; let ReplyContext { mut conversation, mut tools, @@ -849,66 +838,22 @@ impl Agent { mut system_prompt, goose_mode, initial_messages, - config, } = context; let reply_span = tracing::Span::current(); self.reset_retry_attempts().await; - // This will need further refactoring. In the ideal world we pass the new message into - // reply and load the existing conversation. Until we get to that point, fetch the conversation - // so far and append the last (user) message that the caller already added. - if let Some(session_config) = &session { - let stored_conversation = SessionManager::get_session(&session_config.id, true) - .await? - .conversation - .ok_or_else(|| { - anyhow::anyhow!("Session {} has no conversation", session_config.id) - })?; - - match conversation.len().cmp(&stored_conversation.len()) { - std::cmp::Ordering::Equal => { - if conversation != stored_conversation { - warn!("Session messages mismatch - replacing with incoming"); - SessionManager::replace_conversation(&session_config.id, &conversation) - .await?; - } - } - std::cmp::Ordering::Greater - if conversation.len() == stored_conversation.len() + 1 => - { - let last_message = conversation.last().unwrap(); - if let Some(content) = last_message.content.first().and_then(|c| c.as_text()) { - debug!("user_message" = &content); - } - SessionManager::add_message(&session_config.id, last_message).await?; - } - _ => { - warn!( - "Unexpected session state: stored={}, incoming={}. Replacing.", - stored_conversation.len(), - conversation.len() - ); - SessionManager::replace_conversation(&session_config.id, &conversation).await?; - } + let provider = self.provider().await?; + let session_id = session_config.id.clone(); + tokio::spawn(async move { + if let Err(e) = SessionManager::maybe_update_name(&session_id, provider).await { + warn!("Failed to generate session description: {}", e); } - let provider = self.provider().await?; - let session_id = session_config.id.clone(); - tokio::spawn(async move { - if let Err(e) = SessionManager::maybe_update_name(&session_id, provider).await { - warn!("Failed to generate session description: {}", e); - } - }); - } + }); Ok(Box::pin(async_stream::try_stream! { let _ = reply_span.enter(); let mut turns_taken = 0u32; - let max_turns = session - .as_ref() - .and_then(|s| s.max_turns) - .unwrap_or_else(|| { - config.get_param("GOOSE_MAX_TURNS").unwrap_or(DEFAULT_MAX_TURNS) - }); + let max_turns = session_config.max_turns.unwrap_or(DEFAULT_MAX_TURNS); loop { if is_token_cancelled(&cancel_token) { @@ -989,11 +934,8 @@ impl Agent { } } - // Record usage for the session - if let Some(ref session_config) = &session { - if let Some(ref usage) = usage { - Self::update_session_metrics(session_config, usage, false).await?; - } + if let Some(ref usage) = usage { + Self::update_session_metrics(&session_config, usage, false).await?; } if let Some(response) = response { @@ -1078,18 +1020,17 @@ impl Agent { &permission_check_result, message_tool_response.clone(), cancel_token.clone(), - session.clone(), + &session, ).await?; let tool_futures_arc = Arc::new(Mutex::new(tool_futures)); - // Process tools requiring approval let mut tool_approval_stream = self.handle_approval_tool_requests( &permission_check_result.needs_approval, tool_futures_arc.clone(), message_tool_response.clone(), cancel_token.clone(), - session.clone(), + &session, &inspection_results, ); @@ -1136,10 +1077,8 @@ impl Agent { } if all_install_successful && !enable_extension_request_ids.is_empty() { - if let Some(ref session_config) = session { - if let Err(e) = self.save_extension_state(session_config).await { - warn!("Failed to save extension state after runtime changes: {}", e); - } + if let Err(e) = self.save_extension_state(&session_config).await { + warn!("Failed to save extension state after runtime changes: {}", e); } tools_updated = true; } @@ -1168,14 +1107,10 @@ impl Agent { match crate::context_mgmt::compact_messages(self, &conversation, true).await { Ok((compacted_conversation, usage)) => { - if let Some(session_to_store) = &session { - SessionManager::replace_conversation(&session_to_store.id, &compacted_conversation).await?; - Self::update_session_metrics(session_to_store, &usage, true).await?; - } - + SessionManager::replace_conversation(&session_config.id, &compacted_conversation).await?; + Self::update_session_metrics(&session_config, &usage, true).await?; conversation = compacted_conversation; did_recovery_compact_this_iteration = true; - yield AgentEvent::HistoryReplaced(conversation.clone()); continue; } @@ -1221,7 +1156,7 @@ impl Agent { } else if did_recovery_compact_this_iteration { // Avoid setting exit_chat; continue from last user message in the conversation } else { - match self.handle_retry_logic(&mut conversation, &session, &initial_messages).await { + match self.handle_retry_logic(&mut conversation, &session_config, &initial_messages).await { Ok(should_retry) => { if should_retry { info!("Retry logic triggered, restarting agent loop"); @@ -1242,10 +1177,8 @@ impl Agent { } } - if let Some(session_config) = &session { - for msg in &messages_to_add { - SessionManager::add_message(&session_config.id, msg).await?; - } + for msg in &messages_to_add { + SessionManager::add_message(&session_config.id, msg).await?; } conversation.extend(messages_to_add); if exit_chat { @@ -1257,17 +1190,6 @@ impl Agent { })) } - fn determine_goose_mode(session: Option<&SessionConfig>, config: &Config) -> GooseMode { - let mode = session.and_then(|s| s.execution_mode.as_deref()); - - match mode { - Some("foreground") => GooseMode::Chat, - Some("background") => GooseMode::Auto, - _ => config.get_goose_mode().unwrap_or(GooseMode::Auto), - } - } - - /// Extend the system prompt with one line of additional instruction pub async fn extend_system_prompt(&self, instruction: String) { let mut prompt_manager = self.prompt_manager.lock().await; prompt_manager.add_system_prompt_extra(instruction); diff --git a/crates/goose/src/agents/platform_tools.rs b/crates/goose/src/agents/platform_tools.rs index 57bde5eaeb3e..e0877bdb717d 100644 --- a/crates/goose/src/agents/platform_tools.rs +++ b/crates/goose/src/agents/platform_tools.rs @@ -33,7 +33,6 @@ pub fn manage_schedule_tool() -> Tool { "job_id": {"type": "string", "description": "Job identifier for operations on existing jobs"}, "recipe_path": {"type": "string", "description": "Path to recipe file for create action"}, "cron_expression": {"type": "string", "description": "A cron expression for create action. Supports both 5-field (minute hour day month weekday) and 6-field (second minute hour day month weekday) formats. 5-field expressions are automatically converted to 6-field by prepending '0' for seconds."}, - "execution_mode": {"type": "string", "description": "Execution mode for create action: 'foreground' or 'background'", "enum": ["foreground", "background"], "default": "background"}, "limit": {"type": "integer", "description": "Limit for sessions list", "default": 50}, "session_id": {"type": "string", "description": "Session identifier for session_content action"} } diff --git a/crates/goose/src/agents/retry.rs b/crates/goose/src/agents/retry.rs index ffa53b655075..b39dbcfd2cf6 100644 --- a/crates/goose/src/agents/retry.rs +++ b/crates/goose/src/agents/retry.rs @@ -108,18 +108,13 @@ impl RetryManager { } } - /// Handle retry logic for the agent reply loop pub async fn handle_retry_logic( &self, messages: &mut Conversation, - session: &Option, + session_config: &SessionConfig, initial_messages: &[Message], final_output_tool: &Arc>>, ) -> Result { - let Some(session_config) = session else { - return Ok(RetryResult::Skipped); - }; - let Some(retry_config) = &session_config.retry_config else { return Ok(RetryResult::Skipped); }; diff --git a/crates/goose/src/agents/schedule_tool.rs b/crates/goose/src/agents/schedule_tool.rs index 3fb98a9de564..3651c9bc7c96 100644 --- a/crates/goose/src/agents/schedule_tool.rs +++ b/crates/goose/src/agents/schedule_tool.rs @@ -186,7 +186,6 @@ impl Agent { paused: false, current_session_id: None, process_start_time: None, - execution_mode: Some(execution_mode.to_string()), }; match scheduler.add_scheduled_job(job).await { diff --git a/crates/goose/src/agents/subagent_handler.rs b/crates/goose/src/agents/subagent_handler.rs index 47ee99d08879..e02cf6427c41 100644 --- a/crates/goose/src/agents/subagent_handler.rs +++ b/crates/goose/src/agents/subagent_handler.rs @@ -1,8 +1,6 @@ +use crate::session::session_manager::SessionType; use crate::{ - agents::{ - extension::PlatformExtensionContext, subagent_task_config::TaskConfig, Agent, AgentEvent, - SessionConfig, - }, + agents::{subagent_task_config::TaskConfig, AgentEvent, SessionConfig}, conversation::{message::Message, Conversation}, execution::manager::AgentManager, session::SessionManager, @@ -10,8 +8,8 @@ use crate::{ use anyhow::{anyhow, Result}; use futures::StreamExt; use rmcp::model::{ErrorCode, ErrorData}; +use std::future::Future; use std::pin::Pin; -use std::{future::Future, sync::Arc}; use tracing::debug; /// Standalone function to run a complete subagent task with output options @@ -104,34 +102,18 @@ fn get_agent_messages( .map_err(|e| anyhow!("Failed to create AgentManager: {}", e))?; let parent_session_id = task_config.parent_session_id; let working_dir = task_config.parent_working_dir; - let (agent, session_id) = match parent_session_id { - Some(parent_session_id) => { - let session = SessionManager::create_session( - working_dir.clone(), - format!("Subagent task for: {}", parent_session_id), - ) - .await - .map_err(|e| anyhow!("Failed to create a session for sub agent: {}", e))?; + let session = SessionManager::create_session( + working_dir.clone(), + format!("Subagent task for: {}", parent_session_id), + SessionType::SubAgent, + ) + .await + .map_err(|e| anyhow!("Failed to create a session for sub agent: {}", e))?; - let agent = agent_manager - .get_or_create_agent(session.id.clone()) - .await - .map_err(|e| anyhow!("Failed to get sub agent session file path: {}", e))?; - (agent, Some(session.id)) - } - None => { - let agent = Arc::new(Agent::new()); - agent - .extension_manager - .set_context(PlatformExtensionContext { - session_id: None, - extension_manager: Some(Arc::downgrade(&agent.extension_manager)), - tool_route_manager: Some(Arc::downgrade(&agent.tool_route_manager)), - }) - .await; - (agent, None) - } - }; + let agent = agent_manager + .get_or_create_agent(session.id.clone()) + .await + .map_err(|e| anyhow!("Failed to get sub agent session file path: {}", e))?; agent .update_provider(task_config.provider) @@ -148,28 +130,18 @@ fn get_agent_messages( } } - let mut conversation = - Conversation::new_unvalidated( - vec![Message::user().with_text(text_instruction.clone())], - ); - let session_config = if let Some(session_id) = session_id { - Some(SessionConfig { - id: session_id, - working_dir, - schedule_id: None, - execution_mode: None, - max_turns: task_config.max_turns.map(|v| v as u32), - retry_config: None, - }) - } else { - None + let user_message = Message::user().with_text(text_instruction); + let mut conversation = Conversation::new_unvalidated(vec![user_message.clone()]); + + let session_config = SessionConfig { + id: session.id.clone(), + schedule_id: None, + max_turns: task_config.max_turns.map(|v| v as u32), + retry_config: None, }; - let session_id = session_config.as_ref().map(|s| s.id.clone()); - let mut stream = crate::session_context::with_session_id(session_id, async { - agent - .reply(conversation.clone(), session_config, None) - .await + let mut stream = crate::session_context::with_session_id(Some(session.id.clone()), async { + agent.reply(user_message, session_config, None).await }) .await .map_err(|e| anyhow!("Failed to get reply from agent: {}", e))?; diff --git a/crates/goose/src/agents/subagent_task_config.rs b/crates/goose/src/agents/subagent_task_config.rs index d3375c92be30..01c955d0c01c 100644 --- a/crates/goose/src/agents/subagent_task_config.rs +++ b/crates/goose/src/agents/subagent_task_config.rs @@ -2,7 +2,7 @@ use crate::agents::ExtensionConfig; use crate::providers::base::Provider; use std::env; use std::fmt; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::Arc; /// Default maximum number of turns for task execution @@ -15,7 +15,7 @@ pub const GOOSE_SUBAGENT_MAX_TURNS_ENV_VAR: &str = "GOOSE_SUBAGENT_MAX_TURNS"; #[derive(Clone)] pub struct TaskConfig { pub provider: Arc, - pub parent_session_id: Option, + pub parent_session_id: String, pub parent_working_dir: PathBuf, pub extensions: Vec, pub max_turns: Option, @@ -34,17 +34,16 @@ impl fmt::Debug for TaskConfig { } impl TaskConfig { - /// Create a new TaskConfig with all required dependencies pub fn new( provider: Arc, - parent_session_id: Option, - parent_working_dir: PathBuf, + parent_session_id: &str, + parent_working_dir: &Path, extensions: Vec, ) -> Self { Self { provider, - parent_session_id, - parent_working_dir, + parent_session_id: parent_session_id.to_owned(), + parent_working_dir: parent_working_dir.to_owned(), extensions, max_turns: Some( env::var(GOOSE_SUBAGENT_MAX_TURNS_ENV_VAR) diff --git a/crates/goose/src/agents/tool_execution.rs b/crates/goose/src/agents/tool_execution.rs index 64ab6af3d997..87c1986a7f36 100644 --- a/crates/goose/src/agents/tool_execution.rs +++ b/crates/goose/src/agents/tool_execution.rs @@ -29,8 +29,9 @@ impl From>> for ToolCallResult { } use super::agent::{tool_stream, ToolStream}; -use crate::agents::{Agent, SessionConfig}; +use crate::agents::Agent; use crate::conversation::message::{Message, ToolRequest}; +use crate::session::Session; use crate::tool_inspection::get_security_finding_id_from_results; pub const DECLINED_RESPONSE: &str = "The user has declined to run this tool. \ @@ -53,7 +54,7 @@ impl Agent { tool_futures: Arc>>, message_tool_response: Arc>, cancellation_token: Option, - session: Option, + session: &'a Session, inspection_results: &'a [crate::tool_inspection::InspectionResult], ) -> BoxStream<'a, anyhow::Result> { try_stream! { @@ -93,7 +94,7 @@ impl Agent { } if confirmation.permission == Permission::AllowOnce || confirmation.permission == Permission::AlwaysAllow { - let (req_id, tool_result) = self.dispatch_tool_call(tool_call.clone(), request.id.clone(), cancellation_token.clone(), session.clone()).await; + let (req_id, tool_result) = self.dispatch_tool_call(tool_call.clone(), request.id.clone(), cancellation_token.clone(), session).await; let mut futures = tool_futures.lock().await; futures.push((req_id, match tool_result { diff --git a/crates/goose/src/agents/types.rs b/crates/goose/src/agents/types.rs index 027560179b2a..0f2902bf9e15 100644 --- a/crates/goose/src/agents/types.rs +++ b/crates/goose/src/agents/types.rs @@ -2,7 +2,6 @@ use crate::mcp_utils::ToolResult; use crate::providers::base::Provider; use rmcp::model::{Content, Tool}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; use std::sync::Arc; use tokio::sync::{mpsc, Mutex}; use utoipa::ToSchema; @@ -84,14 +83,10 @@ pub struct FrontendTool { /// Session configuration for an agent #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SessionConfig { - /// Unique identifier for the session + /// Identifier of the underlying Session pub id: String, - /// Working directory for the session - pub working_dir: PathBuf, /// ID of the schedule that triggered this session, if any pub schedule_id: Option, - /// Execution mode for scheduled jobs: "foreground" or "background" - pub execution_mode: Option, /// Maximum number of turns (iterations) allowed without user input pub max_turns: Option, /// Retry configuration for automated validation and recovery diff --git a/crates/goose/src/context_mgmt/mod.rs b/crates/goose/src/context_mgmt/mod.rs index 57e43a706a75..e0ac4368aa81 100644 --- a/crates/goose/src/context_mgmt/mod.rs +++ b/crates/goose/src/context_mgmt/mod.rs @@ -145,11 +145,10 @@ pub async fn check_if_compaction_needed( agent: &Agent, conversation: &Conversation, threshold_override: Option, - session_metadata: Option<&crate::session::Session>, + session: &crate::session::Session, ) -> Result { let messages = conversation.messages(); let config = Config::global(); - // TODO(Douwe): check the default here; it seems to reset to 0.3 sometimes let threshold = threshold_override.unwrap_or_else(|| { config .get_param::("GOOSE_AUTO_COMPACT_THRESHOLD") @@ -159,7 +158,7 @@ pub async fn check_if_compaction_needed( let provider = agent.provider().await?; let context_limit = provider.get_model_config().context_limit(); - let (current_tokens, token_source) = match session_metadata.and_then(|m| m.total_tokens) { + let (current_tokens, token_source) = match session.total_tokens { Some(tokens) => (tokens as usize, "session metadata"), None => { let token_counter = create_token_counter() diff --git a/crates/goose/src/scheduler.rs b/crates/goose/src/scheduler.rs index 45eaeb13fa3b..84ce29560a23 100644 --- a/crates/goose/src/scheduler.rs +++ b/crates/goose/src/scheduler.rs @@ -21,6 +21,7 @@ use crate::providers::base::Provider as GooseProvider; // Alias to avoid conflic use crate::providers::create; use crate::recipe::Recipe; use crate::scheduler_trait::SchedulerTrait; +use crate::session::session_manager::SessionType; use crate::session::{Session, SessionManager}; // Track running tasks with their abort handles @@ -152,8 +153,6 @@ pub struct ScheduledJob { pub current_session_id: Option, #[serde(default)] pub process_start_time: Option>, - #[serde(default)] - pub execution_mode: Option, // "foreground" or "background" } async fn persist_jobs_from_arc( @@ -1160,8 +1159,6 @@ async fn run_scheduled_job_internal( }); } tracing::info!("Agent configured with provider for job '{}'", job.id); - let execution_mode = job.execution_mode.as_deref().unwrap_or("background"); - tracing::info!("Job '{}' running in {} mode", job.id, execution_mode); let current_dir = match std::env::current_dir() { Ok(cd) => cd, @@ -1173,10 +1170,10 @@ async fn run_scheduled_job_internal( } }; - // Create session upfront let session = match SessionManager::create_session( current_dir.clone(), format!("Scheduled job: {}", job.id), + SessionType::Scheduled, ) .await { @@ -1204,23 +1201,19 @@ async fn run_scheduled_job_internal( .or(recipe.instructions.as_ref()) .unwrap(); - let mut conversation = - Conversation::new_unvalidated(vec![Message::user().with_text(prompt_text.clone())]); + let user_message = Message::user().with_text(prompt_text); + let mut conversation = Conversation::new_unvalidated(vec![user_message.clone()]); let session_config = SessionConfig { id: session.id.clone(), - working_dir: current_dir.clone(), schedule_id: Some(job.id.clone()), - execution_mode: job.execution_mode.clone(), max_turns: None, retry_config: None, }; let session_id = Some(session_config.id.clone()); match crate::session_context::with_session_id(session_id, async { - agent - .reply(conversation.clone(), Some(session_config.clone()), None) - .await + agent.reply(user_message, session_config, None).await }) .await { @@ -1455,7 +1448,6 @@ mod tests { paused: false, current_session_id: None, process_start_time: None, - execution_mode: Some("background".to_string()), // Default for test }; let mock_model_config = ModelConfig::new_or_fail("test_model"); diff --git a/crates/goose/src/session/mod.rs b/crates/goose/src/session/mod.rs index e15579bb83c4..b8b7c8d5a28c 100644 --- a/crates/goose/src/session/mod.rs +++ b/crates/goose/src/session/mod.rs @@ -6,4 +6,4 @@ pub mod session_manager; pub use diagnostics::generate_diagnostics; pub use extension_data::{EnabledExtensionsState, ExtensionData, ExtensionState, TodoState}; -pub use session_manager::{Session, SessionInsights, SessionManager}; +pub use session_manager::{Session, SessionInsights, SessionManager, SessionType}; diff --git a/crates/goose/src/session/session_manager.rs b/crates/goose/src/session/session_manager.rs index ce97c8ead3f8..2f960cd8497e 100644 --- a/crates/goose/src/session/session_manager.rs +++ b/crates/goose/src/session/session_manager.rs @@ -18,7 +18,47 @@ use tokio::sync::OnceCell; use tracing::{info, warn}; use utoipa::ToSchema; -const CURRENT_SCHEMA_VERSION: i32 = 4; +const CURRENT_SCHEMA_VERSION: i32 = 5; + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum SessionType { + User, + Scheduled, + SubAgent, + Hidden, +} + +impl Default for SessionType { + fn default() -> Self { + Self::User + } +} + +impl std::fmt::Display for SessionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SessionType::User => write!(f, "user"), + SessionType::SubAgent => write!(f, "sub_agent"), + SessionType::Hidden => write!(f, "hidden"), + SessionType::Scheduled => write!(f, "scheduled"), + } + } +} + +impl std::str::FromStr for SessionType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "user" => Ok(SessionType::User), + "sub_agent" => Ok(SessionType::SubAgent), + "hidden" => Ok(SessionType::Hidden), + "scheduled" => Ok(SessionType::Scheduled), + _ => Err(anyhow::anyhow!("Invalid session type: {}", s)), + } + } +} static SESSION_STORAGE: OnceCell> = OnceCell::const_new(); @@ -27,11 +67,12 @@ pub struct Session { pub id: String, #[schema(value_type = String)] pub working_dir: PathBuf, - // Allow importing session exports from before 'description' was renamed to 'name' #[serde(alias = "description")] pub name: String, #[serde(default)] pub user_set_name: bool, + #[serde(default)] + pub session_type: SessionType, pub created_at: DateTime, pub updated_at: DateTime, pub extension_data: ExtensionData, @@ -52,6 +93,7 @@ pub struct SessionUpdateBuilder { session_id: String, name: Option, user_set_name: Option, + session_type: Option, working_dir: Option, extension_data: Option, total_tokens: Option>, @@ -78,6 +120,7 @@ impl SessionUpdateBuilder { session_id, name: None, user_set_name: None, + session_type: None, working_dir: None, extension_data: None, total_tokens: None, @@ -110,6 +153,11 @@ impl SessionUpdateBuilder { self } + pub fn session_type(mut self, session_type: SessionType) -> Self { + self.session_type = Some(session_type); + self + } + pub fn working_dir(mut self, working_dir: PathBuf) -> Self { self.working_dir = Some(working_dir); self @@ -183,10 +231,14 @@ impl SessionManager { .map(Arc::clone) } - pub async fn create_session(working_dir: PathBuf, name: String) -> Result { + pub async fn create_session( + working_dir: PathBuf, + name: String, + session_type: SessionType, + ) -> Result { Self::instance() .await? - .create_session(working_dir, name) + .create_session(working_dir, name, session_type) .await } @@ -306,6 +358,7 @@ impl Default for Session { working_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), name: String::new(), user_set_name: false, + session_type: SessionType::default(), created_at: Default::default(), updated_at: Default::default(), extension_data: ExtensionData::default(), @@ -353,11 +406,17 @@ impl sqlx::FromRow<'_, sqlx::sqlite::SqliteRow> for Session { let user_set_name = row.try_get("user_set_name").unwrap_or(false); + let session_type_str: String = row + .try_get("session_type") + .unwrap_or_else(|_| "user".to_string()); + let session_type = session_type_str.parse().unwrap_or_default(); + Ok(Session { id: row.try_get("id")?, working_dir: PathBuf::from(row.try_get::("working_dir")?), name, user_set_name, + session_type, created_at: row.try_get("created_at")?, updated_at: row.try_get("updated_at")?, extension_data: serde_json::from_str(&row.try_get::("extension_data")?) @@ -446,6 +505,7 @@ impl SessionStorage { name TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', user_set_name BOOLEAN DEFAULT FALSE, + session_type TEXT NOT NULL DEFAULT 'user', working_dir TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, @@ -491,6 +551,9 @@ impl SessionStorage { sqlx::query("CREATE INDEX idx_sessions_updated ON sessions(updated_at DESC)") .execute(&pool) .await?; + sqlx::query("CREATE INDEX idx_sessions_type ON sessions(session_type)") + .execute(&pool) + .await?; Ok(Self { pool }) } @@ -553,31 +616,32 @@ impl SessionStorage { sqlx::query( r#" INSERT INTO sessions ( - id, name, user_set_name, working_dir, created_at, updated_at, extension_data, + id, name, user_set_name, session_type, working_dir, created_at, updated_at, extension_data, total_tokens, input_tokens, output_tokens, accumulated_total_tokens, accumulated_input_tokens, accumulated_output_tokens, schedule_id, recipe_json, user_recipe_values_json - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "#, ) - .bind(&session.id) - .bind(&session.name) - .bind(session.user_set_name) - .bind(session.working_dir.to_string_lossy().as_ref()) - .bind(session.created_at) - .bind(session.updated_at) - .bind(serde_json::to_string(&session.extension_data)?) - .bind(session.total_tokens) - .bind(session.input_tokens) - .bind(session.output_tokens) - .bind(session.accumulated_total_tokens) - .bind(session.accumulated_input_tokens) - .bind(session.accumulated_output_tokens) - .bind(&session.schedule_id) - .bind(recipe_json) - .bind(user_recipe_values_json) - .execute(&self.pool) - .await?; + .bind(&session.id) + .bind(&session.name) + .bind(session.user_set_name) + .bind(session.session_type.to_string()) + .bind(session.working_dir.to_string_lossy().as_ref()) + .bind(session.created_at) + .bind(session.updated_at) + .bind(serde_json::to_string(&session.extension_data)?) + .bind(session.total_tokens) + .bind(session.input_tokens) + .bind(session.output_tokens) + .bind(session.accumulated_total_tokens) + .bind(session.accumulated_input_tokens) + .bind(session.accumulated_output_tokens) + .bind(&session.schedule_id) + .bind(recipe_json) + .bind(user_recipe_values_json) + .execute(&self.pool) + .await?; if let Some(conversation) = &session.conversation { self.replace_conversation(&session.id, conversation).await?; @@ -687,6 +751,19 @@ impl SessionStorage { .execute(&self.pool) .await?; } + 5 => { + sqlx::query( + r#" + ALTER TABLE sessions ADD COLUMN session_type TEXT NOT NULL DEFAULT 'user' + "#, + ) + .execute(&self.pool) + .await?; + + sqlx::query("CREATE INDEX idx_sessions_type ON sessions(session_type)") + .execute(&self.pool) + .await?; + } _ => { anyhow::bail!("Unknown migration version: {}", version); } @@ -695,11 +772,16 @@ impl SessionStorage { Ok(()) } - async fn create_session(&self, working_dir: PathBuf, name: String) -> Result { + async fn create_session( + &self, + working_dir: PathBuf, + name: String, + session_type: SessionType, + ) -> Result { let today = chrono::Utc::now().format("%Y%m%d").to_string(); Ok(sqlx::query_as( r#" - INSERT INTO sessions (id, name, user_set_name, working_dir, extension_data) + INSERT INTO sessions (id, name, user_set_name, session_type, working_dir, extension_data) VALUES ( ? || '_' || CAST(COALESCE(( SELECT MAX(CAST(SUBSTR(id, 10) AS INTEGER)) @@ -709,23 +791,25 @@ impl SessionStorage { ?, FALSE, ?, + ?, '{}' ) RETURNING * "#, ) - .bind(&today) - .bind(&today) - .bind(&name) - .bind(working_dir.to_string_lossy().as_ref()) - .fetch_one(&self.pool) - .await?) + .bind(&today) + .bind(&today) + .bind(&name) + .bind(session_type.to_string()) + .bind(working_dir.to_string_lossy().as_ref()) + .fetch_one(&self.pool) + .await?) } async fn get_session(&self, id: &str, include_messages: bool) -> Result { let mut session = sqlx::query_as::<_, Session>( r#" - SELECT id, working_dir, name, description, user_set_name, created_at, updated_at, extension_data, + SELECT id, working_dir, name, description, user_set_name, session_type, created_at, updated_at, extension_data, total_tokens, input_tokens, output_tokens, accumulated_total_tokens, accumulated_input_tokens, accumulated_output_tokens, schedule_id, recipe_json, user_recipe_values_json @@ -733,10 +817,10 @@ impl SessionStorage { WHERE id = ? "#, ) - .bind(id) - .fetch_optional(&self.pool) - .await? - .ok_or_else(|| anyhow::anyhow!("Session not found"))?; + .bind(id) + .fetch_optional(&self.pool) + .await? + .ok_or_else(|| anyhow::anyhow!("Session not found"))?; if include_messages { let conv = self.get_conversation(&session.id).await?; @@ -773,6 +857,7 @@ impl SessionStorage { add_update!(builder.name, "name"); add_update!(builder.user_set_name, "user_set_name"); + add_update!(builder.session_type, "session_type"); add_update!(builder.working_dir, "working_dir"); add_update!(builder.extension_data, "extension_data"); add_update!(builder.total_tokens, "total_tokens"); @@ -803,6 +888,9 @@ impl SessionStorage { if let Some(user_set_name) = builder.user_set_name { q = q.bind(user_set_name); } + if let Some(session_type) = builder.session_type { + q = q.bind(session_type.to_string()); + } if let Some(wd) = builder.working_dir { q = q.bind(wd.to_string_lossy().to_string()); } @@ -872,7 +960,6 @@ impl SessionStorage { let mut message = Message::new(role, created_timestamp, content); message.metadata = metadata; - // TODO(Douwe): make id required message = message.with_id(format!("msg_{}_{}", session_id, idx)); messages.push(message); } @@ -942,20 +1029,21 @@ impl SessionStorage { async fn list_sessions(&self) -> Result> { sqlx::query_as::<_, Session>( r#" - SELECT s.id, s.working_dir, s.name, s.description, s.user_set_name, s.created_at, s.updated_at, s.extension_data, + SELECT s.id, s.working_dir, s.name, s.description, s.user_set_name, s.session_type, s.created_at, s.updated_at, s.extension_data, s.total_tokens, s.input_tokens, s.output_tokens, s.accumulated_total_tokens, s.accumulated_input_tokens, s.accumulated_output_tokens, s.schedule_id, s.recipe_json, s.user_recipe_values_json, COUNT(m.id) as message_count FROM sessions s INNER JOIN messages m ON s.id = m.session_id + WHERE s.session_type = 'user' OR s.session_type = 'scheduled' GROUP BY s.id ORDER BY s.updated_at DESC "#, ) - .fetch_all(&self.pool) - .await - .map_err(Into::into) + .fetch_all(&self.pool) + .await + .map_err(Into::into) } async fn delete_session(&self, session_id: &str) -> Result<()> { @@ -1008,7 +1096,11 @@ impl SessionStorage { let import: Session = serde_json::from_str(json)?; let session = self - .create_session(import.working_dir.clone(), import.name.clone()) + .create_session( + import.working_dir.clone(), + import.name.clone(), + import.session_type, + ) .await?; let mut builder = SessionUpdateBuilder::new(session.id.clone()) @@ -1084,7 +1176,7 @@ mod tests { let description = format!("Test session {}", i); let session = session_storage - .create_session(working_dir.clone(), description) + .create_session(working_dir.clone(), description, SessionType::User) .await .unwrap(); @@ -1176,7 +1268,11 @@ mod tests { let storage = Arc::new(SessionStorage::create(&db_path).await.unwrap()); let original = storage - .create_session(PathBuf::from("/tmp/test"), DESCRIPTION.to_string()) + .create_session( + PathBuf::from("/tmp/test"), + DESCRIPTION.to_string(), + SessionType::User, + ) .await .unwrap(); diff --git a/crates/goose/tests/agent.rs b/crates/goose/tests/agent.rs index 77e7359f6987..7478119027fa 100644 --- a/crates/goose/tests/agent.rs +++ b/crates/goose/tests/agent.rs @@ -4,1423 +4,497 @@ use anyhow::Result; use futures::StreamExt; use goose::agents::{Agent, AgentEvent}; use goose::config::extensions::{set_extension, ExtensionEntry}; -use goose::conversation::message::Message; -use goose::conversation::Conversation; -use goose::model::ModelConfig; -use goose::providers::base::Provider; -use goose::providers::{ - anthropic::AnthropicProvider, azure::AzureProvider, bedrock::BedrockProvider, - databricks::DatabricksProvider, gcpvertexai::GcpVertexAIProvider, google::GoogleProvider, - ollama::OllamaProvider, openai::OpenAiProvider, openrouter::OpenRouterProvider, - xai::XaiProvider, -}; - -#[derive(Debug, PartialEq)] -enum ProviderType { - Azure, - OpenAi, - #[allow(dead_code)] - Anthropic, - Bedrock, - Databricks, - GcpVertexAI, - Google, - Ollama, - OpenRouter, - Xai, -} -impl ProviderType { - fn required_env(&self) -> &'static [&'static str] { - match self { - ProviderType::Azure => &[ - "AZURE_OPENAI_API_KEY", - "AZURE_OPENAI_ENDPOINT", - "AZURE_OPENAI_DEPLOYMENT_NAME", - ], - ProviderType::OpenAi => &["OPENAI_API_KEY"], - ProviderType::Anthropic => &["ANTHROPIC_API_KEY"], - ProviderType::Bedrock => &["AWS_PROFILE"], - ProviderType::Databricks => &["DATABRICKS_HOST"], - ProviderType::Google => &["GOOGLE_API_KEY"], - ProviderType::Ollama => &[], - ProviderType::OpenRouter => &["OPENROUTER_API_KEY"], - ProviderType::GcpVertexAI => &["GCP_PROJECT_ID", "GCP_LOCATION"], - ProviderType::Xai => &["XAI_API_KEY"], +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(test)] + mod schedule_tool_tests { + use super::*; + use async_trait::async_trait; + use chrono::{DateTime, Utc}; + use goose::agents::platform_tools::PLATFORM_MANAGE_SCHEDULE_TOOL_NAME; + use goose::scheduler::{ScheduledJob, SchedulerError}; + use goose::scheduler_trait::SchedulerTrait; + use goose::session::Session; + use std::sync::Arc; + + struct MockScheduler { + jobs: tokio::sync::Mutex>, } - } - fn pre_check(&self) -> Result<()> { - match self { - ProviderType::Ollama => { - // Check if the `ollama ls` CLI command works - use std::process::Command; - let output = Command::new("ollama").arg("ls").output(); - if let Ok(output) = output { - if output.status.success() { - return Ok(()); // CLI is running - } + impl MockScheduler { + fn new() -> Self { + Self { + jobs: tokio::sync::Mutex::new(Vec::new()), } - println!("Skipping Ollama tests - `ollama ls` command not found or failed"); - Err(anyhow::anyhow!("Ollama CLI is not running")) } - _ => Ok(()), // Other providers don't need special pre-checks } - } - async fn create_provider(&self, model_config: ModelConfig) -> Result> { - Ok(match self { - ProviderType::Azure => Arc::new(AzureProvider::from_env(model_config).await?), - ProviderType::OpenAi => Arc::new(OpenAiProvider::from_env(model_config).await?), - ProviderType::Anthropic => Arc::new(AnthropicProvider::from_env(model_config).await?), - ProviderType::Bedrock => Arc::new(BedrockProvider::from_env(model_config).await?), - ProviderType::Databricks => Arc::new(DatabricksProvider::from_env(model_config).await?), - ProviderType::GcpVertexAI => { - Arc::new(GcpVertexAIProvider::from_env(model_config).await?) + #[async_trait] + impl SchedulerTrait for MockScheduler { + async fn add_scheduled_job(&self, job: ScheduledJob) -> Result<(), SchedulerError> { + let mut jobs = self.jobs.lock().await; + jobs.push(job); + Ok(()) } - ProviderType::Google => Arc::new(GoogleProvider::from_env(model_config).await?), - ProviderType::Ollama => Arc::new(OllamaProvider::from_env(model_config).await?), - ProviderType::OpenRouter => Arc::new(OpenRouterProvider::from_env(model_config).await?), - ProviderType::Xai => Arc::new(XaiProvider::from_env(model_config).await?), - }) - } -} -pub fn check_required_env_vars(required_vars: &[&str]) -> Result<()> { - let missing_vars: Vec<&str> = required_vars - .iter() - .filter(|&&var| std::env::var(var).is_err()) - .cloned() - .collect(); - - if !missing_vars.is_empty() { - println!( - "Skipping tests. Missing environment variables: {:?}", - missing_vars - ); - return Err(anyhow::anyhow!("Required environment variables not set")); - } - Ok(()) -} + async fn list_scheduled_jobs(&self) -> Result, SchedulerError> { + let jobs = self.jobs.lock().await; + Ok(jobs.clone()) + } -async fn run_truncate_test( - provider_type: ProviderType, - model: &str, - context_window: usize, -) -> Result<()> { - let model_config = ModelConfig::new(model) - .unwrap() - .with_context_limit(Some(context_window)) - .with_temperature(Some(0.0)); - let provider = provider_type.create_provider(model_config).await?; - - let agent = Agent::new(); - agent.update_provider(provider).await?; - let repeat_count = context_window + 10_000; - let large_message_content = "hello ".repeat(repeat_count); - let conversation = Conversation::new(vec![ - Message::user().with_text("hi there. what is 2 + 2?"), - Message::assistant().with_text("hey! I think it's 4."), - Message::user().with_text(&large_message_content), - Message::assistant().with_text("heyy!!"), - Message::user().with_text("what's the meaning of life?"), - Message::assistant().with_text("the meaning of life is 42"), - Message::user().with_text( - "did I ask you what's 2+2 in this message history? just respond with 'yes' or 'no'", - ), - ]) - .unwrap(); - - let reply_stream = agent.reply(conversation, None, None).await?; - tokio::pin!(reply_stream); - - let mut responses = Vec::new(); - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(response)) => responses.push(response), - Ok(AgentEvent::McpNotification(n)) => { - println!("MCP Notification: {n:?}"); + async fn remove_scheduled_job(&self, id: &str) -> Result<(), SchedulerError> { + let mut jobs = self.jobs.lock().await; + if let Some(pos) = jobs.iter().position(|job| job.id == id) { + jobs.remove(pos); + Ok(()) + } else { + Err(SchedulerError::JobNotFound(id.to_string())) + } } - Ok(AgentEvent::ModelChange { .. }) => { - // Model change events are informational, just continue + + async fn pause_schedule(&self, _id: &str) -> Result<(), SchedulerError> { + Ok(()) } - Ok(AgentEvent::HistoryReplaced(_updated_conversation)) => { - // Should update the conversation here, but we're not reading it + + async fn unpause_schedule(&self, _id: &str) -> Result<(), SchedulerError> { + Ok(()) } - Err(e) => { - println!("Error: {:?}", e); - return Err(e); + + async fn run_now(&self, _id: &str) -> Result { + Ok("test_session_123".to_string()) } - } - } - println!("Responses: {responses:?}\n"); - - // Ollama and OpenRouter truncate by default even when the context window is exceeded - // We don't have control over the truncation behavior in these providers. - // Skip the strict assertions for these providers. - if provider_type == ProviderType::Ollama || provider_type == ProviderType::OpenRouter { - println!( - "WARNING: Skipping test for {:?} because it truncates by default when the context window is exceeded", - provider_type - ); - return Ok(()); - } + async fn sessions( + &self, + _sched_id: &str, + _limit: usize, + ) -> Result, SchedulerError> { + Ok(vec![]) + } - assert_eq!(responses.len(), 1); + async fn update_schedule( + &self, + _sched_id: &str, + _new_cron: String, + ) -> Result<(), SchedulerError> { + Ok(()) + } - assert_eq!(responses[0].content.len(), 1); + async fn kill_running_job(&self, _sched_id: &str) -> Result<(), SchedulerError> { + Ok(()) + } - match responses[0].content[0] { - goose::conversation::message::MessageContent::Text(ref text_content) => { - assert!(text_content.text.to_lowercase().contains("no")); - assert!(!text_content.text.to_lowercase().contains("yes")); - } - _ => { - panic!( - "Unexpected message content type: {:?}", - responses[0].content[0] - ); + async fn get_running_job_info( + &self, + _sched_id: &str, + ) -> Result)>, SchedulerError> { + Ok(None) + } } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - #[derive(Debug)] - struct TestConfig { - provider_type: ProviderType, - model: &'static str, - context_window: usize, - } - - async fn run_test_with_config(config: TestConfig) -> Result<()> { - println!("Starting test for {config:?}"); - - // Check for required environment variables - if check_required_env_vars(config.provider_type.required_env()).is_err() { - return Ok(()); // Skip test if env vars are missing + #[tokio::test] + async fn test_schedule_management_tool_list() { + let agent = Agent::new(); + let mock_scheduler = Arc::new(MockScheduler::new()); + agent.set_scheduler(mock_scheduler.clone()).await; + + // Test that the schedule management tool is available in the tools list + let tools = agent.list_tools(None).await; + let schedule_tool = tools + .iter() + .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); + assert!(schedule_tool.is_some()); + + let tool = schedule_tool.unwrap(); + assert!(tool + .description + .clone() + .unwrap_or_default() + .contains("Manage scheduled recipe execution")); + } + + #[tokio::test] + async fn test_schedule_management_tool_no_scheduler() { + let agent = Agent::new(); + // Don't set scheduler - test that the tool still appears in the list + // but would fail if actually called (which we can't test directly through public API) + + let tools = agent.list_tools(None).await; + let schedule_tool = tools + .iter() + .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); + assert!(schedule_tool.is_some()); + } + + #[tokio::test] + async fn test_schedule_management_tool_in_platform_tools() { + let agent = Agent::new(); + let tools = agent.list_tools(Some("platform".to_string())).await; + + // Check that the schedule management tool is included in platform tools + let schedule_tool = tools + .iter() + .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); + assert!(schedule_tool.is_some()); + + let tool = schedule_tool.unwrap(); + assert!(tool + .description + .clone() + .unwrap_or_default() + .contains("Manage scheduled recipe execution")); + + // Verify the tool has the expected actions in its schema + if let Some(properties) = tool.input_schema.get("properties") { + if let Some(action_prop) = properties.get("action") { + if let Some(enum_values) = action_prop.get("enum") { + let actions: Vec = enum_values + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect(); + + // Check that our session_content action is included + assert!(actions.contains(&"session_content".to_string())); + assert!(actions.contains(&"list".to_string())); + assert!(actions.contains(&"create".to_string())); + assert!(actions.contains(&"sessions".to_string())); + } + } + } } - // Run provider-specific pre-checks - if config.provider_type.pre_check().is_err() { - return Ok(()); // Skip test if pre-check fails + #[tokio::test] + async fn test_schedule_management_tool_schema_validation() { + let agent = Agent::new(); + let tools = agent.list_tools(None).await; + let schedule_tool = tools + .iter() + .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); + assert!(schedule_tool.is_some()); + + let tool = schedule_tool.unwrap(); + + // Verify the tool schema has the session_id parameter for session_content action + if let Some(properties) = tool.input_schema.get("properties") { + assert!(properties.get("session_id").is_some()); + + if let Some(session_id_prop) = properties.get("session_id") { + assert_eq!( + session_id_prop.get("type").unwrap().as_str().unwrap(), + "string" + ); + assert!(session_id_prop + .get("description") + .unwrap() + .as_str() + .unwrap() + .contains("Session identifier for session_content action")); + } + } } - - // Run the truncate test - run_truncate_test(config.provider_type, config.model, config.context_window).await - } - - #[tokio::test] - async fn test_agent_with_openai() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::OpenAi, - model: "o3-mini-low", - context_window: 200_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_anthropic() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Anthropic, - model: "claude-sonnet-4", - context_window: 200_000, - }) - .await } - #[tokio::test] - async fn test_agent_with_azure() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Azure, - model: "gpt-4o-mini", - context_window: 128_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_bedrock() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Bedrock, - model: "anthropic.claude-sonnet-4-20250514:0", - context_window: 200_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_databricks() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Databricks, - model: "databricks-meta-llama-3-3-70b-instruct", - context_window: 128_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_databricks_bedrock() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Databricks, - model: "claude-sonnet-4", - context_window: 200_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_databricks_openai() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Databricks, - model: "gpt-4o-mini", - context_window: 128_000, - }) - .await - } - - #[tokio::test] - async fn test_agent_with_google() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Google, - model: "gemini-2.0-flash-exp", - context_window: 1_200_000, - }) - .await - } + #[cfg(test)] + mod retry_tests { + use super::*; + use goose::agents::types::{RetryConfig, SuccessCheck}; - #[tokio::test] - async fn test_agent_with_openrouter() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::OpenRouter, - model: "deepseek/deepseek-r1", - context_window: 130_000, - }) - .await - } + #[tokio::test] + async fn test_retry_success_check_execution() -> Result<()> { + use goose::agents::retry::execute_success_checks; - #[tokio::test] - async fn test_agent_with_ollama() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Ollama, - model: "llama3.2", - context_window: 128_000, - }) - .await - } + let retry_config = RetryConfig { + max_retries: 3, + checks: vec![], + on_failure: None, + timeout_seconds: Some(30), + on_failure_timeout_seconds: Some(60), + }; - #[tokio::test] - async fn test_agent_with_gcpvertexai() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::GcpVertexAI, - model: "claude-sonnet-4-20250514", - context_window: 200_000, - }) - .await - } + let success_checks = vec![SuccessCheck::Shell { + command: "echo 'test'".to_string(), + }]; - #[tokio::test] - async fn test_agent_with_xai() -> Result<()> { - run_test_with_config(TestConfig { - provider_type: ProviderType::Xai, - model: "grok-3", - context_window: 9_000, - }) - .await - } -} + let result = execute_success_checks(&success_checks, &retry_config).await; + assert!(result.is_ok(), "Success check should pass"); + assert!(result.unwrap(), "Command should succeed"); -#[cfg(test)] -mod schedule_tool_tests { - use super::*; - use async_trait::async_trait; - use chrono::{DateTime, Utc}; - use goose::agents::platform_tools::PLATFORM_MANAGE_SCHEDULE_TOOL_NAME; - use goose::scheduler::{ScheduledJob, SchedulerError}; - use goose::scheduler_trait::SchedulerTrait; - use goose::session::Session; - use std::sync::Arc; - - struct MockScheduler { - jobs: tokio::sync::Mutex>, - } + let fail_checks = vec![SuccessCheck::Shell { + command: "false".to_string(), + }]; - impl MockScheduler { - fn new() -> Self { - Self { - jobs: tokio::sync::Mutex::new(Vec::new()), - } - } - } + let result = execute_success_checks(&fail_checks, &retry_config).await; + assert!(result.is_ok(), "Success check execution should not error"); + assert!(!result.unwrap(), "Command should fail"); - #[async_trait] - impl SchedulerTrait for MockScheduler { - async fn add_scheduled_job(&self, job: ScheduledJob) -> Result<(), SchedulerError> { - let mut jobs = self.jobs.lock().await; - jobs.push(job); Ok(()) } - async fn list_scheduled_jobs(&self) -> Result, SchedulerError> { - let jobs = self.jobs.lock().await; - Ok(jobs.clone()) - } + #[tokio::test] + async fn test_retry_logic_with_validation_errors() -> Result<()> { + let invalid_retry_config = RetryConfig { + max_retries: 0, + checks: vec![], + on_failure: None, + timeout_seconds: Some(0), + on_failure_timeout_seconds: None, + }; - async fn remove_scheduled_job(&self, id: &str) -> Result<(), SchedulerError> { - let mut jobs = self.jobs.lock().await; - if let Some(pos) = jobs.iter().position(|job| job.id == id) { - jobs.remove(pos); - Ok(()) - } else { - Err(SchedulerError::JobNotFound(id.to_string())) - } - } + let validation_result = invalid_retry_config.validate(); + assert!( + validation_result.is_err(), + "Should validate max_retries > 0" + ); + assert!(validation_result + .unwrap_err() + .contains("max_retries must be greater than 0")); - async fn pause_schedule(&self, _id: &str) -> Result<(), SchedulerError> { Ok(()) } - async fn unpause_schedule(&self, _id: &str) -> Result<(), SchedulerError> { - Ok(()) - } + #[tokio::test] + async fn test_retry_attempts_counter_reset() -> Result<()> { + let agent = Agent::new(); - async fn run_now(&self, _id: &str) -> Result { - Ok("test_session_123".to_string()) - } + agent.reset_retry_attempts().await; + let initial_attempts = agent.get_retry_attempts().await; + assert_eq!(initial_attempts, 0); - async fn sessions( - &self, - _sched_id: &str, - _limit: usize, - ) -> Result, SchedulerError> { - Ok(vec![]) - } + let new_attempts = agent.increment_retry_attempts().await; + assert_eq!(new_attempts, 1); - async fn update_schedule( - &self, - _sched_id: &str, - _new_cron: String, - ) -> Result<(), SchedulerError> { - Ok(()) - } + agent.reset_retry_attempts().await; + let reset_attempts = agent.get_retry_attempts().await; + assert_eq!(reset_attempts, 0); - async fn kill_running_job(&self, _sched_id: &str) -> Result<(), SchedulerError> { Ok(()) } - - async fn get_running_job_info( - &self, - _sched_id: &str, - ) -> Result)>, SchedulerError> { - Ok(None) - } - } - - #[tokio::test] - async fn test_schedule_management_tool_list() { - let agent = Agent::new(); - let mock_scheduler = Arc::new(MockScheduler::new()); - agent.set_scheduler(mock_scheduler.clone()).await; - - // Test that the schedule management tool is available in the tools list - let tools = agent.list_tools(None).await; - let schedule_tool = tools - .iter() - .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); - assert!(schedule_tool.is_some()); - - let tool = schedule_tool.unwrap(); - assert!(tool - .description - .clone() - .unwrap_or_default() - .contains("Manage scheduled recipe execution")); - } - - #[tokio::test] - async fn test_schedule_management_tool_no_scheduler() { - let agent = Agent::new(); - // Don't set scheduler - test that the tool still appears in the list - // but would fail if actually called (which we can't test directly through public API) - - let tools = agent.list_tools(None).await; - let schedule_tool = tools - .iter() - .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); - assert!(schedule_tool.is_some()); - } - - #[tokio::test] - async fn test_schedule_management_tool_in_platform_tools() { - let agent = Agent::new(); - let tools = agent.list_tools(Some("platform".to_string())).await; - - // Check that the schedule management tool is included in platform tools - let schedule_tool = tools - .iter() - .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); - assert!(schedule_tool.is_some()); - - let tool = schedule_tool.unwrap(); - assert!(tool - .description - .clone() - .unwrap_or_default() - .contains("Manage scheduled recipe execution")); - - // Verify the tool has the expected actions in its schema - if let Some(properties) = tool.input_schema.get("properties") { - if let Some(action_prop) = properties.get("action") { - if let Some(enum_values) = action_prop.get("enum") { - let actions: Vec = enum_values - .as_array() - .unwrap() - .iter() - .map(|v| v.as_str().unwrap().to_string()) - .collect(); - - // Check that our session_content action is included - assert!(actions.contains(&"session_content".to_string())); - assert!(actions.contains(&"list".to_string())); - assert!(actions.contains(&"create".to_string())); - assert!(actions.contains(&"sessions".to_string())); - } - } - } - } - - #[tokio::test] - async fn test_schedule_management_tool_schema_validation() { - let agent = Agent::new(); - let tools = agent.list_tools(None).await; - let schedule_tool = tools - .iter() - .find(|tool| tool.name == PLATFORM_MANAGE_SCHEDULE_TOOL_NAME); - assert!(schedule_tool.is_some()); - - let tool = schedule_tool.unwrap(); - - // Verify the tool schema has the session_id parameter for session_content action - if let Some(properties) = tool.input_schema.get("properties") { - assert!(properties.get("session_id").is_some()); - - if let Some(session_id_prop) = properties.get("session_id") { - assert_eq!( - session_id_prop.get("type").unwrap().as_str().unwrap(), - "string" - ); - assert!(session_id_prop - .get("description") - .unwrap() - .as_str() - .unwrap() - .contains("Session identifier for session_content action")); - } - } } -} -#[cfg(test)] -mod final_output_tool_tests { - use super::*; - use futures::stream; - use goose::agents::final_output_tool::FINAL_OUTPUT_TOOL_NAME; - use goose::conversation::Conversation; - use goose::providers::base::MessageStream; - use goose::recipe::Response; - use rmcp::model::CallToolRequestParam; - use rmcp::object; - - #[tokio::test] - async fn test_final_output_assistant_message_in_reply() -> Result<()> { + #[cfg(test)] + mod max_turns_tests { + use super::*; use async_trait::async_trait; - use goose::conversation::message::Message; + use goose::agents::SessionConfig; + use goose::conversation::message::{Message, MessageContent}; use goose::model::ModelConfig; - use goose::providers::base::{Provider, ProviderUsage, Usage}; + use goose::providers::base::{Provider, ProviderMetadata, ProviderUsage, Usage}; use goose::providers::errors::ProviderError; - use rmcp::model::Tool; - - #[derive(Clone)] - struct MockProvider { - model_config: ModelConfig, - } - - #[async_trait] - impl Provider for MockProvider { - fn metadata() -> goose::providers::base::ProviderMetadata { - goose::providers::base::ProviderMetadata::empty() - } - - fn get_name(&self) -> &str { - "mock-test" - } - - fn get_model_config(&self) -> ModelConfig { - self.model_config.clone() - } - - async fn complete( - &self, - _system: &str, - _messages: &[Message], - _tools: &[Tool], - ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - Ok(( - Message::assistant().with_text("Task completed."), - ProviderUsage::new("mock".to_string(), Usage::default()), - )) - } - - async fn complete_with_model( - &self, - _model_config: &ModelConfig, - system: &str, - messages: &[Message], - tools: &[Tool], - ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - self.complete(system, messages, tools).await - } - } - - let agent = Agent::new(); + use goose::session::session_manager::SessionType; + use goose::session::SessionManager; + use rmcp::model::{CallToolRequestParam, Tool}; + use rmcp::object; + use std::path::PathBuf; - let model_config = ModelConfig::new("test-model").unwrap(); - let mock_provider = Arc::new(MockProvider { model_config }); - agent.update_provider(mock_provider).await?; + struct MockToolProvider {} - let response = Response { - json_schema: Some(serde_json::json!({ - "type": "object", - "properties": { - "result": {"type": "string"} - }, - "required": ["result"] - })), - }; - agent.add_final_output_tool(response).await; - - // Simulate a final output tool call occurring. - let tool_call = CallToolRequestParam { - name: FINAL_OUTPUT_TOOL_NAME.into(), - arguments: Some(object!({ - "result": "Test output" - })), - }; - - let (_, result) = agent - .dispatch_tool_call(tool_call, "request_id".to_string(), None, None) - .await; - - assert!(result.is_ok(), "Tool call should succeed"); - let final_result = result.unwrap().result.await; - assert!(final_result.is_ok(), "Tool execution should succeed"); - - let content = final_result.unwrap(); - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("Final output successfully collected."), - "Tool result missing expected content: {}", - text.text - ); - - // Simulate the reply stream continuing after the final output tool call. - let reply_stream = agent.reply(Conversation::empty(), None, None).await?; - tokio::pin!(reply_stream); - - let mut responses = Vec::new(); - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(response)) => responses.push(response), - Ok(_) => {} - Err(e) => return Err(e), + impl MockToolProvider { + fn new() -> Self { + Self {} } } - assert!(!responses.is_empty(), "Should have received responses"); - let last_message = responses.last().unwrap(); - - // Check that the last message is an assistant message with our final output - assert_eq!(last_message.role, rmcp::model::Role::Assistant); - let message_text = last_message.as_concat_text(); - assert_eq!(message_text, r#"{"result":"Test output"}"#); - - Ok(()) - } - - #[tokio::test] - async fn test_when_final_output_not_called_in_reply() -> Result<()> { - use async_trait::async_trait; - use goose::agents::final_output_tool::FINAL_OUTPUT_CONTINUATION_MESSAGE; - use goose::conversation::message::Message; - use goose::model::ModelConfig; - use goose::providers::base::{Provider, ProviderUsage}; - use goose::providers::errors::ProviderError; - use rmcp::model::Tool; - - #[derive(Clone)] - struct MockProvider { - model_config: ModelConfig, - stream_round: std::sync::Arc>, - got_continuation_message: std::sync::Arc>, - } - #[async_trait] - impl Provider for MockProvider { - fn metadata() -> goose::providers::base::ProviderMetadata { - goose::providers::base::ProviderMetadata::empty() - } - - fn get_name(&self) -> &str { - "mock-test" - } - - fn get_model_config(&self) -> ModelConfig { - self.model_config.clone() - } - - fn supports_streaming(&self) -> bool { - true - } - - async fn stream( + impl Provider for MockToolProvider { + async fn complete( &self, - _system: &str, + _system_prompt: &str, _messages: &[Message], _tools: &[Tool], - ) -> Result { - if let Some(last_msg) = _messages.last() { - for content in &last_msg.content { - if let goose::conversation::message::MessageContent::Text(text_content) = - content - { - if text_content.text == FINAL_OUTPUT_CONTINUATION_MESSAGE { - let mut got_continuation = - self.got_continuation_message.lock().unwrap(); - *got_continuation = true; - } - } - } - } - - let mut round = self.stream_round.lock().unwrap(); - *round += 1; - - let deltas = if *round == 1 { - vec![ - Ok((Some(Message::assistant().with_text("Hello")), None)), - Ok((Some(Message::assistant().with_text("Hi!")), None)), - Ok(( - Some(Message::assistant().with_text("What is the final output?")), - None, - )), - ] - } else { - vec![Ok(( - Some(Message::assistant().with_text("Additional random delta")), - None, - ))] + ) -> Result<(Message, ProviderUsage), ProviderError> { + let tool_call = CallToolRequestParam { + name: "test_tool".into(), + arguments: Some(object!({"param": "value"})), }; + let message = Message::assistant().with_tool_request("call_123", Ok(tool_call)); - let stream = stream::iter(deltas.into_iter()); - Ok(Box::pin(stream)) - } + let usage = ProviderUsage::new( + "mock-model".to_string(), + Usage::new(Some(10), Some(5), Some(15)), + ); - async fn complete( - &self, - _system: &str, - _messages: &[Message], - _tools: &[Tool], - ) -> Result<(Message, ProviderUsage), ProviderError> { - Err(ProviderError::NotImplemented("Not implemented".to_string())) + Ok((message, usage)) } async fn complete_with_model( &self, _model_config: &ModelConfig, - system: &str, + system_prompt: &str, messages: &[Message], tools: &[Tool], ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - self.complete(system, messages, tools).await + self.complete(system_prompt, messages, tools).await } - } - let agent = Agent::new(); - - let model_config = ModelConfig::new("test-model").unwrap(); - let mock_provider = Arc::new(MockProvider { - model_config, - stream_round: std::sync::Arc::new(std::sync::Mutex::new(0)), - got_continuation_message: std::sync::Arc::new(std::sync::Mutex::new(false)), - }); - let mock_provider_clone = mock_provider.clone(); - agent.update_provider(mock_provider).await?; - - let response = Response { - json_schema: Some(serde_json::json!({ - "type": "object", - "properties": { - "result": {"type": "string"} - }, - "required": ["result"] - })), - }; - agent.add_final_output_tool(response).await; - - // Simulate the reply stream being called. - let reply_stream = agent.reply(Conversation::empty(), None, None).await?; - tokio::pin!(reply_stream); - - let mut responses = Vec::new(); - let mut count = 0; - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(response)) => { - responses.push(response); - count += 1; - if count >= 4 { - // Limit to 4 messages to avoid infinite loop due to mock provider - break; - } - } - Ok(_) => {} - Err(e) => return Err(e), + fn get_model_config(&self) -> ModelConfig { + ModelConfig::new("mock-model").unwrap() } - } - - assert!(!responses.is_empty(), "Should have received responses"); - let last_message = responses.last().unwrap(); - - // Check that the first 3 messages do not have FINAL_OUTPUT_CONTINUATION_MESSAGE - for (i, response) in responses.iter().take(3).enumerate() { - let message_text = response.as_concat_text(); - assert_ne!( - message_text, - FINAL_OUTPUT_CONTINUATION_MESSAGE, - "Message {} should not be the continuation message, got: '{}'", - i + 1, - message_text - ); - } - - // Check that the last message after the llm stream is the message directing the agent to continue - assert_eq!(last_message.role, rmcp::model::Role::User); - let message_text = last_message.as_concat_text(); - assert_eq!(message_text, FINAL_OUTPUT_CONTINUATION_MESSAGE); - // Continue streaming to consume any remaining content, this lets us verify the provider saw the continuation message - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(_response)) => { - break; // Stop after receiving the next message - } - Ok(_) => {} - Err(e) => { - println!("Error while streaming remaining content: {:?}", e); - break; + fn metadata() -> ProviderMetadata { + ProviderMetadata { + name: "mock".to_string(), + display_name: "Mock Provider".to_string(), + description: "Mock provider for testing".to_string(), + default_model: "mock-model".to_string(), + known_models: vec![], + model_doc_link: "".to_string(), + config_keys: vec![], } } - } - - // Assert that the provider received the continuation message - let got_continuation = mock_provider_clone.got_continuation_message.lock().unwrap(); - assert!( - *got_continuation, - "Provider should have received the FINAL_OUTPUT_CONTINUATION_MESSAGE" - ); - - Ok(()) - } -} - -#[cfg(test)] -mod retry_tests { - use super::*; - use async_trait::async_trait; - use goose::agents::types::{RetryConfig, SuccessCheck}; - use goose::conversation::message::Message; - use goose::conversation::Conversation; - use goose::model::ModelConfig; - use goose::providers::base::{Provider, ProviderUsage, Usage}; - use goose::providers::errors::ProviderError; - use rmcp::model::Tool; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::Arc; - - #[derive(Clone)] - struct MockRetryProvider { - model_config: ModelConfig, - call_count: Arc, - fail_until: usize, - } - - #[async_trait] - impl Provider for MockRetryProvider { - fn metadata() -> goose::providers::base::ProviderMetadata { - goose::providers::base::ProviderMetadata::empty() - } - - fn get_name(&self) -> &str { - "mock-test" - } - - fn get_model_config(&self) -> ModelConfig { - self.model_config.clone() - } - - async fn complete( - &self, - _system: &str, - _messages: &[Message], - _tools: &[Tool], - ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - let count = self.call_count.fetch_add(1, Ordering::SeqCst); - - if count < self.fail_until { - Ok(( - Message::assistant().with_text("Task failed - will retry."), - ProviderUsage::new("mock".to_string(), Usage::default()), - )) - } else { - Ok(( - Message::assistant().with_text("Task completed successfully."), - ProviderUsage::new("mock".to_string(), Usage::default()), - )) - } - } - - async fn complete_with_model( - &self, - _model_config: &ModelConfig, - system: &str, - messages: &[Message], - tools: &[Tool], - ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - self.complete(system, messages, tools).await - } - } - #[tokio::test] - async fn test_retry_config_validation_integration() -> Result<()> { - let agent = Agent::new(); - - let model_config = ModelConfig::new("test-model").unwrap(); - let mock_provider = Arc::new(MockRetryProvider { - model_config, - call_count: Arc::new(AtomicUsize::new(0)), - fail_until: 0, - }); - agent.update_provider(mock_provider.clone()).await?; - - let retry_config = RetryConfig { - max_retries: 3, - checks: vec![SuccessCheck::Shell { - command: "echo 'success check'".to_string(), - }], - on_failure: Some("echo 'cleanup executed'".to_string()), - timeout_seconds: Some(30), - on_failure_timeout_seconds: Some(60), - }; - - assert!( - retry_config.validate().is_ok(), - "Valid config should pass validation" - ); - - let conversation = - Conversation::new(vec![Message::user().with_text("Complete this task")]).unwrap(); - - let reply_stream = agent.reply(conversation, None, None).await?; - tokio::pin!(reply_stream); - - let mut responses = Vec::new(); - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(response)) => responses.push(response), - Ok(_) => {} - Err(e) => return Err(e), + fn get_name(&self) -> &str { + "mock-test" } } - assert!(!responses.is_empty(), "Should have received responses"); - - Ok(()) - } - - #[tokio::test] - async fn test_retry_success_check_execution() -> Result<()> { - use goose::agents::retry::execute_success_checks; - - let retry_config = RetryConfig { - max_retries: 3, - checks: vec![], - on_failure: None, - timeout_seconds: Some(30), - on_failure_timeout_seconds: Some(60), - }; - - let success_checks = vec![SuccessCheck::Shell { - command: "echo 'test'".to_string(), - }]; - - let result = execute_success_checks(&success_checks, &retry_config).await; - assert!(result.is_ok(), "Success check should pass"); - assert!(result.unwrap(), "Command should succeed"); - - let fail_checks = vec![SuccessCheck::Shell { - command: "false".to_string(), - }]; - - let result = execute_success_checks(&fail_checks, &retry_config).await; - assert!(result.is_ok(), "Success check execution should not error"); - assert!(!result.unwrap(), "Command should fail"); - - Ok(()) - } - - #[tokio::test] - async fn test_retry_logic_with_validation_errors() -> Result<()> { - let invalid_retry_config = RetryConfig { - max_retries: 0, - checks: vec![], - on_failure: None, - timeout_seconds: Some(0), - on_failure_timeout_seconds: None, - }; - - let validation_result = invalid_retry_config.validate(); - assert!( - validation_result.is_err(), - "Should validate max_retries > 0" - ); - assert!(validation_result - .unwrap_err() - .contains("max_retries must be greater than 0")); - - Ok(()) - } - - #[tokio::test] - async fn test_retry_attempts_counter_reset() -> Result<()> { - let agent = Agent::new(); - - agent.reset_retry_attempts().await; - let initial_attempts = agent.get_retry_attempts().await; - assert_eq!(initial_attempts, 0); - - let new_attempts = agent.increment_retry_attempts().await; - assert_eq!(new_attempts, 1); - - agent.reset_retry_attempts().await; - let reset_attempts = agent.get_retry_attempts().await; - assert_eq!(reset_attempts, 0); - - Ok(()) - } -} - -#[cfg(test)] -mod max_turns_tests { - use super::*; - use async_trait::async_trait; - use goose::conversation::message::{Message, MessageContent}; - use goose::conversation::Conversation; - use goose::model::ModelConfig; - use goose::providers::base::{Provider, ProviderMetadata, ProviderUsage, Usage}; - use goose::providers::errors::ProviderError; - use rmcp::model::{CallToolRequestParam, Tool}; - use rmcp::object; - - struct MockToolProvider {} - - impl MockToolProvider { - fn new() -> Self { - Self {} - } - } - - #[async_trait] - impl Provider for MockToolProvider { - async fn complete( - &self, - _system_prompt: &str, - _messages: &[Message], - _tools: &[Tool], - ) -> Result<(Message, ProviderUsage), ProviderError> { - let tool_call = CallToolRequestParam { - name: "test_tool".into(), - arguments: Some(object!({"param": "value"})), + #[tokio::test] + async fn test_max_turns_limit() -> Result<()> { + let agent = Agent::new(); + let provider = Arc::new(MockToolProvider::new()); + agent.update_provider(provider).await?; + let user_message = Message::user().with_text("Hello"); + + let session = SessionManager::create_session( + PathBuf::default(), + "max-turn-test".to_string(), + SessionType::Hidden, + ) + .await?; + let session_config = SessionConfig { + id: session.id, + schedule_id: None, + max_turns: None, + retry_config: None, }; - let message = Message::assistant().with_tool_request("call_123", Ok(tool_call)); - - let usage = ProviderUsage::new( - "mock-model".to_string(), - Usage::new(Some(10), Some(5), Some(15)), - ); - - Ok((message, usage)) - } - async fn complete_with_model( - &self, - _model_config: &ModelConfig, - system_prompt: &str, - messages: &[Message], - tools: &[Tool], - ) -> anyhow::Result<(Message, ProviderUsage), ProviderError> { - self.complete(system_prompt, messages, tools).await - } - - fn get_model_config(&self) -> ModelConfig { - ModelConfig::new("mock-model").unwrap() - } - - fn metadata() -> ProviderMetadata { - ProviderMetadata { - name: "mock".to_string(), - display_name: "Mock Provider".to_string(), - description: "Mock provider for testing".to_string(), - default_model: "mock-model".to_string(), - known_models: vec![], - model_doc_link: "".to_string(), - config_keys: vec![], - } - } + let reply_stream = agent.reply(user_message, session_config, None).await?; + tokio::pin!(reply_stream); - fn get_name(&self) -> &str { - "mock-test" - } - } - - #[tokio::test] - async fn test_max_turns_limit() -> Result<()> { - let agent = Agent::new(); - let provider = Arc::new(MockToolProvider::new()); - agent.update_provider(provider).await?; - // The mock provider will call a non-existent tool, which will fail and allow the loop to continue - let conversation = Conversation::new(vec![Message::user().with_text("Hello")]).unwrap(); - - let reply_stream = agent.reply(conversation, None, None).await?; - tokio::pin!(reply_stream); - - let mut responses = Vec::new(); - while let Some(response_result) = reply_stream.next().await { - match response_result { - Ok(AgentEvent::Message(response)) => { - if let Some(MessageContent::ToolConfirmationRequest(ref req)) = - response.content.first() - { - agent.handle_confirmation( + let mut responses = Vec::new(); + while let Some(response_result) = reply_stream.next().await { + match response_result { + Ok(AgentEvent::Message(response)) => { + if let Some(MessageContent::ToolConfirmationRequest(ref req)) = + response.content.first() + { + agent.handle_confirmation( req.id.clone(), goose::permission::PermissionConfirmation { principal_type: goose::permission::permission_confirmation::PrincipalType::Tool, permission: goose::permission::Permission::AllowOnce, } ).await; + } + responses.push(response); + } + Ok(AgentEvent::McpNotification(_)) => {} + Ok(AgentEvent::ModelChange { .. }) => {} + Ok(AgentEvent::HistoryReplaced(_updated_conversation)) => { + // We should update the conversation here, but we're not reading it + } + Err(e) => { + return Err(e); } - responses.push(response); - } - Ok(AgentEvent::McpNotification(_)) => {} - Ok(AgentEvent::ModelChange { .. }) => {} - Ok(AgentEvent::HistoryReplaced(_updated_conversation)) => { - // We should update the conversation here, but we're not reading it - } - Err(e) => { - return Err(e); } } - } - - assert!( - !responses.is_empty(), - "Expected at least 1 response, got {}", - responses.len() - ); - - // Look for the max turns message as the last response - let last_response = responses.last().unwrap(); - let last_content = last_response.content.first().unwrap(); - if let MessageContent::Text(text_content) = last_content { - assert!(text_content.text.contains( - "I've reached the maximum number of actions I can do without user input" - )); - } else { - panic!("Expected text content in last message"); - } - Ok(()) - } -} -#[cfg(test)] -mod extension_manager_tests { - use super::*; - use goose::agents::extension::{ExtensionConfig, PlatformExtensionContext}; - use goose::agents::extension_manager_extension::{ - MANAGE_EXTENSIONS_TOOL_NAME, SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME, - }; - use rmcp::model::CallToolRequestParam; - use rmcp::object; - - async fn setup_agent_with_extension_manager() -> Agent { - // Add the TODO extension to the config so it can be discovered by search_available_extensions - // Set it as disabled initially so tests can enable it - let todo_extension_entry = ExtensionEntry { - enabled: false, - config: ExtensionConfig::Platform { - name: "todo".to_string(), - description: - "Enable a todo list for Goose so it can keep track of what it is doing" - .to_string(), - bundled: Some(true), - available_tools: vec![], - }, - }; - set_extension(todo_extension_entry); - - let agent = Agent::new(); - - agent - .extension_manager - .set_context(PlatformExtensionContext { - session_id: Some("test_session".to_string()), - extension_manager: Some(Arc::downgrade(&agent.extension_manager)), - tool_route_manager: Some(Arc::downgrade(&agent.tool_route_manager)), - }) - .await; - - // Now add the extension manager platform extension - let ext_config = ExtensionConfig::Platform { - name: "extensionmanager".to_string(), - description: "Extension Manager".to_string(), - bundled: Some(true), - available_tools: vec![], - }; - - agent - .add_extension(ext_config) - .await - .expect("Failed to add extension manager"); - agent - } - - #[tokio::test] - async fn test_extension_manager_tools_available() { - let agent = setup_agent_with_extension_manager().await; - let tools = agent.list_tools(None).await; - - // Note: Tool names are prefixed with the normalized extension name "extensionmanager" - // not the display name "Extension Manager" - let search_tool = tools.iter().find(|tool| { - tool.name == format!("extensionmanager__{SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME}") - }); - assert!( - search_tool.is_some(), - "search_available_extensions tool should be available" - ); - - let manage_tool = tools - .iter() - .find(|tool| tool.name == format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}")); - assert!( - manage_tool.is_some(), - "manage_extensions tool should be available" - ); - } - - #[tokio::test] - async fn test_search_available_extensions_tool_call() { - let agent = setup_agent_with_extension_manager().await; - - let tool_call = CallToolRequestParam { - name: format!("extensionmanager__{SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({})), - }; - - let (_, result) = agent - .dispatch_tool_call(tool_call, "request_1".to_string(), None, None) - .await; - - assert!(result.is_ok(), "search_available_extensions should succeed"); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "search_available_extensions execution should succeed" - ); - - let content = call_result.unwrap(); - assert!(!content.is_empty(), "Should return some content"); - - // Verify the content contains expected text - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("Extensions available to enable:"), - "Content should contain 'Extensions available to enable:'" - ); - } - - #[tokio::test] - async fn test_manage_extensions_enable_disable_success() { - let agent = setup_agent_with_extension_manager().await; - - let enable_call = CallToolRequestParam { - name: format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({ - "action": "enable", - "extension_name": "todo" - })), - }; - let (_, result) = agent - .dispatch_tool_call(enable_call, "request_3a".to_string(), None, None) - .await; - assert!(result.is_ok()); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "manage_extensions enable execution should succeed" - ); - - let content = call_result.unwrap(); - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("todo") && text.text.contains("installed successfully"), - "Response should indicate success, got: {}", - text.text - ); - - // Now disable it - let disable_call = CallToolRequestParam { - name: format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({ - "action": "disable", - "extension_name": "todo" - })), - }; - - let (_, result) = agent - .dispatch_tool_call(disable_call, "request_3b".to_string(), None, None) - .await; - - assert!(result.is_ok(), "manage_extensions disable should succeed"); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "manage_extensions disable execution should succeed" - ); - - let content = call_result.unwrap(); - assert!(!content.is_empty(), "Should return confirmation message"); - - // Verify the message indicates success - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("successfully") || text.text.contains("disabled"), - "Response should indicate success, got: {}", - text.text - ); - } - - #[tokio::test] - async fn test_manage_extensions_missing_parameters() { - let agent = setup_agent_with_extension_manager().await; - - // Call manage_extensions without action parameter - let tool_call = CallToolRequestParam { - name: format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({ - "extension_name": "todo" - })), - }; + assert!( + !responses.is_empty(), + "Expected at least 1 response, got {}", + responses.len() + ); - let (_, result) = agent - .dispatch_tool_call(tool_call, "request_4".to_string(), None, None) - .await; - - assert!(result.is_ok(), "Tool call should return a result"); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "Tool execution should return an error result" - ); - - let content = call_result.unwrap(); - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("action") || text.text.contains("parameter"), - "Error should mention missing action parameter" - ); + // Look for the max turns message as the last response + let last_response = responses.last().unwrap(); + let last_content = last_response.content.first().unwrap(); + if let MessageContent::Text(text_content) = last_content { + assert!(text_content.text.contains( + "I've reached the maximum number of actions I can do without user input" + )); + } else { + panic!("Expected text content in last message"); + } + Ok(()) + } } - #[tokio::test] - async fn test_manage_extensions_invalid_action() { - let agent = setup_agent_with_extension_manager().await; - - let tool_call = CallToolRequestParam { - name: format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({ - "action": "invalid_action", - "extension_name": "todo" - })), + #[cfg(test)] + mod extension_manager_tests { + use super::*; + use goose::agents::extension::{ExtensionConfig, PlatformExtensionContext}; + use goose::agents::extension_manager_extension::{ + MANAGE_EXTENSIONS_TOOL_NAME, SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME, }; - let (_, result) = agent - .dispatch_tool_call(tool_call, "request_6".to_string(), None, None) - .await; - - assert!(result.is_ok(), "Tool call should return a result"); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "Tool execution should return an error result" - ); - - let content = call_result.unwrap(); - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("Invalid action") - || text.text.contains("enable") - || text.text.contains("disable"), - "Error should mention invalid action, got: {}", - text.text - ); - } + async fn setup_agent_with_extension_manager() -> Agent { + // Add the TODO extension to the config so it can be discovered by search_available_extensions + // Set it as disabled initially so tests can enable it + let todo_extension_entry = ExtensionEntry { + enabled: false, + config: ExtensionConfig::Platform { + name: "todo".to_string(), + description: + "Enable a todo list for Goose so it can keep track of what it is doing" + .to_string(), + bundled: Some(true), + available_tools: vec![], + }, + }; + set_extension(todo_extension_entry); + + let agent = Agent::new(); + + agent + .extension_manager + .set_context(PlatformExtensionContext { + session_id: Some("test_session".to_string()), + extension_manager: Some(Arc::downgrade(&agent.extension_manager)), + tool_route_manager: Some(Arc::downgrade(&agent.tool_route_manager)), + }) + .await; + + // Now add the extension manager platform extension + let ext_config = ExtensionConfig::Platform { + name: "extensionmanager".to_string(), + description: "Extension Manager".to_string(), + bundled: Some(true), + available_tools: vec![], + }; - #[tokio::test] - async fn test_manage_extensions_extension_not_found() { - let agent = setup_agent_with_extension_manager().await; - - // Try to enable a non-existent extension - let tool_call = CallToolRequestParam { - name: format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}").into(), - arguments: Some(object!({ - "action": "enable", - "extension_name": "nonexistent_extension_12345" - })), - }; + agent + .add_extension(ext_config) + .await + .expect("Failed to add extension manager"); + agent + } + + #[tokio::test] + async fn test_extension_manager_tools_available() { + let agent = setup_agent_with_extension_manager().await; + let tools = agent.list_tools(None).await; + + // Note: Tool names are prefixed with the normalized extension name "extensionmanager" + // not the display name "Extension Manager" + let search_tool = tools.iter().find(|tool| { + tool.name == format!("extensionmanager__{SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME}") + }); + assert!( + search_tool.is_some(), + "search_available_extensions tool should be available" + ); - let (_, result) = agent - .dispatch_tool_call(tool_call, "request_7".to_string(), None, None) - .await; - - assert!(result.is_ok(), "Tool call should return a result"); - let call_result = result.unwrap().result.await; - assert!( - call_result.is_ok(), - "Tool execution should return an error result" - ); - - // Check that the error message indicates extension not found - let content = call_result.unwrap(); - let text = content.first().unwrap().as_text().unwrap(); - assert!( - text.text.contains("not found") || text.text.contains("Extension"), - "Error should mention extension not found, got: {}", - text.text - ); + let manage_tool = tools.iter().find(|tool| { + tool.name == format!("extensionmanager__{MANAGE_EXTENSIONS_TOOL_NAME}") + }); + assert!( + manage_tool.is_some(), + "manage_extensions tool should be available" + ); + } } } diff --git a/crates/goose/tests/private_tests.rs b/crates/goose/tests/private_tests.rs deleted file mode 100644 index 8ac97aa15048..000000000000 --- a/crates/goose/tests/private_tests.rs +++ /dev/null @@ -1,833 +0,0 @@ -#![cfg(test)] - -use rmcp::model::{CallToolRequestParam, ErrorCode}; -use rmcp::object; -use serde_json::json; - -use goose::agents::platform_tools::PLATFORM_MANAGE_SCHEDULE_TOOL_NAME; -mod test_support; -use test_support::{ - create_temp_recipe, create_test_session_metadata, MockBehavior, ScheduleToolTestBuilder, -}; - -// Test all actions of the scheduler platform tool -#[tokio::test] -async fn test_schedule_tool_list_action() { - // Create a test builder with existing jobs - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .with_existing_job("job2", "0 0 * * * *") - .await - .build() - .await; - - // Test list action - let arguments = json!({ - "action": "list" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content.text.contains("Scheduled Jobs:")); - assert!(text_content.text.contains("job1")); - assert!(text_content.text.contains("job2")); - } else { - panic!("Expected text content"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"list_scheduled_jobs".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_list_action_empty() { - // Create a test builder with no jobs - let (agent, scheduler) = ScheduleToolTestBuilder::new().build().await; - - // Test list action - let arguments = json!({ - "action": "list" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content.text.contains("Scheduled Jobs:")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"list_scheduled_jobs".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_list_action_error() { - // Create a test builder with a list error - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_scheduler_behavior( - "list_scheduled_jobs", - MockBehavior::InternalError("Database error".to_string()), - ) - .await - .build() - .await; - - // Test list action - let arguments = json!({ - "action": "list" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INTERNAL_ERROR); - assert!(err.message.contains("Failed to list jobs")); - assert!(err.message.contains("Database error")); - } else { - panic!("Expected ExecutionError"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"list_scheduled_jobs".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_create_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new().build().await; - - // Create a temporary recipe file - let temp_recipe = create_temp_recipe(true, "json"); - - // Test create action - let arguments = json!({ - "action": "create", - "recipe_path": temp_recipe.path.to_str().unwrap(), - "cron_expression": "*/5 * * * * *" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Successfully created scheduled job")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"add_scheduled_job".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_create_action_missing_params() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test create action with missing recipe_path - let arguments = json!({ - "action": "create", - "cron_expression": "*/5 * * * * *" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INVALID_PARAMS); - assert!(err.message.contains("Missing 'recipe_path' parameter")); - } else { - panic!("Expected ExecutionError"); - } - - // Test create action with missing cron_expression - let temp_recipe = create_temp_recipe(true, "json"); - let arguments = json!({ - "action": "create", - "recipe_path": temp_recipe.path.to_str().unwrap() - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INVALID_PARAMS); - assert!(err.message.contains("Missing 'cron_expression' parameter")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_create_action_nonexistent_recipe() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test create action with nonexistent recipe - let arguments = json!({ - "action": "create", - "recipe_path": "/nonexistent/recipe.json", - "cron_expression": "*/5 * * * * *" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INTERNAL_ERROR); - assert!(err.message.contains("Recipe file not found")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_create_action_invalid_recipe() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Create an invalid recipe file - let temp_recipe = create_temp_recipe(false, "json"); - - // Test create action with invalid recipe - let arguments = json!({ - "action": "create", - "recipe_path": temp_recipe.path.to_str().unwrap(), - "cron_expression": "*/5 * * * * *" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INTERNAL_ERROR); - assert!(err.message.contains("Invalid JSON recipe")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_create_action_scheduler_error() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_scheduler_behavior( - "add_scheduled_job", - MockBehavior::AlreadyExists("job1".to_string()), - ) - .await - .build() - .await; - - // Create a temporary recipe file - let temp_recipe = create_temp_recipe(true, "json"); - - // Test create action - let arguments = json!({ - "action": "create", - "recipe_path": temp_recipe.path.to_str().unwrap(), - "cron_expression": "*/5 * * * * *" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INTERNAL_ERROR); - assert!(err.message.contains("Failed to create job")); - assert!(err.message.contains("job1")); - } else { - panic!("Expected ExecutionError"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"add_scheduled_job".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_run_now_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test run_now action - let arguments = json!({ - "action": "run_now", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Successfully started job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"run_now".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_run_now_action_missing_job_id() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test run_now action with missing job_id - let arguments = json!({ - "action": "run_now" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert_eq!(err.code, ErrorCode::INVALID_PARAMS); - assert!(err.message.contains("Missing 'job_id' parameter")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_run_now_action_nonexistent_job() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_scheduler_behavior("run_now", MockBehavior::NotFound("nonexistent".to_string())) - .await - .build() - .await; - - // Test run_now action with nonexistent job - let arguments = json!({ - "action": "run_now", - "job_id": "nonexistent" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Failed to run job")); - assert!(err.message.contains("nonexistent")); - } else { - panic!("Expected ExecutionError"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"run_now".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_pause_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test pause action - let arguments = json!({ - "action": "pause", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content.text.contains("Successfully paused job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"pause_schedule".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_pause_action_missing_job_id() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test pause action with missing job_id - let arguments = json!({ - "action": "pause" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Missing 'job_id' parameter")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_pause_action_running_job() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_scheduler_behavior( - "pause_schedule", - MockBehavior::JobCurrentlyRunning("job1".to_string()), - ) - .await - .build() - .await; - - // Test pause action with a running job - let arguments = json!({ - "action": "pause", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Failed to pause job")); - assert!(err.message.contains("job1")); - } else { - panic!("Expected ExecutionError"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"pause_schedule".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_unpause_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test unpause action - let arguments = json!({ - "action": "unpause", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Successfully unpaused job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"unpause_schedule".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_delete_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test delete action - let arguments = json!({ - "action": "delete", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Successfully deleted job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"remove_scheduled_job".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_kill_action() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .with_running_job("job1") - .await - .build() - .await; - - // Test kill action - let arguments = json!({ - "action": "kill", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Successfully killed running job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"kill_running_job".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_kill_action_not_running() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test kill action with a job that's not running - let arguments = json!({ - "action": "kill", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Failed to kill job")); - } else { - panic!("Expected ExecutionError"); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"kill_running_job".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_inspect_action_running() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .with_running_job("job1") - .await - .build() - .await; - - // Test inspect action - let arguments = json!({ - "action": "inspect", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Job 'job1' is currently running")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"get_running_job_info".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_inspect_action_not_running() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test inspect action with a job that's not running - let arguments = json!({ - "action": "inspect", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("Job 'job1' is not currently running")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"get_running_job_info".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_sessions_action() { - // Create test session metadata - let sessions = vec![ - ( - "1234567890_session1".to_string(), - create_test_session_metadata(5, "/tmp"), - ), - ( - "0987654321_session2".to_string(), - create_test_session_metadata(10, "/home"), - ), - ]; - - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .with_sessions_data("job1", sessions) - .await - .build() - .await; - - // Test sessions action - let arguments = json!({ - "action": "sessions", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content.text.contains("Sessions for job 'job1'")); - assert!(text_content.text.contains("session1")); - assert!(text_content.text.contains("session2")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"sessions".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_sessions_action_with_limit() { - // Create test session metadata - let sessions = vec![ - ( - "1234567890_session1".to_string(), - create_test_session_metadata(5, "/tmp"), - ), - ( - "0987654321_session2".to_string(), - create_test_session_metadata(10, "/home"), - ), - ( - "5555555555_session3".to_string(), - create_test_session_metadata(15, "/usr"), - ), - ]; - - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .with_sessions_data("job1", sessions) - .await - .build() - .await; - - // Test sessions action with limit - let arguments = json!({ - "action": "sessions", - "job_id": "job1", - "limit": 2 - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"sessions".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_sessions_action_empty() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test sessions action with no sessions - let arguments = json!({ - "action": "sessions", - "job_id": "job1" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_ok()); - - let content = result.unwrap(); - assert_eq!(content.len(), 1); - if let Some(text_content) = content[0].as_text() { - assert!(text_content - .text - .contains("No sessions found for job 'job1'")); - } - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"sessions".to_string())); -} - -#[tokio::test] -async fn test_schedule_tool_session_content_action_missing_session_id() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test session_content action with missing session_id - let arguments = json!({ - "action": "session_content" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Missing 'session_id' parameter")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_unknown_action() { - let (agent, _) = ScheduleToolTestBuilder::new().build().await; - - // Test unknown action - let arguments = json!({ - "action": "unknown_action" - }); - - let result = agent - .handle_schedule_management(arguments, "test_req".to_string()) - .await; - assert!(result.is_err()); - - if let Err(err) = result { - assert!(err.message.contains("Unknown action")); - } else { - panic!("Expected ExecutionError"); - } -} - -#[tokio::test] -async fn test_schedule_tool_dispatch() { - let (agent, scheduler) = ScheduleToolTestBuilder::new() - .with_existing_job("job1", "*/5 * * * * *") - .await - .build() - .await; - - // Test that the tool is properly dispatched through dispatch_tool_call - let tool_call = CallToolRequestParam { - name: PLATFORM_MANAGE_SCHEDULE_TOOL_NAME.into(), - arguments: Some(object!({ - "action": "list" - })), - }; - - let (request_id, result) = agent - .dispatch_tool_call(tool_call, "test_dispatch".to_string(), None, None) - .await; - assert_eq!(request_id, "test_dispatch"); - assert!(result.is_ok()); - - let tool_result = result.unwrap(); - // The result should be a future that resolves to the tool output - let output = tool_result.result.await; - assert!(output.is_ok()); - - // Verify the scheduler was called - let calls = scheduler.get_calls().await; - assert!(calls.contains(&"list_scheduled_jobs".to_string())); -} diff --git a/crates/goose/tests/test_support.rs b/crates/goose/tests/test_support.rs index 6bba89e9198b..49dd89d885b7 100644 --- a/crates/goose/tests/test_support.rs +++ b/crates/goose/tests/test_support.rs @@ -345,7 +345,6 @@ impl ScheduleToolTestBuilder { paused: false, current_session_id: None, process_start_time: None, - execution_mode: Some("background".to_string()), }; { let mut jobs = self.scheduler.jobs.lock().await; @@ -397,5 +396,6 @@ pub fn create_test_session_metadata(message_count: usize, working_dir: &str) -> conversation: None, message_count, user_recipe_values: None, + session_type: Default::default(), } } diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index ea97a2c0b84c..d4478cbad647 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -4127,10 +4127,6 @@ "currently_running": { "type": "boolean" }, - "execution_mode": { - "type": "string", - "nullable": true - }, "id": { "type": "string" }, @@ -4226,6 +4222,9 @@ "type": "string", "nullable": true }, + "session_type": { + "$ref": "#/components/schemas/SessionType" + }, "total_tokens": { "type": "integer", "format": "int32", @@ -4344,6 +4343,15 @@ } } }, + "SessionType": { + "type": "string", + "enum": [ + "user", + "scheduled", + "sub_agent", + "hidden" + ] + }, "SessionsQuery": { "type": "object", "properties": { diff --git a/ui/desktop/package-lock.json b/ui/desktop/package-lock.json index 67ee1410849a..73f1474fb30a 100644 --- a/ui/desktop/package-lock.json +++ b/ui/desktop/package-lock.json @@ -328,6 +328,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -697,6 +698,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -743,6 +745,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -1182,6 +1185,7 @@ "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", @@ -2731,6 +2735,7 @@ "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/checkbox": "^3.0.1", "@inquirer/confirm": "^4.0.1", @@ -5960,8 +5965,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -6250,6 +6254,7 @@ "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -6291,6 +6296,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -6301,6 +6307,7 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6447,6 +6454,7 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -6848,6 +6856,7 @@ "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", @@ -7097,6 +7106,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7736,6 +7746,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -9071,8 +9082,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -9130,6 +9140,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", @@ -10145,6 +10156,7 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -10604,6 +10616,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -12819,6 +12832,7 @@ "integrity": "sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@asamuzakjp/dom-selector": "^6.7.2", "cssstyle": "^5.3.1", @@ -14043,7 +14057,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -14064,6 +14077,7 @@ "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", @@ -16438,6 +16452,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -16526,7 +16541,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -16542,7 +16556,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -16859,6 +16872,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -16868,6 +16882,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -16889,8 +16904,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-markdown": { "version": "10.1.0", @@ -17839,6 +17853,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -18832,7 +18847,8 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.15.tgz", "integrity": "sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -19451,6 +19467,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -19836,6 +19853,7 @@ "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -19949,6 +19967,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -20654,6 +20673,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 843822c14a53..6468fd3ee3cb 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -667,7 +667,6 @@ export type ScheduledJob = { cron: string; current_session_id?: string | null; currently_running?: boolean; - execution_mode?: string | null; id: string; last_run?: string | null; paused?: boolean; @@ -689,6 +688,7 @@ export type Session = { output_tokens?: number | null; recipe?: Recipe | null; schedule_id?: string | null; + session_type?: SessionType; total_tokens?: number | null; updated_at: string; user_recipe_values?: { @@ -725,6 +725,8 @@ export type SessionListResponse = { sessions: Array; }; +export type SessionType = 'user' | 'scheduled' | 'sub_agent' | 'hidden'; + export type SessionsQuery = { limit?: number; }; From 8e45e3b6ff5d1bcb78b79ab009c709c75288e700 Mon Sep 17 00:00:00 2001 From: Sheikh Limon Date: Tue, 4 Nov 2025 22:33:17 +0600 Subject: [PATCH 079/121] feat: add --output-format json flag to goose run command (#5525) Signed-off-by: sheikhlimon Signed-off-by: Sheikh Limon Signed-off-by: fbalicchia --- crates/goose-cli/src/cli.rs | 14 ++++ crates/goose-cli/src/commands/bench.rs | 1 + .../src/scenario_tests/scenario_runner.rs | 12 +++- crates/goose-cli/src/session/builder.rs | 50 +++++++++++++- crates/goose-cli/src/session/mod.rs | 65 +++++++++++++++++-- 5 files changed, 131 insertions(+), 11 deletions(-) diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index be1575cad804..efaad9e47f91 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -720,6 +720,16 @@ enum Command { )] additional_sub_recipes: Vec, + /// Output format (text, json) + #[arg( + long = "output-format", + value_name = "FORMAT", + help = "Output format (text, json)", + default_value = "text", + value_parser = clap::builder::PossibleValuesParser::new(["text", "json"]) + )] + output_format: String, + /// Provider to use for this run (overrides environment variable) #[arg( long = "provider", @@ -974,6 +984,7 @@ pub async fn cli() -> anyhow::Result<()> { sub_recipes: None, final_output_response: None, retry_config: None, + output_format: "text".to_string(), }) .await; @@ -1054,6 +1065,7 @@ pub async fn cli() -> anyhow::Result<()> { scheduled_job_id, quiet, additional_sub_recipes, + output_format, provider, model, }) => { @@ -1183,6 +1195,7 @@ pub async fn cli() -> anyhow::Result<()> { .as_ref() .and_then(|r| r.final_output_response.clone()), retry_config: recipe_info.as_ref().and_then(|r| r.retry_config.clone()), + output_format, }) .await; @@ -1366,6 +1379,7 @@ pub async fn cli() -> anyhow::Result<()> { sub_recipes: None, final_output_response: None, retry_config: None, + output_format: "text".to_string(), }) .await; session.interactive(None).await?; diff --git a/crates/goose-cli/src/commands/bench.rs b/crates/goose-cli/src/commands/bench.rs index da6af17a78fc..c0005fa5400c 100644 --- a/crates/goose-cli/src/commands/bench.rs +++ b/crates/goose-cli/src/commands/bench.rs @@ -55,6 +55,7 @@ pub async fn agent_generator( sub_recipes: None, final_output_response: None, retry_config: None, + output_format: "text".to_string(), }) .await; diff --git a/crates/goose-cli/src/scenario_tests/scenario_runner.rs b/crates/goose-cli/src/scenario_tests/scenario_runner.rs index df09e5ebcf2d..8d7474d4859c 100644 --- a/crates/goose-cli/src/scenario_tests/scenario_runner.rs +++ b/crates/goose-cli/src/scenario_tests/scenario_runner.rs @@ -225,7 +225,17 @@ where SessionType::Hidden, ) .await?; - let mut cli_session = CliSession::new(agent, session.id, false, None, None, None, None).await; + let mut cli_session = CliSession::new( + agent, + session.id, + false, + None, + None, + None, + None, + "text".to_string(), + ) + .await; let mut error = None; for message in &messages { diff --git a/crates/goose-cli/src/session/builder.rs b/crates/goose-cli/src/session/builder.rs index bc15cdbc5026..96321f4bce43 100644 --- a/crates/goose-cli/src/session/builder.rs +++ b/crates/goose-cli/src/session/builder.rs @@ -24,7 +24,7 @@ use tokio::task::JoinSet; /// /// This struct contains all the parameters needed to create a new session, /// including session identification, extension configuration, and debug settings. -#[derive(Default, Clone, Debug)] +#[derive(Clone, Debug)] pub struct SessionBuilderConfig { /// Session id, optional need to deduce from context pub session_id: Option, @@ -68,6 +68,39 @@ pub struct SessionBuilderConfig { pub final_output_response: Option, /// Retry configuration for automated validation and recovery pub retry_config: Option, + /// Output format (text, json) + pub output_format: String, +} + +/// Manual implementation of Default to ensure proper initialization of output_format +/// This struct requires explicit default value for output_format field +impl Default for SessionBuilderConfig { + fn default() -> Self { + SessionBuilderConfig { + session_id: None, + resume: false, + no_session: false, + extensions: Vec::new(), + remote_extensions: Vec::new(), + streamable_http_extensions: Vec::new(), + builtins: Vec::new(), + extensions_override: None, + additional_system_prompt: None, + settings: None, + provider: None, + model: None, + debug: false, + max_tool_repetitions: None, + max_turns: None, + scheduled_job_id: None, + interactive: false, + quiet: false, + sub_recipes: None, + final_output_response: None, + retry_config: None, + output_format: "text".to_string(), + } + } } /// Offers to help debug an extension failure by creating a minimal debugging session @@ -139,8 +172,17 @@ async fn offer_extension_debugging_help( SessionType::Hidden, ) .await?; - let mut debug_session = - CliSession::new(debug_agent, session.id, false, None, None, None, None).await; + let mut debug_session = CliSession::new( + debug_agent, + session.id, + false, + None, + None, + None, + None, + "text".to_string(), + ) + .await; // Process the debugging request println!("{}", style("Analyzing the extension failure...").yellow()); @@ -459,6 +501,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession { session_config.max_turns, edit_mode, session_config.retry_config.clone(), + session_config.output_format.clone(), ) .await; @@ -643,6 +686,7 @@ mod tests { sub_recipes: None, final_output_response: None, retry_config: None, + output_format: "text".to_string(), }; assert_eq!(config.extensions.len(), 1); diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index 94192f86b655..35f8999d01a2 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -41,6 +41,7 @@ use goose::config::paths::Paths; use goose::conversation::message::{Message, MessageContent}; use rand::{distributions::Alphanumeric, Rng}; use rustyline::EditMode; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; use std::path::PathBuf; @@ -50,6 +51,18 @@ use tokio; use tokio_util::sync::CancellationToken; use tracing::warn; +#[derive(Serialize, Deserialize, Debug)] +struct JsonOutput { + messages: Vec, + metadata: JsonMetadata, +} + +#[derive(Serialize, Deserialize, Debug)] +struct JsonMetadata { + total_tokens: Option, + status: String, +} + pub enum RunMode { Normal, Plan, @@ -66,6 +79,7 @@ pub struct CliSession { max_turns: Option, edit_mode: Option, retry_config: Option, + output_format: String, } // Cache structure for completion data @@ -120,6 +134,7 @@ pub async fn classify_planner_response( } impl CliSession { + #[allow(clippy::too_many_arguments)] pub async fn new( agent: Agent, session_id: String, @@ -128,6 +143,7 @@ impl CliSession { max_turns: Option, edit_mode: Option, retry_config: Option, + output_format: String, ) -> Self { let messages = SessionManager::get_session(&session_id, true) .await @@ -145,6 +161,7 @@ impl CliSession { max_turns, edit_mode, retry_config, + output_format, } } @@ -760,6 +777,9 @@ impl CliSession { ) -> Result<()> { let cancel_token_clone = cancel_token.clone(); + // Cache the output format check to avoid repeated string comparisons in the hot loop + let is_json_mode = self.output_format == "json"; + let session_config = SessionConfig { id: self.session_id.clone(), schedule_id: self.scheduled_job_id.clone(), @@ -891,11 +911,16 @@ impl CliSession { ); } } + self.messages.push(message.clone()); if interactive {output::hide_thinking()}; let _ = progress_bars.hide(); - output::render_message(&message, self.debug); + + // Don't render in JSON mode + if !is_json_mode { + output::render_message(&message, self.debug); + } } } Some(Ok(AgentEvent::McpNotification((_id, message)))) => { @@ -967,17 +992,21 @@ impl CliSession { // TODO: proper display for subagent notifications if interactive { let _ = progress_bars.hide(); - println!("{}", console::style(&formatted_message).green().dim()); - } else { + if !is_json_mode { + println!("{}", console::style(&formatted_message).green().dim()); + } + } else if !is_json_mode { progress_bars.log(&formatted_message); } } else if let Some(ref notification_type) = message_notification_type { if notification_type == TASK_EXECUTION_NOTIFICATION_TYPE { if interactive { let _ = progress_bars.hide(); - print!("{}", formatted_message); - std::io::stdout().flush().unwrap(); - } else { + if !is_json_mode { + print!("{}", formatted_message); + std::io::stdout().flush().unwrap(); + } + } else if !is_json_mode { print!("{}", formatted_message); std::io::stdout().flush().unwrap(); } @@ -1056,7 +1085,29 @@ impl CliSession { } } } - println!(); + + // Output JSON if requested + if is_json_mode { + let metadata = match SessionManager::get_session(&self.session_id, false).await { + Ok(session) => JsonMetadata { + total_tokens: session.total_tokens, + status: "completed".to_string(), + }, + Err(_) => JsonMetadata { + total_tokens: None, + status: "completed".to_string(), + }, + }; + + let json_output = JsonOutput { + messages: self.messages.messages().to_vec(), + metadata, + }; + + println!("{}", serde_json::to_string_pretty(&json_output)?); + } else { + println!(); + } Ok(()) } From 150fd325c03ff3b8cbbbd79c3c41e30483c976ee Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Tue, 4 Nov 2025 11:40:05 -0500 Subject: [PATCH 080/121] fix: unblock acp via databricks (#5562) Signed-off-by: fbalicchia --- crates/goose/src/providers/databricks.rs | 40 +++++++++++------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/crates/goose/src/providers/databricks.rs b/crates/goose/src/providers/databricks.rs index b36b07f1484e..414fd0dd4e40 100644 --- a/crates/goose/src/providers/databricks.rs +++ b/crates/goose/src/providers/databricks.rs @@ -152,28 +152,24 @@ impl DatabricksProvider { }; // Check if the default fast model exists in the workspace - let model_with_fast = tokio::task::block_in_place(|| { - tokio::runtime::Handle::current().block_on(async { - if let Ok(Some(models)) = provider.fetch_supported_models().await { - if models.contains(&DATABRICKS_DEFAULT_FAST_MODEL.to_string()) { - tracing::debug!( - "Found {} in Databricks workspace, setting as fast model", - DATABRICKS_DEFAULT_FAST_MODEL - ); - model.with_fast(DATABRICKS_DEFAULT_FAST_MODEL.to_string()) - } else { - tracing::debug!( - "{} not found in Databricks workspace, not setting fast model", - DATABRICKS_DEFAULT_FAST_MODEL - ); - model - } - } else { - tracing::debug!("Could not fetch Databricks models, not setting fast model"); - model - } - }) - }); + let model_with_fast = if let Ok(Some(models)) = provider.fetch_supported_models().await { + if models.contains(&DATABRICKS_DEFAULT_FAST_MODEL.to_string()) { + tracing::debug!( + "Found {} in Databricks workspace, setting as fast model", + DATABRICKS_DEFAULT_FAST_MODEL + ); + model.with_fast(DATABRICKS_DEFAULT_FAST_MODEL.to_string()) + } else { + tracing::debug!( + "{} not found in Databricks workspace, not setting fast model", + DATABRICKS_DEFAULT_FAST_MODEL + ); + model + } + } else { + tracing::debug!("Could not fetch Databricks models, not setting fast model"); + model + }; provider.model = model_with_fast; Ok(provider) From 20ef7924250fd61fc1f4a28e386be11a1c9daaaf Mon Sep 17 00:00:00 2001 From: Alex Holder Date: Tue, 4 Nov 2025 17:54:28 +0000 Subject: [PATCH 081/121] improvement: add useful error message when attempting to use unauthenticated cursor-agent (#5300) Signed-off-by: Alex Holder Signed-off-by: fbalicchia --- crates/goose/src/providers/cursor_agent.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/goose/src/providers/cursor_agent.rs b/crates/goose/src/providers/cursor_agent.rs index 31b185f3ddae..225d09e0265d 100644 --- a/crates/goose/src/providers/cursor_agent.rs +++ b/crates/goose/src/providers/cursor_agent.rs @@ -47,6 +47,17 @@ impl CursorAgentProvider { }) } + /// Get authentication status from cursor-agent + async fn get_authentication_status(&self) -> bool { + Command::new(&self.command) + .arg("status") + .output() + .await + .ok() + .map(|output| String::from_utf8_lossy(&output.stdout).contains("✓ Logged in as")) + .unwrap_or(false) + } + /// Search for cursor-agent executable in common installation locations fn find_cursor_agent_executable(command_name: &str) -> Option { let home = std::env::var("HOME").ok()?; @@ -319,6 +330,11 @@ impl CursorAgentProvider { })?; if !exit_status.success() { + if !self.get_authentication_status().await { + return Err(ProviderError::Authentication( + "You are not logged in to cursor-agent. Please run 'cursor-agent login' to authenticate first." + .to_string())); + } return Err(ProviderError::RequestFailed(format!( "Command failed with exit code: {:?}", exit_status.code() From c6d206435cbcdffd88f05feb87aed52607c199f1 Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Tue, 4 Nov 2025 11:59:00 -0600 Subject: [PATCH 082/121] fix: improve server error messages to include HTTP status code (#5532) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: fbalicchia --- crates/goose/src/providers/utils.rs | 53 ++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/crates/goose/src/providers/utils.rs b/crates/goose/src/providers/utils.rs index 777750415531..c227b4ddf1c7 100644 --- a/crates/goose/src/providers/utils.rs +++ b/crates/goose/src/providers/utils.rs @@ -68,6 +68,16 @@ fn check_context_length_exceeded(text: &str) -> bool { .any(|phrase| text_lower.contains(phrase)) } +fn format_server_error_message(status_code: StatusCode, payload: Option<&Value>) -> String { + match payload { + Some(Value::Null) | None => format!( + "HTTP {}: No response body received from server", + status_code.as_u16() + ), + Some(p) => format!("HTTP {}: {}", status_code.as_u16(), p), + } +} + pub fn map_http_error_to_provider_error( status: StatusCode, payload: Option, @@ -79,7 +89,7 @@ pub fn map_http_error_to_provider_error( "Authentication failed. Please ensure your API keys are valid and have the required permissions. \ Status: {}{}", status, - payload.as_ref().map(|p| format!(". Response: {:?}", p)).unwrap_or_default() + payload.as_ref().map(|p| format!(". Response: {}", p)).unwrap_or_default() ); ProviderError::Authentication(message) } @@ -116,7 +126,9 @@ pub fn map_http_error_to_provider_error( details: format!("{:?}", payload), retry_delay: None, }, - _ if status.is_server_error() => ProviderError::ServerError(format!("{:?}", payload)), + _ if status.is_server_error() => { + ProviderError::ServerError(format_server_error_message(status, payload.as_ref())) + } _ => ProviderError::RequestFailed(format!("Request failed with status: {}", status)), }; @@ -295,12 +307,9 @@ pub async fn handle_response_google_compat(response: Response) -> Result { - Err(ProviderError::ServerError(format!("{:?}", payload))) - } - StatusCode::INTERNAL_SERVER_ERROR | StatusCode::SERVICE_UNAVAILABLE => { - Err(ProviderError::ServerError(format!("{:?}", payload))) - } + _ if final_status.is_server_error() => Err(ProviderError::ServerError( + format_server_error_message(final_status, payload.as_ref()), + )), _ => { tracing::debug!( "{}", format!("Provider request failed with status: {}. Payload: {:?}", final_status, payload) @@ -1059,15 +1068,13 @@ mod tests { #[test] fn test_map_http_error_to_provider_error() { let test_cases = vec![ - // UNAUTHORIZED/FORBIDDEN - with payload ( StatusCode::UNAUTHORIZED, Some(json!({"error": "auth failed"})), ProviderError::Authentication( - "Authentication failed. Please ensure your API keys are valid and have the required permissions. Status: 401 Unauthorized. Response: Object {\"error\": String(\"auth failed\")}".to_string(), + "Authentication failed. Please ensure your API keys are valid and have the required permissions. Status: 401 Unauthorized. Response: {\"error\":\"auth failed\"}".to_string(), ), ), - // UNAUTHORIZED/FORBIDDEN - without payload ( StatusCode::FORBIDDEN, None, @@ -1075,7 +1082,6 @@ mod tests { "Authentication failed. Please ensure your API keys are valid and have the required permissions. Status: 403 Forbidden".to_string(), ), ), - // BAD_REQUEST - with context_length_exceeded detection ( StatusCode::BAD_REQUEST, Some(json!({"error": {"message": "context_length_exceeded"}})), @@ -1083,7 +1089,6 @@ mod tests { "{\"error\":{\"message\":\"context_length_exceeded\"}}".to_string(), ), ), - // BAD_REQUEST - with error.message extraction ( StatusCode::BAD_REQUEST, Some(json!({"error": {"message": "Custom error"}})), @@ -1091,7 +1096,6 @@ mod tests { "Request failed with status: 400 Bad Request. Message: Custom error".to_string(), ), ), - // BAD_REQUEST - without payload ( StatusCode::BAD_REQUEST, None, @@ -1099,7 +1103,6 @@ mod tests { "Request failed with status: 400 Bad Request".to_string(), ), ), - // TOO_MANY_REQUESTS ( StatusCode::TOO_MANY_REQUESTS, Some(json!({"retry_after": 60})), @@ -1108,17 +1111,29 @@ mod tests { retry_delay: None, }, ), - // is_server_error() without payload ( StatusCode::INTERNAL_SERVER_ERROR, None, - ProviderError::ServerError("None".to_string()), + ProviderError::ServerError(format_server_error_message( + StatusCode::INTERNAL_SERVER_ERROR, + None, + )), + ), + ( + StatusCode::INTERNAL_SERVER_ERROR, + Some(Value::Null), + ProviderError::ServerError(format_server_error_message( + StatusCode::INTERNAL_SERVER_ERROR, + Some(&Value::Null), + )), ), - // is_server_error() with payload ( StatusCode::BAD_GATEWAY, Some(json!({"error": "upstream error"})), - ProviderError::ServerError("Some(Object {\"error\": String(\"upstream error\")})".to_string()), + ProviderError::ServerError(format_server_error_message( + StatusCode::BAD_GATEWAY, + Some(&json!({"error": "upstream error"})), + )), ), // Default - any other status code ( From 4dd06234ea83ec1ee35b9eb95cab242ed7f86532 Mon Sep 17 00:00:00 2001 From: Ebony Louis <55366651+EbonyLouis@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:44:03 -0500 Subject: [PATCH 083/121] Add Diagnostics Info to Q&A and Bug Report Templates (#5565) Signed-off-by: fbalicchia --- .github/DISCUSSION_TEMPLATE/qa.yml | 26 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 31 ++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 .github/DISCUSSION_TEMPLATE/qa.yml diff --git a/.github/DISCUSSION_TEMPLATE/qa.yml b/.github/DISCUSSION_TEMPLATE/qa.yml new file mode 100644 index 000000000000..9bbd676aff86 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/qa.yml @@ -0,0 +1,26 @@ +title: "❓ Question: [Brief summary]" +labels: + - help +body: + - type: markdown + attributes: + value: | + 💡 Before posting, please attach your **diagnostics zip** — it helps the Goose team debug faster and saves everyone time. + [How to capture and share diagnostics](https://block.github.io/goose/docs/troubleshooting/diagnostics-and-reporting/) + - type: textarea + id: problem + attributes: + label: What happened? + description: Describe the issue in detail and attach your diagnostics zip if possible. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Tell us how to reproduce the issue — commands, steps, or context. + - type: textarea + id: version + attributes: + label: Goose version and environment + description: Include your Goose version and operating system if known. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 689e3ef1702a..e2d4d93e0ef8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,17 +2,22 @@ name: Bug report about: Create a report to help us improve title: '' -labels: '' +labels: bug assignees: '' - --- **Describe the bug** -Note: Please check the common issues on https://block.github.io/goose/docs/troubleshooting before filing a report +💡 Before filing, please check common issues: +https://block.github.io/goose/docs/troubleshooting + +📦 To help us debug faster, attach your **diagnostics zip** if possible. +👉 How to capture it: https://block.github.io/goose/docs/troubleshooting/diagnostics-and-reporting/ A clear and concise description of what the bug is. +--- + **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' @@ -20,18 +25,26 @@ Steps to reproduce the behavior: 3. Scroll down to '....' 4. See error +--- + **Expected behavior** A clear and concise description of what you expected to happen. +--- + **Screenshots** If applicable, add screenshots to help explain your problem. -**Please provide following information:** - - **OS & Arch:** [e.g. Ubuntu 22.04 x86] - - **Interface:** [UI/CLI] - - **Version:** [e.g. v1.0.2] - - **Extensions enabled:** [e.g. Computer Controller, Figma] - - **Provider & Model:** [e.g. Google - gemini-1.5-pro] +--- + +**Please provide the following information** +- **OS & Arch:** [e.g. Ubuntu 22.04 x86] +- **Interface:** [UI / CLI] +- **Version:** [e.g. v1.0.2] +- **Extensions enabled:** [e.g. Computer Controller, Figma] +- **Provider & Model:** [e.g. Google – gemini-1.5-pro] + +--- **Additional context** Add any other context about the problem here. From 2da8b0b8dd5a8a883c8ebf78a99ddcaf8b81cc69 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Tue, 4 Nov 2025 14:47:44 -0500 Subject: [PATCH 084/121] disable RPM build-ID generation to prevent package conflicts (#5563) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- ui/desktop/forge.config.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts index 942e749f863b..83f676f28c9b 100644 --- a/ui/desktop/forge.config.ts +++ b/ui/desktop/forge.config.ts @@ -26,12 +26,12 @@ let cfg = { // Document types for drag-and-drop support onto dock icon CFBundleDocumentTypes: [ { - CFBundleTypeName: "Folders", - CFBundleTypeRole: "Viewer", - LSHandlerRank: "Alternate", - LSItemContentTypes: ["public.directory", "public.folder"] - } - ] + CFBundleTypeName: 'Folders', + CFBundleTypeRole: 'Viewer', + LSHandlerRank: 'Alternate', + LSItemContentTypes: ['public.directory', 'public.folder'], + }, + ], }, }; @@ -73,8 +73,8 @@ module.exports = { desktopTemplate: './forge.deb.desktop', options: { icon: 'src/images/icon.png', - prefix: '/opt' - } + prefix: '/opt', + }, }, }, { @@ -88,8 +88,9 @@ module.exports = { desktopTemplate: './forge.rpm.desktop', options: { icon: 'src/images/icon.png', - prefix: '/opt' - } + prefix: '/opt', + fpm: ['--rpm-rpmbuild-define', '_build_id_links none'], + }, }, }, ], From 616ec70c9e14e3f4b3f46ef29e3bc4aa76fcd698 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:47:51 -0800 Subject: [PATCH 085/121] use app.isPackaged instead of checking for node env development (#5465) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- ui/desktop/src/main.ts | 2 +- ui/desktop/src/utils/autoUpdater.ts | 3 +- ui/desktop/src/utils/costDatabase.ts | 47 ---------------------------- ui/desktop/src/utils/logger.ts | 16 ++-------- ui/desktop/src/utils/pathUtils.ts | 4 +-- 5 files changed, 6 insertions(+), 66 deletions(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index 0bbac7a99020..b97971986fdc 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -768,7 +768,7 @@ const createTray = () => { // If tray already exists, destroy it first destroyTray(); - const isDev = process.env.NODE_ENV === 'development'; + const isDev = !app.isPackaged; let iconPath: string; if (isDev) { diff --git a/ui/desktop/src/utils/autoUpdater.ts b/ui/desktop/src/utils/autoUpdater.ts index 6753cc0e8f05..9495c9d19092 100644 --- a/ui/desktop/src/utils/autoUpdater.ts +++ b/ui/desktop/src/utils/autoUpdater.ts @@ -248,7 +248,6 @@ export function setupAutoUpdater(tray?: Tray) { log.info('Setting up auto-updater...'); log.info(`Current app version: ${app.getVersion()}`); log.info(`Platform: ${process.platform}, Arch: ${process.arch}`); - log.info(`NODE_ENV: ${process.env.NODE_ENV}`); log.info(`ENABLE_DEV_UPDATES: ${process.env.ENABLE_DEV_UPDATES}`); log.info(`App is packaged: ${app.isPackaged}`); log.info(`App path: ${app.getAppPath()}`); @@ -470,7 +469,7 @@ function sendStatusToWindow(event: string, data?: unknown) { function updateTrayIcon(hasUpdate: boolean) { if (!trayRef) return; - const isDev = process.env.NODE_ENV === 'development'; + const isDev = !app.isPackaged; let iconPath: string; if (hasUpdate) { diff --git a/ui/desktop/src/utils/costDatabase.ts b/ui/desktop/src/utils/costDatabase.ts index a2e8e5cbd213..5b3bde1de0fe 100644 --- a/ui/desktop/src/utils/costDatabase.ts +++ b/ui/desktop/src/utils/costDatabase.ts @@ -1,4 +1,3 @@ -// Import the proper type from ConfigContext import { getApiUrl } from '../config'; import { safeJsonParse } from './conversionUtils'; @@ -206,49 +205,3 @@ export async function fetchAndCachePricing( return null; } } - -/** - * Refresh pricing data from backend - */ -export async function refreshPricing(): Promise { - try { - // Clear session cache to force re-fetch - sessionPricingCache.clear(); - - // The actual refresh happens on the backend when we call with configured_only: false - const apiUrl = getApiUrl('/config/pricing'); - const secretKey = await window.electron.getSecretKey(); - - const headers: HeadersInit = { 'Content-Type': 'application/json' }; - if (secretKey) { - headers['X-Secret-Key'] = secretKey; - } - - const response = await fetch(apiUrl, { - method: 'POST', - headers, - body: JSON.stringify({ configured_only: false }), - }); - - return response.ok; - } catch { - return false; - } -} - -// Expose functions for testing in development mode -declare global { - interface Window { - getCostForModel?: typeof getCostForModel; - fetchAndCachePricing?: typeof fetchAndCachePricing; - refreshPricing?: typeof refreshPricing; - sessionPricingCache?: typeof sessionPricingCache; - } -} - -if (process.env.NODE_ENV === 'development' || typeof window !== 'undefined') { - window.getCostForModel = getCostForModel; - window.fetchAndCachePricing = fetchAndCachePricing; - window.refreshPricing = refreshPricing; - window.sessionPricingCache = sessionPricingCache; -} diff --git a/ui/desktop/src/utils/logger.ts b/ui/desktop/src/utils/logger.ts index f11e8b2543e4..4a088ad32cd9 100644 --- a/ui/desktop/src/utils/logger.ts +++ b/ui/desktop/src/utils/logger.ts @@ -2,21 +2,11 @@ import log from 'electron-log'; import path from 'node:path'; import { app } from 'electron'; -// Configure electron-log -// In development: ~/Library/Logs/goose/main.log -// In production: ~/Library/Application Support/goose/logs/main.log log.transports.file.resolvePathFn = () => { - const isDev = process.env.NODE_ENV === 'development'; - if (isDev) { - return path.join(app.getPath('home'), 'Library/Logs/goose/main.log'); - } - return path.join(app.getPath('userData'), 'logs/main.log'); + return path.join(app.getPath('userData'), 'logs', 'main.log'); }; -// Configure log level based on environment -log.transports.file.level = process.env.NODE_ENV === 'development' ? 'debug' : 'info'; - -// Also log to console in development -log.transports.console.level = process.env.NODE_ENV === 'development' ? 'debug' : false; +log.transports.file.level = app.isPackaged ? 'info' : 'debug'; +log.transports.console.level = app.isPackaged ? false : 'debug'; export default log; diff --git a/ui/desktop/src/utils/pathUtils.ts b/ui/desktop/src/utils/pathUtils.ts index cfa2677d09f4..f2865227a80f 100644 --- a/ui/desktop/src/utils/pathUtils.ts +++ b/ui/desktop/src/utils/pathUtils.ts @@ -71,9 +71,7 @@ const addPaths = ( executableName: string, app: Electron.App ): void => { - const isDev = process.env.NODE_ENV === 'development'; - const isPackaged = app.isPackaged; - if (isDev && !isPackaged) { + if (!app.isPackaged) { possiblePaths.push( path.join(process.cwd(), 'src', 'bin', executableName), path.join(process.cwd(), 'bin', executableName), From 2f1f20f9b9d0eb4f4dae212b847be326f7d631c0 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Tue, 4 Nov 2025 14:59:44 -0500 Subject: [PATCH 086/121] feat: log rotation (#5561) Signed-off-by: fbalicchia --- crates/goose-cli/src/logging.rs | 18 ++-------- crates/goose-server/src/logging.rs | 21 ++++-------- crates/goose/src/logging.rs | 52 +++++++++++++++++++++-------- crates/goose/src/providers/utils.rs | 6 ++-- 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/crates/goose-cli/src/logging.rs b/crates/goose-cli/src/logging.rs index f65fe5a4df6a..acd9d16d23ee 100644 --- a/crates/goose-cli/src/logging.rs +++ b/crates/goose-cli/src/logging.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Result}; -use std::path::PathBuf; use std::sync::Arc; use std::sync::Once; use tokio::sync::Mutex; @@ -16,12 +15,6 @@ use goose_bench::error_capture::ErrorCaptureLayer; // Used to ensure we only set up tracing once static INIT: Once = Once::new(); -/// Returns the directory where log files should be stored. -/// Creates the directory structure if it doesn't exist. -fn get_log_directory() -> Result { - goose::logging::get_log_directory("cli", true) -} - /// Sets up the logging infrastructure for the application. /// This includes: /// - File-based logging with JSON formatting (DEBUG level) @@ -50,20 +43,15 @@ fn setup_logging_internal( let mut setup = || { result = (|| { - // Set up file appender for goose module logs - let log_dir = get_log_directory()?; + let log_dir = goose::logging::prepare_log_directory("cli", true)?; let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S").to_string(); - - // Create log file name by prefixing with timestamp let log_filename = if name.is_some() { format!("{}-{}.log", timestamp, name.unwrap()) } else { format!("{}.log", timestamp) }; - - // Create non-rolling file appender for detailed logs let file_appender = tracing_appender::rolling::RollingFileAppender::new( - Rotation::NEVER, + Rotation::NEVER, // we do manual rotation via file naming and cleanup_old_logs log_dir, log_filename, ); @@ -177,7 +165,7 @@ mod tests { #[test] fn test_log_directory_creation() { let _temp_dir = setup_temp_home(); - let log_dir = get_log_directory().unwrap(); + let log_dir = goose::logging::prepare_log_directory("cli", true).unwrap(); assert!(log_dir.exists()); assert!(log_dir.is_dir()); diff --git a/crates/goose-server/src/logging.rs b/crates/goose-server/src/logging.rs index 7179e3cf7da3..0a5eadc20cf1 100644 --- a/crates/goose-server/src/logging.rs +++ b/crates/goose-server/src/logging.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Result}; -use std::path::PathBuf; use tracing_appender::rolling::Rotation; use tracing_subscriber::{ filter::LevelFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, @@ -8,32 +7,24 @@ use tracing_subscriber::{ use goose::tracing::{langfuse_layer, otlp_layer}; -/// Returns the directory where log files should be stored. -/// Creates the directory structure if it doesn't exist. -fn get_log_directory() -> Result { - goose::logging::get_log_directory("server", true) -} - /// Sets up the logging infrastructure for the application. /// This includes: /// - File-based logging with JSON formatting (DEBUG level) /// - Console output for development (INFO level) /// - Optional Langfuse integration (DEBUG level) pub fn setup_logging(name: Option<&str>) -> Result<()> { - // Set up file appender for goose module logs - let log_dir = get_log_directory()?; + let log_dir = goose::logging::prepare_log_directory("server", true)?; let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S").to_string(); - - // Create log file name by prefixing with timestamp let log_filename = if name.is_some() { format!("{}-{}.log", timestamp, name.unwrap()) } else { format!("{}.log", timestamp) }; - - // Create non-rolling file appender for detailed logs - let file_appender = - tracing_appender::rolling::RollingFileAppender::new(Rotation::NEVER, log_dir, log_filename); + let file_appender = tracing_appender::rolling::RollingFileAppender::new( + Rotation::NEVER, // we do manual rotation via file naming and cleanup_old_logs + log_dir, + log_filename, + ); // Create JSON file logging layer let file_layer = fmt::layer() diff --git a/crates/goose/src/logging.rs b/crates/goose/src/logging.rs index a6742d3d1e8f..80b96a935d85 100644 --- a/crates/goose/src/logging.rs +++ b/crates/goose/src/logging.rs @@ -2,33 +2,59 @@ use crate::config::paths::Paths; use anyhow::{Context, Result}; use std::fs; use std::path::PathBuf; +use std::time::{Duration, SystemTime}; /// Returns the directory where log files should be stored for a specific component. /// Creates the directory structure if it doesn't exist. /// /// # Arguments /// -/// * `component` - The component name (e.g., "cli", "server", "debug") +/// * `component` - The component name (e.g., "cli", "server", "debug", "llm") /// * `use_date_subdir` - Whether to create a date-based subdirectory -pub fn get_log_directory(component: &str, use_date_subdir: bool) -> Result { +pub fn prepare_log_directory(component: &str, use_date_subdir: bool) -> Result { let base_log_dir = Paths::in_state_dir("logs"); + let _ = cleanup_old_logs(component); + let component_dir = base_log_dir.join(component); let log_dir = if use_date_subdir { - // Create date-based subdirectory - let now = chrono::Local::now(); - component_dir.join(now.format("%Y-%m-%d").to_string()) + component_dir.join(chrono::Local::now().format("%Y-%m-%d").to_string()) } else { component_dir }; - // Ensure log directory exists fs::create_dir_all(&log_dir).context("Failed to create log directory")?; Ok(log_dir) } +pub fn cleanup_old_logs(component: &str) -> Result<()> { + let base_log_dir = Paths::in_state_dir("logs"); + let component_dir = base_log_dir.join(component); + + if !component_dir.exists() { + return Ok(()); + } + + let two_weeks = SystemTime::now() - Duration::from_secs(14 * 24 * 60 * 60); + let entries = fs::read_dir(&component_dir)?; + + for entry in entries.flatten() { + let path = entry.path(); + + if let Ok(metadata) = entry.metadata() { + if let Ok(modified) = metadata.modified() { + if modified < two_weeks && path.is_dir() { + let _ = fs::remove_dir_all(&path); + } + } + } + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -37,7 +63,7 @@ mod tests { #[test] fn test_get_log_directory_basic_functionality() { // Test basic directory creation without date subdirectory - let result = get_log_directory("cli", false); + let result = prepare_log_directory("cli", false); assert!(result.is_ok()); let log_dir = result.unwrap(); @@ -59,7 +85,7 @@ mod tests { #[test] fn test_get_log_directory_with_date_subdir() { // Test date-based subdirectory creation - let result = get_log_directory("server", true); + let result = prepare_log_directory("server", true); assert!(result.is_ok()); let log_dir = result.unwrap(); @@ -90,11 +116,11 @@ mod tests { // Test that multiple calls return the same result and don't fail let component = "debug"; - let result1 = get_log_directory(component, false); + let result1 = prepare_log_directory(component, false); assert!(result1.is_ok()); let log_dir1 = result1.unwrap(); - let result2 = get_log_directory(component, false); + let result2 = prepare_log_directory(component, false); assert!(result2.is_ok()); let log_dir2 = result2.unwrap(); @@ -104,11 +130,11 @@ mod tests { assert!(log_dir2.exists()); // Test same behavior with date subdirectories - let result3 = get_log_directory(component, true); + let result3 = prepare_log_directory(component, true); assert!(result3.is_ok()); let log_dir3 = result3.unwrap(); - let result4 = get_log_directory(component, true); + let result4 = prepare_log_directory(component, true); assert!(result4.is_ok()); let log_dir4 = result4.unwrap(); @@ -123,7 +149,7 @@ mod tests { let mut created_dirs = Vec::new(); for component in &components { - let result = get_log_directory(component, false); + let result = prepare_log_directory(component, false); assert!(result.is_ok(), "Failed for component: {}", component); let log_dir = result.unwrap(); diff --git a/crates/goose/src/providers/utils.rs b/crates/goose/src/providers/utils.rs index c227b4ddf1c7..def0c4e544d7 100644 --- a/crates/goose/src/providers/utils.rs +++ b/crates/goose/src/providers/utils.rs @@ -1,6 +1,5 @@ use super::base::Usage; use super::errors::GoogleErrorCode; -use crate::config::paths::Paths; use crate::model::ModelConfig; use crate::providers::errors::{OpenAIError, ProviderError}; use anyhow::{anyhow, Result}; @@ -471,8 +470,7 @@ impl RequestLog { where Payload: Serialize, { - let logs_dir = Paths::in_state_dir("logs"); - std::fs::create_dir_all(&logs_dir)?; + let logs_dir = crate::logging::prepare_log_directory("llm", true)?; let request_id = Uuid::new_v4(); let temp_name = format!("llm_request.{request_id}.jsonl"); @@ -529,7 +527,7 @@ impl RequestLog { fn finish(&mut self) -> Result<()> { if let Some(mut writer) = self.writer.take() { writer.flush()?; - let logs_dir = Paths::in_state_dir("logs"); + let logs_dir = crate::logging::prepare_log_directory("llm", true)?; let log_path = |i| logs_dir.join(format!("llm_request.{}.jsonl", i)); for i in (0..LOGS_TO_KEEP - 1).rev() { From d0a5ecc26f56547422af8da124642a421fba2892 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:06:24 -0800 Subject: [PATCH 087/121] improve linux tray icon support (#5425) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- ui/desktop/src/main.ts | 48 ++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index b97971986fdc..6fd76def0959 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -764,30 +764,43 @@ const destroyTray = () => { } }; +const disableTray = () => { + const settings = loadSettings(); + settings.showMenuBarIcon = false; + saveSettings(settings); +}; + const createTray = () => { - // If tray already exists, destroy it first destroyTray(); - const isDev = !app.isPackaged; - let iconPath: string; + const possiblePaths = [ + path.join(process.resourcesPath, 'images', 'iconTemplate.png'), + path.join(process.cwd(), 'src', 'images', 'iconTemplate.png'), + path.join(__dirname, '..', 'images', 'iconTemplate.png'), + path.join(__dirname, 'images', 'iconTemplate.png'), + path.join(process.cwd(), 'images', 'iconTemplate.png'), + ]; - if (isDev) { - iconPath = path.join(process.cwd(), 'src', 'images', 'iconTemplate.png'); - } else { - iconPath = path.join(process.resourcesPath, 'images', 'iconTemplate.png'); - } - - tray = new Tray(iconPath); + const iconPath = possiblePaths.find((p) => fsSync.existsSync(p)); - // Set tray reference for auto-updater - setTrayRef(tray); + if (!iconPath) { + console.warn('[Main] Tray icon not found. App will continue without system tray.'); + disableTray(); + return; + } - // Initially build menu based on update status - updateTrayMenu(getUpdateAvailable()); + try { + tray = new Tray(iconPath); + setTrayRef(tray); + updateTrayMenu(getUpdateAvailable()); - // On Windows, clicking the tray icon should show the window - if (process.platform === 'win32') { - tray.on('click', showWindow); + if (process.platform === 'win32') { + tray.on('click', showWindow); + } + } catch (error) { + console.error('[Main] Tray creation failed. App will continue without system tray.', error); + disableTray(); + tray = null; } }; @@ -802,7 +815,6 @@ const showWindow = async () => { return; } - // Define the initial offset values const initialOffsetX = 30; const initialOffsetY = 30; From 218182154df5302f2fb4d4e2dfe555f21c1b3546 Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:46:25 -0800 Subject: [PATCH 088/121] add clippy warning for string_slice (#5422) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- Cargo.toml | 1 + crates/goose-cli/src/session/completion.rs | 4 +- crates/goose-cli/src/session/input.rs | 18 ++++--- .../src/developer/analyze/formatter.rs | 18 +++---- .../src/developer/analyze/languages/go.rs | 2 +- .../src/developer/analyze/languages/ruby.rs | 2 +- .../src/developer/analyze/languages/rust.rs | 8 +-- .../goose-mcp/src/developer/analyze/parser.rs | 50 +++++++++++++------ .../editor_models/morphllm_editor.rs | 5 +- .../goose-mcp/src/developer/rmcp_developer.rs | 27 ++++++---- crates/goose-test/src/mcp/stdio/playback.rs | 2 +- crates/goose/src/agents/agent.rs | 8 --- .../agents/subagent_execution_tool/tasks.rs | 2 +- crates/goose/src/providers/claude_code.rs | 27 +--------- crates/goose/src/providers/cursor_agent.rs | 29 ++--------- .../goose/src/providers/formats/snowflake.rs | 4 +- crates/goose/src/providers/gemini_cli.rs | 27 +--------- crates/goose/src/providers/githubcopilot.rs | 4 +- crates/goose/src/providers/sagemaker_tgi.rs | 2 +- crates/goose/src/providers/utils.rs | 25 ++++++++++ .../utils_universal_openai_stream.rs | 12 +++-- scripts/test_providers.sh | 2 +- 22 files changed, 131 insertions(+), 148 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c312ee8c8ba..d88b69afed98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ description = "An AI agent" [workspace.lints.clippy] uninlined_format_args = "allow" +string_slice = "warn" [workspace.dependencies] rmcp = { version = "0.8.3", features = ["schemars", "auth"] } diff --git a/crates/goose-cli/src/session/completion.rs b/crates/goose-cli/src/session/completion.rs index 67021047458c..6c32529a9aba 100644 --- a/crates/goose-cli/src/session/completion.rs +++ b/crates/goose-cli/src/session/completion.rs @@ -26,7 +26,7 @@ impl GooseCompleter { /// Complete prompt names for the /prompt command fn complete_prompt_names(&self, line: &str) -> Result<(usize, Vec)> { // Get the prefix of the prompt name being typed - let prefix = if line.len() > 8 { &line[8..] } else { "" }; + let prefix = line.get(8..).unwrap_or(""); // Get available prompts from cache let cache = self.completion_cache.read().unwrap(); @@ -156,7 +156,7 @@ impl GooseCompleter { /// Complete argument keys for a specific prompt fn complete_argument_keys(&self, line: &str) -> Result<(usize, Vec)> { - let parts: Vec<&str> = line[8..].split_whitespace().collect(); + let parts: Vec<&str> = line.get(8..).unwrap_or("").split_whitespace().collect(); // We need at least the prompt name if parts.is_empty() { diff --git a/crates/goose-cli/src/session/input.rs b/crates/goose-cli/src/session/input.rs index 081be75f9862..a1d44b877fda 100644 --- a/crates/goose-cli/src/session/input.rs +++ b/crates/goose-cli/src/session/input.rs @@ -169,15 +169,17 @@ fn handle_slash_command(input: &str) -> Option { } } s if s.starts_with(CMD_EXTENSION) => Some(InputResult::AddExtension( - s[CMD_EXTENSION.len()..].to_string(), + s.get(CMD_EXTENSION.len()..).unwrap_or("").to_string(), )), - s if s.starts_with(CMD_BUILTIN) => { - Some(InputResult::AddBuiltin(s[CMD_BUILTIN.len()..].to_string())) - } - s if s.starts_with(CMD_MODE) => { - Some(InputResult::GooseMode(s[CMD_MODE.len()..].to_string())) + s if s.starts_with(CMD_BUILTIN) => Some(InputResult::AddBuiltin( + s.get(CMD_BUILTIN.len()..).unwrap_or("").to_string(), + )), + s if s.starts_with(CMD_MODE) => Some(InputResult::GooseMode( + s.get(CMD_MODE.len()..).unwrap_or("").to_string(), + )), + s if s.starts_with(CMD_PLAN) => { + parse_plan_command(s.get(CMD_PLAN.len()..).unwrap_or("").trim().to_string()) } - s if s.starts_with(CMD_PLAN) => parse_plan_command(s[CMD_PLAN.len()..].trim().to_string()), s if s == CMD_ENDPLAN => Some(InputResult::EndPlan), s if s == CMD_CLEAR => Some(InputResult::Clear), s if s.starts_with(CMD_RECIPE) => parse_recipe_command(s), @@ -199,7 +201,7 @@ fn parse_recipe_command(s: &str) -> Option { } // Extract the filepath from the command - let filepath = s[CMD_RECIPE.len()..].trim(); + let filepath = s.get(CMD_RECIPE.len()..).unwrap_or("").trim(); if filepath.is_empty() { return Some(InputResult::Recipe(None)); diff --git a/crates/goose-mcp/src/developer/analyze/formatter.rs b/crates/goose-mcp/src/developer/analyze/formatter.rs index c05011647820..49bb76cc4509 100644 --- a/crates/goose-mcp/src/developer/analyze/formatter.rs +++ b/crates/goose-mcp/src/developer/analyze/formatter.rs @@ -1,11 +1,11 @@ -use rmcp::model::{Content, Role}; -use std::collections::{HashMap, HashSet}; -use std::path::{Path, PathBuf}; - use crate::developer::analyze::types::{ AnalysisMode, AnalysisResult, CallChain, EntryType, FocusedAnalysisData, }; use crate::developer::lang; +use goose::utils::safe_truncate; +use rmcp::model::{Content, Role}; +use std::collections::{HashMap, HashSet}; +use std::path::{Path, PathBuf}; pub struct Formatter; @@ -164,13 +164,7 @@ impl Formatter { if imports.len() > 1 { format!("{}({})", group, imports.len()) } else { - // For single imports, show more detail - let imp = &imports[0]; - if imp.len() > 40 { - format!("{}...", &imp[..37]) - } else { - imp.clone() - } + safe_truncate(&imports[0], 40) } }) .collect(); @@ -727,7 +721,7 @@ impl Formatter { if let Some(header_line) = output .lines() .rev() - .find(|l| l.starts_with("##") && line.contains(&l[3..])) + .find(|l| l.starts_with("##") && l.get(3..).is_some_and(|s| line.contains(s))) { if !filtered.contains(header_line) { filtered.push_str(header_line); diff --git a/crates/goose-mcp/src/developer/analyze/languages/go.rs b/crates/goose-mcp/src/developer/analyze/languages/go.rs index 71c7116e7aee..9c1ec28376e0 100644 --- a/crates/goose-mcp/src/developer/analyze/languages/go.rs +++ b/crates/goose-mcp/src/developer/analyze/languages/go.rs @@ -87,7 +87,7 @@ pub fn find_method_for_receiver( for i in 0..parent.child_count() { if let Some(child) = parent.child(i) { if child.kind() == "field_identifier" { - return Some(source[child.byte_range()].to_string()); + return source.get(child.byte_range()).map(|s| s.to_string()); } } } diff --git a/crates/goose-mcp/src/developer/analyze/languages/ruby.rs b/crates/goose-mcp/src/developer/analyze/languages/ruby.rs index 6214e6313596..df9f7496fa7c 100644 --- a/crates/goose-mcp/src/developer/analyze/languages/ruby.rs +++ b/crates/goose-mcp/src/developer/analyze/languages/ruby.rs @@ -140,7 +140,7 @@ fn find_method_in_body_with_depth( for j in 0..child.child_count() { if let Some(name_node) = child.child(j) { if name_node.kind() == "identifier" { - return Some(source[name_node.byte_range()].to_string()); + return source.get(name_node.byte_range()).map(|s| s.to_string()); } } } diff --git a/crates/goose-mcp/src/developer/analyze/languages/rust.rs b/crates/goose-mcp/src/developer/analyze/languages/rust.rs index bc1a980db1cf..bf9a6f983e47 100644 --- a/crates/goose-mcp/src/developer/analyze/languages/rust.rs +++ b/crates/goose-mcp/src/developer/analyze/languages/rust.rs @@ -83,7 +83,9 @@ pub fn extract_function_name_for_kind( for i in 0..node.child_count() { if let Some(child) = node.child(i) { if child.kind() == "type_identifier" { - return Some(format!("impl {}", &source[child.byte_range()])); + return source + .get(child.byte_range()) + .map(|s| format!("impl {}", s)); } } } @@ -109,7 +111,7 @@ pub fn find_method_for_receiver( for i in 0..parent.child_count() { if let Some(child) = parent.child(i) { if child.kind() == "identifier" { - return Some(source[child.byte_range()].to_string()); + return source.get(child.byte_range()).map(|s| s.to_string()); } } } @@ -133,7 +135,7 @@ pub fn find_receiver_type(node: &tree_sitter::Node, source: &str) -> Option Option { - Self::find_child_by_kind(node, kinds).map(|child| source[child.byte_range()].to_string()) + Self::find_child_by_kind(node, kinds) + .and_then(|child| source.get(child.byte_range()).map(|s| s.to_string())) } pub fn extract_with_depth( @@ -216,8 +217,13 @@ impl ElementExtractor { for match_ in matches.by_ref() { for capture in match_.captures { let node = capture.node; - let text = &source[node.byte_range()]; - let line = source[..node.start_byte()].lines().count() + 1; + let Some(text) = source.get(node.byte_range()) else { + continue; + }; + let line = source + .get(..node.start_byte()) + .map(|s| s.lines().count() + 1) + .unwrap_or(1); match query.capture_names()[capture.index as usize] { "func" | "const" => { @@ -284,18 +290,25 @@ impl ElementExtractor { for match_ in matches.by_ref() { for capture in match_.captures { let node = capture.node; - let text = &source[node.byte_range()]; + let Some(text) = source.get(node.byte_range()) else { + continue; + }; let start_pos = node.start_position(); - let line_start = source[..node.start_byte()] - .rfind('\n') + let line_start = source + .get(..node.start_byte()) + .and_then(|s| s.rfind('\n')) .map(|i| i + 1) .unwrap_or(0); - let line_end = source[node.end_byte()..] - .find('\n') + let line_end = source + .get(node.end_byte()..) + .and_then(|s| s.find('\n')) .map(|i| node.end_byte() + i) .unwrap_or(source.len()); - let context = source[line_start..line_end].trim().to_string(); + let context = source + .get(line_start..line_end) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); let caller_name = Self::find_containing_function(&node, source, language); @@ -356,18 +369,25 @@ impl ElementExtractor { for match_ in matches.by_ref() { for capture in match_.captures { let node = capture.node; - let text = &source[node.byte_range()]; + let Some(text) = source.get(node.byte_range()) else { + continue; + }; let start_pos = node.start_position(); - let line_start = source[..node.start_byte()] - .rfind('\n') + let line_start = source + .get(..node.start_byte()) + .and_then(|s| s.rfind('\n')) .map(|i| i + 1) .unwrap_or(0); - let line_end = source[node.end_byte()..] - .find('\n') + let line_end = source + .get(node.end_byte()..) + .and_then(|s| s.find('\n')) .map(|i| node.end_byte() + i) .unwrap_or(source.len()); - let context = source[line_start..line_end].trim().to_string(); + let context = source + .get(line_start..line_end) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); let capture_name = query.capture_names()[capture.index as usize]; diff --git a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs index 57a33859636b..44170a48cf81 100644 --- a/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs +++ b/crates/goose-mcp/src/developer/editor_models/morphllm_editor.rs @@ -28,8 +28,9 @@ impl MorphLLMEditor { if let (Some(start_pos), Some(end_pos)) = (text.find(&start_tag), text.find(&end_tag)) { if start_pos < end_pos { let content_start = start_pos + start_tag.len(); - let content = &text[content_start..end_pos]; - return Some(content.trim().to_string()); + if let Some(content) = text.get(content_start..end_pos) { + return Some(content.trim().to_string()); + } } } None diff --git a/crates/goose-mcp/src/developer/rmcp_developer.rs b/crates/goose-mcp/src/developer/rmcp_developer.rs index bbd91d96ae25..c2257c2876e0 100644 --- a/crates/goose-mcp/src/developer/rmcp_developer.rs +++ b/crates/goose-mcp/src/developer/rmcp_developer.rs @@ -1335,20 +1335,22 @@ impl DeveloperServer { // Find the last space before AM/PM and replace it with U+202F let space_pos = filename.rfind(meridian) - .map(|pos| filename[..pos].trim_end().len()) + .and_then(|pos| filename.get(..pos).map(|s| s.trim_end().len())) .unwrap_or(0); if space_pos > 0 { let parent = path.parent().unwrap_or(Path::new("")); - let new_filename = format!( - "{}{}{}", - &filename[..space_pos], - '\u{202F}', - &filename[space_pos+1..] - ); - let new_path = parent.join(new_filename); - - return new_path; + if let (Some(before), Some(after)) = (filename.get(..space_pos), filename.get(space_pos+1..)) { + let new_filename = format!( + "{}{}{}", + before, + '\u{202F}', + after + ); + let new_path = parent.join(new_filename); + + return new_path; + } } } } @@ -3208,7 +3210,10 @@ mod tests { ) { let start_idx = start + start_tag.len(); if start_idx < end { - let path = assistant_content.text[start_idx..end].trim(); + let Some(path) = assistant_content.text.get(start_idx..end).map(|s| s.trim()) + else { + panic!("Failed to extract path from assistant content"); + }; println!("Extracted path: {}", path); let file_contents = diff --git a/crates/goose-test/src/mcp/stdio/playback.rs b/crates/goose-test/src/mcp/stdio/playback.rs index 82f3897ecf1e..49c3e4567e20 100644 --- a/crates/goose-test/src/mcp/stdio/playback.rs +++ b/crates/goose-test/src/mcp/stdio/playback.rs @@ -20,7 +20,7 @@ struct LogEntry { fn parse_log_line(line: &str) -> Option { line.find(": ").and_then(|pos| { let (prefix, content) = line.split_at(pos); - let content = &content[2..]; // Skip ": " + let content = content.get(2..)?; // Skip ": " let stream_type = match prefix { "STDIN" => StreamType::Stdin, diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 9e80a08f8160..61dfa73acd1e 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -1365,17 +1365,9 @@ impl Agent { .unwrap_or(&content) .trim() .to_string(); - tracing::debug!( - "Cleaned content for parsing: {}", - &clean_content[..std::cmp::min(200, clean_content.len())] - ); - // try to parse json response from the LLM - tracing::debug!("Attempting to parse recipe content as JSON"); let (instructions, activities) = if let Ok(json_content) = serde_json::from_str::(&clean_content) { - tracing::debug!("Successfully parsed JSON content"); - let instructions = json_content .get("instructions") .ok_or_else(|| anyhow!("Missing 'instructions' in json response"))? diff --git a/crates/goose/src/agents/subagent_execution_tool/tasks.rs b/crates/goose/src/agents/subagent_execution_tool/tasks.rs index e978030231f0..f8a46ae7ace8 100644 --- a/crates/goose/src/agents/subagent_execution_tool/tasks.rs +++ b/crates/goose/src/agents/subagent_execution_tool/tasks.rs @@ -249,7 +249,7 @@ fn extract_json_from_line(line: &str) -> Option { return None; } - let potential_json = &line[start..=end]; + let potential_json = line.get(start..=end)?; if serde_json::from_str::(potential_json).is_ok() { Some(potential_json.to_string()) } else { diff --git a/crates/goose/src/providers/claude_code.rs b/crates/goose/src/providers/claude_code.rs index e64a212bd2d9..a05e64c08d73 100644 --- a/crates/goose/src/providers/claude_code.rs +++ b/crates/goose/src/providers/claude_code.rs @@ -9,7 +9,7 @@ use tokio::process::Command; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; -use super::utils::RequestLog; +use super::utils::{filter_extensions_from_system_prompt, RequestLog}; use crate::config::{Config, GooseMode}; use crate::conversation::message::{Message, MessageContent}; use crate::model::ModelConfig; @@ -103,28 +103,6 @@ impl ClaudeCodeProvider { None } - /// Filter out the Extensions section from the system prompt - fn filter_extensions_from_system_prompt(&self, system: &str) -> String { - // Find the Extensions section and remove it - if let Some(extensions_start) = system.find("# Extensions") { - // Look for the next major section that starts with # - let after_extensions = &system[extensions_start..]; - if let Some(next_section_pos) = after_extensions[1..].find("\n# ") { - // Found next section, keep everything before Extensions and after the next section - let before_extensions = &system[..extensions_start]; - let next_section_start = extensions_start + next_section_pos + 1; - let after_next_section = &system[next_section_start..]; - format!("{}{}", before_extensions.trim_end(), after_next_section) - } else { - // No next section found, just remove everything from Extensions onward - system[..extensions_start].trim_end().to_string() - } - } else { - // No Extensions section found, return original - system.to_string() - } - } - /// Convert goose messages to the format expected by claude CLI fn messages_to_claude_format(&self, _system: &str, messages: &[Message]) -> Result { let mut claude_messages = Vec::new(); @@ -303,8 +281,7 @@ impl ClaudeCodeProvider { ProviderError::RequestFailed(format!("Failed to format messages: {}", e)) })?; - // Create a filtered system prompt without Extensions section - let filtered_system = self.filter_extensions_from_system_prompt(system); + let filtered_system = filter_extensions_from_system_prompt(system); if std::env::var("GOOSE_CLAUDE_CODE_DEBUG").is_ok() { println!("=== CLAUDE CODE PROVIDER DEBUG ==="); diff --git a/crates/goose/src/providers/cursor_agent.rs b/crates/goose/src/providers/cursor_agent.rs index 225d09e0265d..66469c83c2ae 100644 --- a/crates/goose/src/providers/cursor_agent.rs +++ b/crates/goose/src/providers/cursor_agent.rs @@ -9,7 +9,7 @@ use tokio::process::Command; use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; -use super::utils::RequestLog; +use super::utils::{filter_extensions_from_system_prompt, RequestLog}; use crate::conversation::message::{Message, MessageContent}; use crate::model::ModelConfig; use rmcp::model::Tool; @@ -112,34 +112,11 @@ impl CursorAgentProvider { None } - /// Filter out the Extensions section from the system prompt - fn filter_extensions_from_system_prompt(&self, system: &str) -> String { - // Find the Extensions section and remove it - if let Some(extensions_start) = system.find("# Extensions") { - // Look for the next major section that starts with # - let after_extensions = &system[extensions_start..]; - if let Some(next_section_pos) = after_extensions[1..].find("\n# ") { - // Found next section, keep everything before Extensions and after the next section - let before_extensions = &system[..extensions_start]; - let next_section_start = extensions_start + next_section_pos + 1; - let after_next_section = &system[next_section_start..]; - format!("{}{}", before_extensions.trim_end(), after_next_section) - } else { - // No next section found, just remove everything from Extensions onward - system[..extensions_start].trim_end().to_string() - } - } else { - // No Extensions section found, return original - system.to_string() - } - } - /// Convert goose messages to a simple prompt format for cursor-agent CLI fn messages_to_cursor_agent_format(&self, system: &str, messages: &[Message]) -> String { let mut full_prompt = String::new(); - // Add system prompt - let filtered_system = self.filter_extensions_from_system_prompt(system); + let filtered_system = filter_extensions_from_system_prompt(system); full_prompt.push_str(&filtered_system); full_prompt.push_str("\n\n"); @@ -267,7 +244,7 @@ impl CursorAgentProvider { println!("Original system prompt length: {} chars", system.len()); println!( "Filtered system prompt length: {} chars", - self.filter_extensions_from_system_prompt(system).len() + filter_extensions_from_system_prompt(system).len() ); println!("Full prompt: {}", prompt); println!("Model: {}", self.model.model_name); diff --git a/crates/goose/src/providers/formats/snowflake.rs b/crates/goose/src/providers/formats/snowflake.rs index 0f355612fe2b..2f8d492ad3ec 100644 --- a/crates/goose/src/providers/formats/snowflake.rs +++ b/crates/goose/src/providers/formats/snowflake.rs @@ -133,7 +133,9 @@ pub fn parse_streaming_response(sse_data: &str) -> Result { continue; } - let json_str = &line[6..]; // Remove "data: " prefix + let Some(json_str) = line.get(6..) else { + continue; + }; // Remove "data: " prefix if json_str.trim().is_empty() || json_str.trim() == "[DONE]" { continue; } diff --git a/crates/goose/src/providers/gemini_cli.rs b/crates/goose/src/providers/gemini_cli.rs index e13610e7dd09..af0016cac5ad 100644 --- a/crates/goose/src/providers/gemini_cli.rs +++ b/crates/goose/src/providers/gemini_cli.rs @@ -8,7 +8,7 @@ use tokio::process::Command; use super::base::{Provider, ProviderMetadata, ProviderUsage, Usage}; use super::errors::ProviderError; -use super::utils::RequestLog; +use super::utils::{filter_extensions_from_system_prompt, RequestLog}; use crate::conversation::message::{Message, MessageContent}; use crate::model::ModelConfig; @@ -103,28 +103,6 @@ impl GeminiCliProvider { None } - /// Filter out the Extensions section from the system prompt - fn filter_extensions_from_system_prompt(&self, system: &str) -> String { - // Find the Extensions section and remove it - if let Some(extensions_start) = system.find("# Extensions") { - // Look for the next major section that starts with # - let after_extensions = &system[extensions_start..]; - if let Some(next_section_pos) = after_extensions[1..].find("\n# ") { - // Found next section, keep everything before Extensions and after the next section - let before_extensions = &system[..extensions_start]; - let next_section_start = extensions_start + next_section_pos + 1; - let after_next_section = &system[next_section_start..]; - format!("{}{}", before_extensions.trim_end(), after_next_section) - } else { - // No next section found, just remove everything from Extensions onward - system[..extensions_start].trim_end().to_string() - } - } else { - // No Extensions section found, return original - system.to_string() - } - } - /// Execute gemini CLI command with simple text prompt async fn execute_command( &self, @@ -135,8 +113,7 @@ impl GeminiCliProvider { // Create a simple prompt combining system + conversation let mut full_prompt = String::new(); - // Add system prompt - let filtered_system = self.filter_extensions_from_system_prompt(system); + let filtered_system = filter_extensions_from_system_prompt(system); full_prompt.push_str(&filtered_system); full_prompt.push_str("\n\n"); diff --git a/crates/goose/src/providers/githubcopilot.rs b/crates/goose/src/providers/githubcopilot.rs index 1b503aa50a38..a4478ac1d56d 100644 --- a/crates/goose/src/providers/githubcopilot.rs +++ b/crates/goose/src/providers/githubcopilot.rs @@ -169,7 +169,9 @@ impl GithubCopilotProvider { if !tline.starts_with("data: ") { continue; } - let payload = &tline[6..]; + let Some(payload) = tline.get(6..) else { + continue; + }; if payload == "[DONE]" { break; } diff --git a/crates/goose/src/providers/sagemaker_tgi.rs b/crates/goose/src/providers/sagemaker_tgi.rs index a5210b5b91fa..74dbff3fa683 100644 --- a/crates/goose/src/providers/sagemaker_tgi.rs +++ b/crates/goose/src/providers/sagemaker_tgi.rs @@ -246,7 +246,7 @@ impl SageMakerTgiProvider { // Remove any remaining HTML-like tags using a simple pattern // This is a basic implementation - for production use, consider using a proper HTML parser while let Some(start) = result.find('<') { - if let Some(end) = result[start..].find('>') { + if let Some(end) = result.get(start..).and_then(|s| s.find('>')) { result.replace_range(start..start + end + 1, ""); } else { break; diff --git a/crates/goose/src/providers/utils.rs b/crates/goose/src/providers/utils.rs index def0c4e544d7..5da1946a623d 100644 --- a/crates/goose/src/providers/utils.rs +++ b/crates/goose/src/providers/utils.rs @@ -47,6 +47,31 @@ pub fn convert_image(image: &ImageContent, image_format: &ImageFormat) -> Value } } +pub fn filter_extensions_from_system_prompt(system: &str) -> String { + let Some(extensions_start) = system.find("# Extensions") else { + return system.to_string(); + }; + + let Some(after_extensions) = system.get(extensions_start + 1..) else { + return system.to_string(); + }; + + if let Some(next_section_pos) = after_extensions.find("\n# ") { + let Some(before) = system.get(..extensions_start) else { + return system.to_string(); + }; + let Some(after) = system.get(extensions_start + next_section_pos + 1..) else { + return system.to_string(); + }; + format!("{}{}", before.trim_end(), after) + } else { + system + .get(..extensions_start) + .map(|s| s.trim_end().to_string()) + .unwrap_or_else(|| system.to_string()) + } +} + fn check_context_length_exceeded(text: &str) -> bool { let check_phrases = [ "too long", diff --git a/crates/goose/src/providers/utils_universal_openai_stream.rs b/crates/goose/src/providers/utils_universal_openai_stream.rs index 1025e0bf7cd3..38f1aab35e25 100644 --- a/crates/goose/src/providers/utils_universal_openai_stream.rs +++ b/crates/goose/src/providers/utils_universal_openai_stream.rs @@ -275,7 +275,9 @@ data: [DONE] if !line.starts_with("data: ") { continue; } - let payload = &line[6..]; + let Some(payload) = line.get(6..) else { + continue; + }; if payload == "[DONE]" { break; } @@ -325,7 +327,9 @@ data: [DONE] if !line.starts_with("data: ") { continue; } - let payload = &line[6..]; + let Some(payload) = line.get(6..) else { + continue; + }; if payload == "[DONE]" { break; } @@ -377,7 +381,9 @@ data: [DONE] if !line.starts_with("data: ") { continue; } - let payload = &line[6..]; + let Some(payload) = line.get(6..) else { + continue; + }; if payload == "[DONE]" { break; } diff --git a/scripts/test_providers.sh b/scripts/test_providers.sh index ae31e40ebac7..c4261d75c14c 100755 --- a/scripts/test_providers.sh +++ b/scripts/test_providers.sh @@ -51,7 +51,7 @@ for provider_config in "${PROVIDERS[@]}"; do echo "Model: ${MODEL}" echo "" TMPFILE=$(mktemp) - (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --text "please list files in the current directory" --with-builtin developer,autovisualiser,computercontroller,tutorial 2>&1) | tee "$TMPFILE" + (cd "$TESTDIR" && "$SCRIPT_DIR/target/release/goose" run --text "please list files in the current directory" --with-builtin developer,autovisualiser,computercontroller,tutorial,todo,extensionmanager 2>&1) | tee "$TMPFILE" echo "" if grep -q "shell | developer" "$TMPFILE"; then echo "✓ SUCCESS: Test passed - developer tool called" From fd65c8b3da55d5819e56a0449b7b80e07acb4cc6 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 5 Nov 2025 06:54:42 -0500 Subject: [PATCH 089/121] automate more of the release process (#5409) Signed-off-by: fbalicchia --- .../generate-release-pr-body/action.yaml | 44 ++++++ .../pr_body_template.txt | 19 +++ .github/workflows/check-release-pr.yaml | 57 +++++++ .github/workflows/create-release-pr.yaml | 82 ++++++++++ .../workflows/merge-release-pr-on-tag.yaml | 148 ++++++++++++++++++ .github/workflows/minor-release.yaml | 16 ++ .github/workflows/patch-release.yaml | 20 +++ .github/workflows/update-release-pr.yaml | 65 ++++++++ Justfile | 6 + 9 files changed, 457 insertions(+) create mode 100644 .github/actions/generate-release-pr-body/action.yaml create mode 100644 .github/actions/generate-release-pr-body/pr_body_template.txt create mode 100644 .github/workflows/check-release-pr.yaml create mode 100644 .github/workflows/create-release-pr.yaml create mode 100644 .github/workflows/merge-release-pr-on-tag.yaml create mode 100644 .github/workflows/minor-release.yaml create mode 100644 .github/workflows/patch-release.yaml create mode 100644 .github/workflows/update-release-pr.yaml diff --git a/.github/actions/generate-release-pr-body/action.yaml b/.github/actions/generate-release-pr-body/action.yaml new file mode 100644 index 000000000000..72ccd754e382 --- /dev/null +++ b/.github/actions/generate-release-pr-body/action.yaml @@ -0,0 +1,44 @@ +name: 'Generate Release Notes' +description: 'Generate release notes for a given version' + +inputs: + version: + description: 'The version being released' + required: true + head_ref: + description: 'The commit SHA or reference of the head of the release branch' + required: true + prior_ref: + description: 'The previous version to compare against' + required: true + +outputs: + pr_body_file: + description: 'Path to the generated PR body file' + value: ${{ steps.generate.outputs.pr_body_file }} + +runs: + using: 'composite' + steps: + - name: Generate release notes + id: generate + shell: bash + env: + VERSION: ${{ inputs.version }} + HEAD_REF: ${{ inputs.head_ref }} + PRIOR_REF: ${{ inputs.prior_ref }} + TEMPLATE_FILE: "${{ github.action_path }}/pr_body_template.txt" + run: | + git fetch origin --tags + + { + sed -e "s/{{VERSION}}/${VERSION}/g" \ + -e "s/{{PRIOR_VERSION}}/${PRIOR_REF}/g" \ + "$TEMPLATE_FILE" + git log --pretty=format:"- %s (%h)" --reverse ${PRIOR_REF}..${HEAD_REF} + echo "" + echo "---" + echo "*This release PR was generated automatically.*" + } > pr_body.txt + + echo "pr_body_file=pr_body.txt" >> $GITHUB_OUTPUT diff --git a/.github/actions/generate-release-pr-body/pr_body_template.txt b/.github/actions/generate-release-pr-body/pr_body_template.txt new file mode 100644 index 000000000000..e63e7c2041f7 --- /dev/null +++ b/.github/actions/generate-release-pr-body/pr_body_template.txt @@ -0,0 +1,19 @@ +# Release v{{VERSION}} + +## How to Release + +Push the release tag to trigger the release: + ```bash + git fetch && git tag v{{VERSION}} origin/release/{{VERSION}} + git push origin v{{VERSION}} + ``` +This PR will auto-merge once the tag is pushed. + +## Important Notes + +- All commits in this release should have corresponding cherry-picks in `main` +- This PR can be closed if the release is not needed. + +## Changes in This Release + +**Comparing:** `{{PRIOR_VERSION}}...v{{VERSION}}` diff --git a/.github/workflows/check-release-pr.yaml b/.github/workflows/check-release-pr.yaml new file mode 100644 index 000000000000..d5462ee41749 --- /dev/null +++ b/.github/workflows/check-release-pr.yaml @@ -0,0 +1,57 @@ +name: Check Release PR + +on: + pull_request: + types: + - opened + - synchronize + branches: + - main + +jobs: + check-commits: + runs-on: ubuntu-latest + if: startsWith(github.head_ref, 'release/') + steps: + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 + + - name: Check all PR commits exist in main + run: | + git fetch origin main + + CHERRY_OUTPUT=$(git cherry origin/main HEAD) + + if [ -z "$CHERRY_OUTPUT" ]; then + echo "✅ All commits already exist in main" + exit 0 + fi + + echo "Cherry check results:" + echo "$CHERRY_OUTPUT" + + MISSING_COMMITS=$(echo "$CHERRY_OUTPUT" | grep '^+' | cut -d' ' -f2) + + if [ -z "$MISSING_COMMITS" ]; then + echo "✅ All commits exist in main" + exit 0 + fi + + COMMIT_COUNT=$(echo "$MISSING_COMMITS" | wc -l) + FIRST_COMMIT=$(git rev-list --reverse HEAD ^origin/main | head -1) + + if [ "$COMMIT_COUNT" -eq 1 ] && echo "$MISSING_COMMITS" | grep -q "$FIRST_COMMIT"; then + echo "✅ Only version bump commit is unique" + git log --oneline -1 "$FIRST_COMMIT" + else + echo "❌ Found commits that should exist in main:" + for commit in $MISSING_COMMITS; do + if [ "$commit" != "$FIRST_COMMIT" ]; then + git log --oneline -1 "$commit" + fi + done + echo "Make sure commits have equivalents in main. If you've since updated main, re-run this job" + exit 1 + fi diff --git a/.github/workflows/create-release-pr.yaml b/.github/workflows/create-release-pr.yaml new file mode 100644 index 000000000000..7208f4e2280a --- /dev/null +++ b/.github/workflows/create-release-pr.yaml @@ -0,0 +1,82 @@ +name: Release Workflow + +on: + workflow_call: + inputs: + bump_type: + description: 'Type of version bump (minor or patch)' + required: true + type: string + target_branch: + description: 'Target branch for the pull request' + required: false + type: string + default: 'main' + +permissions: + contents: write + pull-requests: write + +jobs: + create-release: + runs-on: ubuntu-latest + env: + BUMP_TYPE: ${{ inputs.bump_type }} + TARGET_BRANCH: ${{ inputs.target_branch }} + + steps: + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + ref: ${{ inputs.target_branch }} + fetch-depth: 0 # to generate complete release log + + - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + + - name: Validate input and set old version + run: | + if [[ "$BUMP_TYPE" != "minor" && "$BUMP_TYPE" != "patch" ]]; then + echo "Error: bump_type must be 'minor' or 'patch'" + exit 1 + fi + + - name: create release branch + run: | + PRIOR_VERSION=$(just get-tag-version) + if [[ "$BUMP_TYPE" == "minor" ]]; then + VERSION=$(just get-next-minor-version) + else + VERSION=$(just get-next-patch-version) + fi + + echo "prior_ref=v$PRIOR_VERSION" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_ENV + echo "Version: $VERSION" + + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + just prepare-release $VERSION + BRANCH_NAME=$(git branch --show-current) + echo "branch_name=$BRANCH_NAME" >> $GITHUB_ENV + echo "Branch: $BRANCH_NAME" + + - name: push release branch + run: | + git push origin "${{ env.branch_name }}" + + - name: Generate release notes + uses: ./.github/actions/generate-release-pr-body + with: + version: ${{ env.version }} + head_ref: ${{ github.event.pull_request.head.sha || github.sha }} + prior_ref: ${{ env.prior_ref }} + + - name: Create Pull Request + run: | + gh pr create \ + -B "$TARGET_BRANCH" \ + -H "${{ env.branch_name }}" \ + --title "chore(release): release version ${{ env.version }} ($BUMP_TYPE)" \ + --body-file pr_body.txt + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/merge-release-pr-on-tag.yaml b/.github/workflows/merge-release-pr-on-tag.yaml new file mode 100644 index 000000000000..cbf122f7c55c --- /dev/null +++ b/.github/workflows/merge-release-pr-on-tag.yaml @@ -0,0 +1,148 @@ +name: Merge release PR on tag push + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + +permissions: + actions: write + contents: write + pull-requests: write + checks: read + +jobs: + trigger-patch-release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + + - name: Extract version from tag + id: version + env: + TAG: ${{ github.ref_name }} + run: | + VERSION=${TAG#v} + BRANCH="release/${VERSION}" + + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "branch=${BRANCH}" >> $GITHUB_OUTPUT + + echo "Tag: ${TAG}" + echo "Version: ${VERSION}" + echo "Expected branch: ${BRANCH}" + + - name: Find matching PR + id: find_pr + env: + GH_TOKEN: ${{ github.token }} + BRANCH: ${{ steps.version.outputs.branch }} + run: | + PR_NUMBER=$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number // empty') + + if [ -z "$PR_NUMBER" ]; then + echo "❌ No open PR found for branch: $BRANCH" + echo "pr_found=false" >> $GITHUB_OUTPUT + exit 1 + else + echo "✅ Found PR #$PR_NUMBER for branch: $BRANCH" + echo "pr_found=true" >> $GITHUB_OUTPUT + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + fi + + - name: Get PR details and check status + if: steps.find_pr.outputs.pr_found == 'true' + id: pr_status + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ steps.find_pr.outputs.pr_number }} + run: | + PR_DATA=$(gh pr view $PR_NUMBER --json title,headRefName,baseRefName,mergeable,statusCheckRollup) + + TITLE=$(echo "$PR_DATA" | jq -r '.title') + HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') + BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') + MERGEABLE=$(echo "$PR_DATA" | jq -r '.mergeable') + + echo "PR Title: $TITLE" + echo "Head Branch: $HEAD_BRANCH" + echo "Base Branch: $BASE_BRANCH" + echo "Mergeable: $MERGEABLE" + + if [ "$MERGEABLE" != "MERGEABLE" ]; then + echo "❌ PR is not in a mergeable state: $MERGEABLE" + echo "can_merge=false" >> $GITHUB_OUTPUT + echo "merge_reason=PR is not mergeable (state: $MERGEABLE)" >> $GITHUB_OUTPUT + exit 0 + fi + + STATUS_CHECKS=$(echo "$PR_DATA" | jq -r '.statusCheckRollup[]? | select(.conclusion != null) | "\(.context): \(.conclusion)"') + FAILED_CHECKS=$(echo "$PR_DATA" | jq -r '.statusCheckRollup[]? | select(.conclusion == "FAILURE" or .conclusion == "CANCELLED" or .conclusion == "TIMED_OUT") | .context') + PENDING_CHECKS=$(echo "$PR_DATA" | jq -r '.statusCheckRollup[]? | select(.conclusion == null) | .context') + + echo "Status checks:" + if [ -n "$STATUS_CHECKS" ]; then + echo "$STATUS_CHECKS" + else + echo "No status checks found" + fi + + if [ -n "$FAILED_CHECKS" ]; then + echo "❌ Failed checks found:" + echo "$FAILED_CHECKS" + echo "can_merge=false" >> $GITHUB_OUTPUT + echo "merge_reason=Some checks are failing" >> $GITHUB_OUTPUT + exit 0 + fi + + if [ -n "$PENDING_CHECKS" ]; then + echo "⏳ Pending checks found:" + echo "$PENDING_CHECKS" + echo "can_merge=false" >> $GITHUB_OUTPUT + echo "merge_reason=Some checks are still pending" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "✅ All checks are passing and PR is ready to merge" + echo "can_merge=true" >> $GITHUB_OUTPUT + + - name: Get branch SHA before merge + if: steps.find_pr.outputs.pr_found == 'true' && steps.pr_status.outputs.can_merge == 'true' + id: branch_info + env: + BRANCH: ${{ steps.version.outputs.branch }} + run: | + git fetch origin + + BRANCH_SHA=$(git rev-parse "origin/$BRANCH") + echo "branch_sha=$BRANCH_SHA" >> $GITHUB_OUTPUT + echo "Branch SHA: $BRANCH_SHA" + + - name: Merge PR + if: steps.find_pr.outputs.pr_found == 'true' && steps.pr_status.outputs.can_merge == 'true' + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ steps.find_pr.outputs.pr_number }} + VERSION: ${{ steps.version.outputs.version }} + TAG: ${{ steps.version.outputs.tag }} + run: | + gh pr merge $PR_NUMBER --squash --delete-branch --subject "Release $VERSION" --body "Auto-merged release PR after tag $TAG was pushed" + + - name: Restore branch + if: steps.find_pr.outputs.pr_found == 'true' && steps.pr_status.outputs.can_merge == 'true' + env: + BRANCH: ${{ steps.version.outputs.branch }} + BRANCH_SHA: ${{ steps.branch_info.outputs.branch_sha }} + run: | + git checkout -b "$BRANCH" "$BRANCH_SHA" + git push origin "$BRANCH" + + - name: Trigger patch release + env: + BRANCH: ${{ steps.version.outputs.branch }} + GH_TOKEN: ${{ github.token }} + run: | + gh workflow run patch-release.yaml \ + --field target_branch=$BRANCH diff --git a/.github/workflows/minor-release.yaml b/.github/workflows/minor-release.yaml new file mode 100644 index 000000000000..99ce40a43932 --- /dev/null +++ b/.github/workflows/minor-release.yaml @@ -0,0 +1,16 @@ +name: Create Minor Release PR + +permissions: + contents: write + pull-requests: write + +on: + schedule: + - cron: '0 0 * * 2' + workflow_dispatch: + +jobs: + release: + uses: ./.github/workflows/create-release-pr.yaml + with: + bump_type: "minor" diff --git a/.github/workflows/patch-release.yaml b/.github/workflows/patch-release.yaml new file mode 100644 index 000000000000..29ed3c076093 --- /dev/null +++ b/.github/workflows/patch-release.yaml @@ -0,0 +1,20 @@ +name: Create Patch Release PR + +permissions: + contents: write + pull-requests: write + +on: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch for hotfix' + required: true + type: string + +jobs: + hotfix: + uses: ./.github/workflows/create-release-pr.yaml + with: + bump_type: "patch" + target_branch: ${{ inputs.target_branch }} diff --git a/.github/workflows/update-release-pr.yaml b/.github/workflows/update-release-pr.yaml new file mode 100644 index 000000000000..83a962212d61 --- /dev/null +++ b/.github/workflows/update-release-pr.yaml @@ -0,0 +1,65 @@ +name: Update Release Notes + +on: + pull_request: + types: + - synchronize + branches: + - main + - release/** + +permissions: + contents: read + pull-requests: write + +jobs: + update-release-notes: + runs-on: ubuntu-latest + if: startsWith(github.event.pull_request.head.ref, 'release/') && github.event.pull_request.user.login == 'github-actions[bot]' + steps: + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + fetch-depth: 0 # to generate complete release log + + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4 + with: + ref: ${{ github.base_ref }} + path: './prior-version' + + - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + + - name: Extract version from branch name + env: + REF_NAME: ${{ github.head_ref }} + run: | + BRANCH_NAME="$REF_NAME" + VERSION=$(echo "$BRANCH_NAME" | sed 's/release\///') + echo "version=$VERSION" >> $GITHUB_ENV + echo "Version: $VERSION" + + - name: Get prior version + working-directory: './prior-version' + run: | + PRIOR_VERSION=$(just get-tag-version) + echo "prior_ref=v$PRIOR_VERSION" >> $GITHUB_ENV + + - name: Generate release notes + uses: ./.github/actions/generate-release-pr-body + with: + version: ${{ env.version }} + head_ref: ${{ github.event.pull_request.head.sha }} + prior_ref: ${{ env.prior_ref }} + + - name: Update Pull Request + env: + REF_NAME: ${{ github.head_ref }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head "$REF_NAME" --json number --jq '.[0].number') + + if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then + echo "No PR found for branch $REF_NAME" + exit 1 + fi + + gh pr edit "$PR_NUMBER" --body-file pr_body.txt diff --git a/Justfile b/Justfile index ca22e0cd6f27..515b9b847a8b 100644 --- a/Justfile +++ b/Justfile @@ -268,6 +268,12 @@ validate version: exit 1 fi +get-next-minor-version: + @python -c "import sys; v=sys.argv[1].split('.'); print(f'{v[0]}.{int(v[1])+1}.0')" $(just get-tag-version) + +get-next-patch-version: + @python -c "import sys; v=sys.argv[1].split('.'); print(f'{v[0]}.{v[1]}.{int(v[2])+1}')" $(just get-tag-version) + # set cargo and app versions, must be semver prepare-release version: @just validate {{ version }} || exit 1 From 9a6726608543be1f6402693c10227173b4524361 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 5 Nov 2025 09:15:14 -0500 Subject: [PATCH 090/121] bump to 1.12.0 (#5580) Signed-off-by: fbalicchia --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- ui/desktop/openapi.json | 2 +- ui/desktop/package-lock.json | 4 ++-- ui/desktop/package.json | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f8f79596d96..b84c46478ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2610,7 +2610,7 @@ dependencies = [ [[package]] name = "goose" -version = "1.11.0" +version = "1.12.0" dependencies = [ "ahash", "anyhow", @@ -2691,7 +2691,7 @@ dependencies = [ [[package]] name = "goose-bench" -version = "1.11.0" +version = "1.12.0" dependencies = [ "anyhow", "async-trait", @@ -2714,7 +2714,7 @@ dependencies = [ [[package]] name = "goose-cli" -version = "1.11.0" +version = "1.12.0" dependencies = [ "agent-client-protocol", "anstream", @@ -2766,7 +2766,7 @@ dependencies = [ [[package]] name = "goose-mcp" -version = "1.11.0" +version = "1.12.0" dependencies = [ "anyhow", "async-trait", @@ -2832,7 +2832,7 @@ dependencies = [ [[package]] name = "goose-server" -version = "1.11.0" +version = "1.12.0" dependencies = [ "anyhow", "async-trait", @@ -2869,7 +2869,7 @@ dependencies = [ [[package]] name = "goose-test" -version = "1.11.0" +version = "1.12.0" dependencies = [ "clap", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index d88b69afed98..ca71b1eceae0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ resolver = "2" [workspace.package] edition = "2021" -version = "1.11.0" +version = "1.12.0" authors = ["Block "] license = "Apache-2.0" repository = "https://github.com/block/goose" diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index d4478cbad647..d7412d5bf626 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "Apache-2.0" }, - "version": "1.11.0" + "version": "1.12.0" }, "paths": { "/agent/add_extension": { diff --git a/ui/desktop/package-lock.json b/ui/desktop/package-lock.json index 73f1474fb30a..224643d1b06b 100644 --- a/ui/desktop/package-lock.json +++ b/ui/desktop/package-lock.json @@ -1,12 +1,12 @@ { "name": "goose-app", - "version": "1.11.0", + "version": "1.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "goose-app", - "version": "1.11.0", + "version": "1.12.0", "license": "Apache-2.0", "dependencies": { "@ai-sdk/openai": "^2.0.52", diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 5f946457aadb..386baae08904 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -1,7 +1,7 @@ { "name": "goose-app", "productName": "Goose", - "version": "1.11.0", + "version": "1.12.0", "description": "Goose App", "engines": { "node": "^22.17.1" From 5f492f5abbb28aaa1b8778ac8b25bad9115fdbbe Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Wed, 5 Nov 2025 10:06:40 -0500 Subject: [PATCH 091/121] Keep llm logs in place (#5577) Co-authored-by: Douwe Osinga Signed-off-by: fbalicchia --- crates/goose/src/providers/utils.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/providers/utils.rs b/crates/goose/src/providers/utils.rs index 5da1946a623d..f96b2e1a85d2 100644 --- a/crates/goose/src/providers/utils.rs +++ b/crates/goose/src/providers/utils.rs @@ -1,5 +1,6 @@ use super::base::Usage; use super::errors::GoogleErrorCode; +use crate::config::paths::Paths; use crate::model::ModelConfig; use crate::providers::errors::{OpenAIError, ProviderError}; use anyhow::{anyhow, Result}; @@ -495,7 +496,7 @@ impl RequestLog { where Payload: Serialize, { - let logs_dir = crate::logging::prepare_log_directory("llm", true)?; + let logs_dir = Paths::in_state_dir("logs"); let request_id = Uuid::new_v4(); let temp_name = format!("llm_request.{request_id}.jsonl"); From f0d1b65224375e590e3b670f0741b47888592317 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 5 Nov 2025 10:09:10 -0500 Subject: [PATCH 092/121] Add uv for uvx in Justfile (#5581) Signed-off-by: fbalicchia --- .github/workflows/create-release-pr.yaml | 1 + .github/workflows/update-release-pr.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/create-release-pr.yaml b/.github/workflows/create-release-pr.yaml index 7208f4e2280a..5d9047ab2e75 100644 --- a/.github/workflows/create-release-pr.yaml +++ b/.github/workflows/create-release-pr.yaml @@ -31,6 +31,7 @@ jobs: fetch-depth: 0 # to generate complete release log - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 - name: Validate input and set old version run: | diff --git a/.github/workflows/update-release-pr.yaml b/.github/workflows/update-release-pr.yaml index 83a962212d61..fc5cc94afe9a 100644 --- a/.github/workflows/update-release-pr.yaml +++ b/.github/workflows/update-release-pr.yaml @@ -27,6 +27,7 @@ jobs: path: './prior-version' - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6 - name: Extract version from branch name env: From 210131fef22ea2d7daf95708b70cca5b8f69af45 Mon Sep 17 00:00:00 2001 From: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com> Date: Wed, 5 Nov 2025 10:56:17 -0500 Subject: [PATCH 093/121] fix: Add schema-aware numeric coercion for MCP tool arguments (#5478) Signed-off-by: fbalicchia --- crates/goose/src/agents/reply_parts.rs | 90 +++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/crates/goose/src/agents/reply_parts.rs b/crates/goose/src/agents/reply_parts.rs index 86cb8095c472..99fa94806bbd 100644 --- a/crates/goose/src/agents/reply_parts.rs +++ b/crates/goose/src/agents/reply_parts.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use async_stream::try_stream; use futures::stream::StreamExt; +use serde_json::{json, Value}; use tracing::debug; use super::super::agents::Agent; @@ -19,6 +20,79 @@ use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents; use crate::session::SessionManager; use rmcp::model::Tool; +fn coerce_value(s: &str, schema: &Value) -> Value { + let type_str = schema.get("type"); + + match type_str { + Some(Value::String(t)) => match t.as_str() { + "number" | "integer" => try_coerce_number(s), + "boolean" => try_coerce_boolean(s), + _ => Value::String(s.to_string()), + }, + Some(Value::Array(types)) => { + // Try each type in order + for t in types { + if let Value::String(type_name) = t { + match type_name.as_str() { + "number" | "integer" if s.parse::().is_ok() => { + return try_coerce_number(s) + } + "boolean" if matches!(s.to_lowercase().as_str(), "true" | "false") => { + return try_coerce_boolean(s) + } + _ => continue, + } + } + } + Value::String(s.to_string()) + } + _ => Value::String(s.to_string()), + } +} + +fn try_coerce_number(s: &str) -> Value { + if let Ok(n) = s.parse::() { + if n.fract() == 0.0 && n >= i64::MIN as f64 && n <= i64::MAX as f64 { + json!(n as i64) + } else { + json!(n) + } + } else { + Value::String(s.to_string()) + } +} + +fn try_coerce_boolean(s: &str) -> Value { + match s.to_lowercase().as_str() { + "true" => json!(true), + "false" => json!(false), + _ => Value::String(s.to_string()), + } +} + +fn coerce_tool_arguments( + arguments: Option>, + tool_schema: &Value, +) -> Option> { + let args = arguments?; + + let properties = tool_schema.get("properties").and_then(|p| p.as_object())?; + + let mut coerced = serde_json::Map::new(); + + for (key, value) in args.iter() { + let coerced_value = + if let (Value::String(s), Some(prop_schema)) = (value, properties.get(key)) { + coerce_value(s, prop_schema) + } else { + value.clone() + }; + coerced.insert(key.clone(), coerced_value); + } + + Some(coerced) +} + async fn toolshim_postprocess( response: Message, toolshim_tools: &[Tool], @@ -190,13 +264,25 @@ impl Agent { &self, response: &Message, ) -> (Vec, Vec, Message) { - // First collect all tool requests + let tools = self.list_tools(None).await; + + // First collect all tool requests with coercion applied let tool_requests: Vec = response .content .iter() .filter_map(|content| { if let MessageContent::ToolRequest(req) = content { - Some(req.clone()) + let mut coerced_req = req.clone(); + + if let Ok(ref mut tool_call) = coerced_req.tool_call { + if let Some(tool) = tools.iter().find(|t| t.name == tool_call.name) { + let schema_value = Value::Object(tool.input_schema.as_ref().clone()); + tool_call.arguments = + coerce_tool_arguments(tool_call.arguments.clone(), &schema_value); + } + } + + Some(coerced_req) } else { None } From f28fade587cfa6febcaa3d4f0930e4c47992400a Mon Sep 17 00:00:00 2001 From: dianed-square <73617011+dianed-square@users.noreply.github.com> Date: Wed, 5 Nov 2025 08:09:35 -0800 Subject: [PATCH 094/121] docs: description required for "Add Extension" in cli (#5573) Signed-off-by: fbalicchia --- .../docs/guides/interactive-chat/mcp-ui.md | 11 +- documentation/docs/mcp/_template_.mdx | 126 +++++++++++------- documentation/docs/mcp/apify-mcp.md | 97 +++++++------- documentation/docs/mcp/container-use-mcp.md | 8 +- documentation/docs/mcp/dev.to-mcp.md | 13 +- documentation/docs/mcp/figma-mcp.md | 17 +-- documentation/docs/mcp/firecrawl-mcp.md | 1 + documentation/docs/mcp/github-mcp.md | 44 +++--- documentation/docs/mcp/gitmcp-mcp.md | 15 ++- documentation/docs/mcp/goose-docs-mcp.md | 35 +++-- documentation/docs/mcp/gotohuman-mcp.md | 37 ++--- documentation/docs/mcp/jetbrains-mcp.md | 30 +++-- documentation/docs/mcp/neon-mcp.md | 18 +-- documentation/docs/mcp/reddit-mcp.md | 11 +- documentation/docs/mcp/rube-mcp.md | 7 +- documentation/docs/mcp/vercel-mcp.md | 9 +- .../components/CLIExtensionInstructions.tsx | 20 +-- .../src/components/GooseDesktopInstaller.tsx | 2 +- 18 files changed, 279 insertions(+), 222 deletions(-) diff --git a/documentation/docs/guides/interactive-chat/mcp-ui.md b/documentation/docs/guides/interactive-chat/mcp-ui.md index 60517823f585..8086b1f84a3f 100644 --- a/documentation/docs/guides/interactive-chat/mcp-ui.md +++ b/documentation/docs/guides/interactive-chat/mcp-ui.md @@ -2,7 +2,7 @@ sidebar_position: 1 title: MCP-UI Extensions sidebar_label: MCP-UI Extensions -description: Learn how Goose can render graphical and interactive UI components from MCP-UI-enabled extensions +description: Learn how goose can render graphical and interactive UI components from MCP-UI-enabled extensions --- import Tabs from '@theme/Tabs'; @@ -11,7 +11,7 @@ import GooseDesktopInstaller from '@site/src/components/GooseDesktopInstaller'; import CLIExtensionInstructions from '@site/src/components/CLIExtensionInstructions'; import { PanelLeft } from 'lucide-react'; -Extensions built on MCP-UI allow Goose Desktop to provide interactive and engaging user experiences. Imagine using a graphical, clickable UI instead of reading text responses and typing all your prompts: +Extensions built on MCP-UI allow goose Desktop to provide interactive and engaging user experiences. Imagine using a graphical, clickable UI instead of reading text responses and typing all your prompts: