From 4257610315755ab0495a238f3a04adf0bab86338 Mon Sep 17 00:00:00 2001 From: shiva Date: Mon, 27 Jul 2026 17:24:32 +0530 Subject: [PATCH 01/19] feat(components): auto-enforce core-module usage via init/SessionStart Adds two non-consent components so agentflare init and every SessionStart self-heal the setup needed to actually use flare-docs, flare-search, and lean-ctx through the gateway, instead of relying on hand-run CLI commands: - core-coaching: seeds/refreshes 4 builtin coaching rules (usedocs, usesearch, useleanctx, usetsearch) that nudge the flare gateway's docs/search/lean-ctx/tool-search wrappers over their native equivalents. Drift-protected across version bumps; a same-id rule the user has overridden to a different tier is left alone. - gateway-permissions: keeps ~/.claude/settings.json's permissions.allow containing the flare gateway tools (mcp__flare__docs, mcp__flare__search, mcp__flare__tool, ToolSearch) and strips superseded direct mcp__lean-ctx__* entries. Also widens coaching::store::list_rules to pub(crate) so components.rs can read existing rule state when deciding whether to seed or refresh. --- src/coaching/mod.rs | 8 +- src/coaching/store.rs | 2 +- src/components.rs | 350 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+), 5 deletions(-) diff --git a/src/coaching/mod.rs b/src/coaching/mod.rs index af492d20..0fcb096c 100644 --- a/src/coaching/mod.rs +++ b/src/coaching/mod.rs @@ -20,11 +20,11 @@ pub use store::{ rule_bodies_for_prompt, rule_bodies_for_tool, superseded_bodies, sync_targets_for_host, untriggered_rule_bodies, }; +pub(crate) use store::list_rules; -// Only reached from hook.rs's SessionStart test (#[cfg(test)]), to seed a -// rule before asserting it appears in the printed message — a plain, -// non-test build has no caller for it. -#[allow(unused_imports)] +// Also used by components.rs to seed/refresh the built-in core-module +// coaching rules (flare-docs, flare-search, lean-ctx, tool-search) on every +// `agentflare init` and SessionStart. pub use store::apply_rule; #[cfg(test)] diff --git a/src/coaching/store.rs b/src/coaching/store.rs index 31924d2f..a2710526 100644 --- a/src/coaching/store.rs +++ b/src/coaching/store.rs @@ -56,7 +56,7 @@ impl Drop for RulesLock { /// List all coaching rules from the rules directory, sorted by id. Returns /// an empty vec if the directory doesn't exist or can't be read. -pub(super) fn list_rules() -> Vec { +pub(crate) fn list_rules() -> Vec { let dir = rules_dir(); let Ok(entries) = std::fs::read_dir(&dir) else { return Vec::new(); diff --git a/src/components.rs b/src/components.rs index 0175b641..67fbc96c 100644 --- a/src/components.rs +++ b/src/components.rs @@ -373,6 +373,195 @@ fn sync_skill_overrides() -> Result { Ok(added) } +/// The core-module coaching rules agentflare ships by default: nudge the +/// flare gateway's docs/search/lean-ctx/tool-search wrappers over their +/// native equivalents. Builtin tier so `agentflare init` and every +/// non-consent SessionStart (see hook::session_start_message) refresh them +/// if their body drifts from this list; a same-id rule the user has since +/// tagged Override is left alone — override always wins. +struct DefaultCoachingRule { + id: &'static str, + title: &'static str, + body: &'static str, + tools: &'static [&'static str], + sync: &'static [&'static str], +} + +const DEFAULT_COACHING_RULES: &[DefaultCoachingRule] = &[ + DefaultCoachingRule { + id: "usedocs", + title: "flare-docs for package API questions", + body: "@rule: before writing/reviewing code against any package's API, or citing its behavior, check mcp__flare__docs (search|get) \u{2014} do not rely on memory for library API details @ecosystems: rust (docs.rs, default) \u{b7} npm (ecosystem=\"npm\") @fallback: docs tool missing from your list? ToolSearch(\"select:mcp__flare__docs\") first", + tools: &["Edit", "Write"], + sync: &["claude-code"], + }, + DefaultCoachingRule { + id: "usesearch", + title: "flare-search over native web search", + body: "@use: mcp__flare__search (global, 17 sources via type=) \u{2014} type=web for general internet search, plus social/news/github/academic/datasets/code/memory/store/websites/weather/financial/crypto/fx/indicators/youtube/bluesky @skip: WebFetch, WebSearch, websearch-agent, web_search_exa \u{2014} superseded by mcp__flare__search type=web @fallback: Exa MCP tools only for what flare-search has no equivalent for \u{2014} get_code_context_exa, company_research_exa", + tools: &["WebFetch", "WebSearch"], + sync: &["claude-code"], + }, + DefaultCoachingRule { + id: "useleanctx", + title: "lean-ctx over native file/search/shell tools", + body: "@use: lean-ctx over native tools, routed via the flare gateway \u{2014} never call mcp__lean-ctx__* directly. ctx_read>Read/cat, ctx_shell>Bash, ctx_search>Grep, ctx_glob>Glob, ctx_callgraph>grep for \"who calls X\" @call: mcp__flare__tool(action=\"execute\", server=\"leanctx\", tool=\"\", args={...}) for every ctx_* op above @when: unfamiliar code \u{2014} ctx_compose FIRST, one call instead of a search->read->search chain @discover: unsure of a tools args? mcp__flare__tool(action=\"search\", query=\"\") first", + tools: &["Read", "Grep", "Glob", "Bash"], + sync: &["claude-code"], + }, + DefaultCoachingRule { + id: "usetsearch", + title: "flare tool-search over native ToolSearch for gateway tools", + body: "@use: for MCP tools behind the flare gateway (leanctx, docs, search, memory, review, etc.), prefer mcp__flare__tool(action=\"search\", query=\"\") over native ToolSearch \u{2014} it searches downstream servers directly instead of the static deferred-tool list @fallback: native ToolSearch is still right for first-party deferred tools not behind the gateway (WebFetch, EnterPlanMode, mcp__claude-in-chrome__*, etc.)", + tools: &["ToolSearch"], + sync: &["claude-code"], + }, +]; + +/// True if every `DEFAULT_COACHING_RULES` entry either doesn't exist yet +/// (needs seeding), exists with content matching this list (already in +/// sync), or has been overridden by the user (tier Override — left alone). +fn coaching_defaults_satisfied() -> bool { + let existing = crate::coaching::list_rules(); + DEFAULT_COACHING_RULES.iter().all(|d| { + match existing.iter().find(|r| r.id == d.id) { + None => false, + Some(r) if r.tier == crate::coaching::rule::RuleTier::Override => true, + Some(r) => r.body == d.body, + } + }) +} + +/// Seeds any missing `DEFAULT_COACHING_RULES` entry and refreshes any +/// Builtin-tier one whose body has drifted from this list. Never touches a +/// same-id rule the user has overridden (tier Override). +fn apply_coaching_defaults() -> String { + let existing = crate::coaching::list_rules(); + let mut changed = vec![]; + for d in DEFAULT_COACHING_RULES { + if let Some(r) = existing.iter().find(|r| r.id == d.id) + && (r.tier == crate::coaching::rule::RuleTier::Override || r.body == d.body) + { + continue; + } + let trigger = crate::coaching::rule::RuleTrigger { + tools: d.tools.iter().map(|s| s.to_string()).collect(), + auto_match: true, + }; + let sync: Vec = d.sync.iter().map(|s| s.to_string()).collect(); + if crate::coaching::apply_rule( + d.id, + d.title, + d.body, + Some(trigger), + crate::coaching::rule::RuleTier::Builtin, + sync, + ) + .is_ok() + { + changed.push(d.id); + } + } + if changed.is_empty() { + "core-module coaching rules already up to date".to_string() + } else { + format!( + "core-module coaching rules seeded/refreshed: {}", + changed.join(", ") + ) + } +} + +/// Fully-qualified flare-gateway tool names every core-module coaching rule +/// nudges toward. Kept allowlisted in `~/.claude/settings.json` so the +/// nudge doesn't cost a permission prompt on every call. +const GATEWAY_PERMISSIONS_ALLOW: &[&str] = &[ + "mcp__flare__docs", + "mcp__flare__search", + "mcp__flare__tool", + "ToolSearch", +]; + +/// Prefix of direct lean-ctx MCP tool names superseded by routing through +/// `mcp__flare__tool(action="execute", server="leanctx", ...)` instead. +const STALE_LEANCTX_PERMISSION_PREFIX: &str = "mcp__lean-ctx__"; + +/// Adds any missing `GATEWAY_PERMISSIONS_ALLOW` entry to +/// `settings.permissions.allow` and strips any direct `mcp__lean-ctx__*` +/// entry. Returns the number of entries changed. +fn apply_gateway_permissions(settings: &mut Value) -> Result { + if !settings.is_object() { + *settings = serde_json::json!({}); + } + let obj = settings.as_object_mut().expect("just ensured object above"); + let permissions = obj + .entry("permissions") + .or_insert_with(|| serde_json::json!({})); + if !permissions.is_object() { + *permissions = serde_json::json!({}); + } + let perm_obj = permissions + .as_object_mut() + .ok_or("permissions is not an object")?; + let allow = perm_obj + .entry("allow") + .or_insert_with(|| serde_json::json!([])); + let arr = allow + .as_array_mut() + .ok_or("permissions.allow is not an array")?; + + let before = arr.len(); + arr.retain(|v| { + !v.as_str() + .is_some_and(|s| s.starts_with(STALE_LEANCTX_PERMISSION_PREFIX)) + }); + let mut changed = before - arr.len(); + + for name in GATEWAY_PERMISSIONS_ALLOW { + let present = arr.iter().any(|v| v.as_str() == Some(*name)); + if !present { + arr.push(serde_json::json!(*name)); + changed += 1; + } + } + Ok(changed) +} + +/// True if `~/.claude/settings.json` already allowlists every entry in +/// `GATEWAY_PERMISSIONS_ALLOW` and carries no stale direct lean-ctx entry. +fn gateway_permissions_satisfied() -> bool { + let settings = claude_settings(); + let Some(arr) = settings + .get("permissions") + .and_then(|p| p.get("allow")) + .and_then(|a| a.as_array()) + else { + return false; + }; + let has_all = GATEWAY_PERMISSIONS_ALLOW + .iter() + .all(|name| arr.iter().any(|v| v.as_str() == Some(*name))); + let has_stale = arr.iter().any(|v| { + v.as_str() + .is_some_and(|s| s.starts_with(STALE_LEANCTX_PERMISSION_PREFIX)) + }); + has_all && !has_stale +} + +/// Applies `apply_gateway_permissions` to the real `~/.claude/settings.json`, +/// writing back only if something changed. +fn sync_gateway_permissions() -> Result { + let path = claude_settings_path(); + let mut settings = claude_settings(); + let changed = apply_gateway_permissions(&mut settings)?; + if changed > 0 { + if let Some(parent) = path.parent() { + let _ = fs::create_dir_all(parent); + } + write_json_pretty(&path, &settings).map_err(|e| e.to_string())?; + } + Ok(changed) +} pub fn get_components(host: &str) -> Vec { let claude_code_only = host == "claude-code"; let host_owned = host.to_string(); @@ -695,6 +884,34 @@ pub fn get_components(host: &str) -> Vec { }) }, }, + Component { + id: "core-coaching", + needs_consent: false, + describe: "built-in coaching rules nudging flare-docs, flare-search, lean-ctx, and flare tool-search over their native equivalents".to_string(), + check: Box::new(move || !claude_code_only || coaching_defaults_satisfied()), + apply: Box::new(move || { + if !claude_code_only { + return "not applicable for this host".to_string(); + } + apply_coaching_defaults() + }), + }, + Component { + id: "gateway-permissions", + needs_consent: false, + describe: "allowlist the flare gateway tools (mcp__flare__docs, mcp__flare__search, mcp__flare__tool, ToolSearch) in ~/.claude/settings.json and remove superseded direct mcp__lean-ctx__* entries".to_string(), + check: Box::new(move || !claude_code_only || gateway_permissions_satisfied()), + apply: Box::new(move || { + if !claude_code_only { + return "not applicable for this host".to_string(); + } + match sync_gateway_permissions() { + Ok(0) => "gateway permissions already up to date".to_string(), + Ok(n) => format!("gateway permissions updated ({n} change(s))"), + Err(e) => format!("gateway permissions sync failed: {e}"), + } + }), + }, ]; // Gated behind the `skill-overrides-sync` cargo feature (off by @@ -766,6 +983,8 @@ mod tests { "leanctx", "agentflare-mcp", "optimize-code-mode", + "core-coaching", + "gateway-permissions", ]; #[cfg(feature = "skill-overrides-sync")] let expected: Vec<&str> = vec![ @@ -777,6 +996,8 @@ mod tests { "leanctx", "agentflare-mcp", "optimize-code-mode", + "core-coaching", + "gateway-permissions", "skill-overrides-sync", ]; @@ -1289,4 +1510,133 @@ mod tests { assert!((guard.check)()); }); } + + #[test] + fn apply_gateway_permissions_adds_missing_and_strips_stale_leanctx() { + let mut settings = serde_json::json!({ + "permissions": { + "allow": ["mcp__lean-ctx__ctx_read", "mcp__flare__docs"] + } + }); + let changed = apply_gateway_permissions(&mut settings).unwrap(); + assert_eq!(changed, 4, "3 missing entries added + 1 stale entry stripped"); + let allow = settings["permissions"]["allow"].as_array().unwrap(); + for name in GATEWAY_PERMISSIONS_ALLOW { + assert!( + allow.iter().any(|v| v.as_str() == Some(*name)), + "expected {name} in permissions.allow" + ); + } + assert!( + allow + .iter() + .all(|v| !v.as_str().unwrap().starts_with(STALE_LEANCTX_PERMISSION_PREFIX)), + "no direct mcp__lean-ctx__* entry should remain" + ); + } + + #[test] + fn apply_gateway_permissions_is_idempotent_once_satisfied() { + let mut settings = serde_json::json!({}); + apply_gateway_permissions(&mut settings).unwrap(); + let changed = apply_gateway_permissions(&mut settings).unwrap(); + assert_eq!(changed, 0, "second pass over already-correct settings changes nothing"); + } + + #[test] + fn gateway_permissions_component_check_then_apply_then_check() { + crate::paths::test_support::with_temp_home(|| { + let components = get_components("claude-code"); + let gw = components + .iter() + .find(|c| c.id == "gateway-permissions") + .unwrap(); + assert!(!(gw.check)(), "fresh temp home has no settings.json yet"); + (gw.apply)(); + assert!((gw.check)(), "should be satisfied immediately after apply"); + }); + } + + #[test] + fn gateway_permissions_is_satisfied_for_non_claude_code_hosts() { + crate::paths::test_support::with_temp_home(|| { + let components = get_components("opencode"); + let gw = components + .iter() + .find(|c| c.id == "gateway-permissions") + .unwrap(); + assert!((gw.check)()); + }); + } + + #[test] + fn coaching_defaults_seed_all_four_rules_on_fresh_home() { + crate::paths::test_support::with_temp_home(|| { + assert!(!coaching_defaults_satisfied()); + let summary = apply_coaching_defaults(); + assert!(summary.contains("seeded/refreshed")); + assert!(coaching_defaults_satisfied()); + + let existing = crate::coaching::list_rules(); + for d in DEFAULT_COACHING_RULES { + let r = existing.iter().find(|r| r.id == d.id).unwrap_or_else(|| { + panic!("expected seeded rule '{}'", d.id) + }); + assert_eq!(r.body, d.body); + assert_eq!(r.tier, crate::coaching::rule::RuleTier::Builtin); + } + }); + } + + #[test] + fn coaching_defaults_apply_is_idempotent_once_seeded() { + crate::paths::test_support::with_temp_home(|| { + apply_coaching_defaults(); + let summary = apply_coaching_defaults(); + assert_eq!(summary, "core-module coaching rules already up to date"); + }); + } + + #[test] + fn coaching_defaults_never_overwrite_a_user_override() { + crate::paths::test_support::with_temp_home(|| { + apply_coaching_defaults(); + + let first = DEFAULT_COACHING_RULES.first().unwrap(); + crate::coaching::apply_rule( + first.id, + "my own title", + "my own customized body", + None, + crate::coaching::rule::RuleTier::Override, + vec![], + ) + .unwrap(); + + assert!( + coaching_defaults_satisfied(), + "an Override-tier rule at a default id counts as satisfied" + ); + apply_coaching_defaults(); + + let existing = crate::coaching::list_rules(); + let r = existing.iter().find(|r| r.id == first.id).unwrap(); + assert_eq!(r.body, "my own customized body"); + assert_eq!(r.tier, crate::coaching::rule::RuleTier::Override); + }); + } + + #[test] + fn coaching_defaults_component_check_then_apply_then_check() { + crate::paths::test_support::with_temp_home(|| { + let components = get_components("claude-code"); + let cc = components + .iter() + .find(|c| c.id == "core-coaching") + .unwrap(); + assert!(!(cc.check)()); + (cc.apply)(); + assert!((cc.check)()); + }); + } } From 7447e16028172712126c0f9f094add515ed1de69 Mon Sep 17 00:00:00 2001 From: shiva Date: Mon, 27 Jul 2026 19:27:20 +0530 Subject: [PATCH 02/19] feat(site): add flare-docs documentation site, aube-linked monorepo Adds docs-site/, an Astro Starlight project documenting the flare-docs module (overview, supported languages, MCP tool reference, CLI reference, examples, and a comparison against Context7), reusing the landing page's exact design system (colors, fonts, mono headings) via customCss. site/ and docs-site/ are linked as sibling packages in an aube-workspace.yaml monorepo rooted at the repo root, with mise tasks (install/dev:site/dev:docs/ build:docs/deploy/tail) as the entry points. The two connect only at deploy time: site's deploy script builds docs-site out-of-tree and copies its output into site/public/docs before wrangler deploy, so day-to-day dev on either package never touches the other. --- .gitignore | 4 + aube-lock.yaml | 4886 ++++++++++++++++++++ aube-workspace.yaml | 6 + docs-site/.gitignore | 3 + docs-site/README.md | 28 + docs-site/astro.config.mjs | 42 + docs-site/package.json | 15 + docs-site/public/favicon.svg | 11 + docs-site/src/assets/logo.svg | 10 + docs-site/src/content.config.ts | 7 + docs-site/src/content/docs/cli.md | 62 + docs-site/src/content/docs/compare.md | 51 + docs-site/src/content/docs/examples.md | 56 + docs-site/src/content/docs/how-it-works.md | 44 + docs-site/src/content/docs/index.mdx | 42 + docs-site/src/content/docs/mcp-tool.md | 27 + docs-site/src/fonts/LICENSE.txt | 90 + docs-site/src/fonts/commit-mono-400.woff2 | Bin 0 -> 48128 bytes docs-site/src/fonts/commit-mono-700.woff2 | Bin 0 -> 47304 bytes docs-site/src/styles/custom.css | 121 + docs-site/tsconfig.json | 5 + mise.toml | 30 + package.json | 11 + site/.gitignore | 4 + site/README.md | 45 +- site/package.json | 4 +- site/public/index.html | 1 + 27 files changed, 5598 insertions(+), 7 deletions(-) create mode 100644 aube-lock.yaml create mode 100644 aube-workspace.yaml create mode 100644 docs-site/.gitignore create mode 100644 docs-site/README.md create mode 100644 docs-site/astro.config.mjs create mode 100644 docs-site/package.json create mode 100644 docs-site/public/favicon.svg create mode 100644 docs-site/src/assets/logo.svg create mode 100644 docs-site/src/content.config.ts create mode 100644 docs-site/src/content/docs/cli.md create mode 100644 docs-site/src/content/docs/compare.md create mode 100644 docs-site/src/content/docs/examples.md create mode 100644 docs-site/src/content/docs/how-it-works.md create mode 100644 docs-site/src/content/docs/index.mdx create mode 100644 docs-site/src/content/docs/mcp-tool.md create mode 100644 docs-site/src/fonts/LICENSE.txt create mode 100644 docs-site/src/fonts/commit-mono-400.woff2 create mode 100644 docs-site/src/fonts/commit-mono-700.woff2 create mode 100644 docs-site/src/styles/custom.css create mode 100644 docs-site/tsconfig.json create mode 100644 mise.toml create mode 100644 package.json diff --git a/.gitignore b/.gitignore index a325fae2..57ebfe77 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,7 @@ # mise tasks are personal dev-workflow shortcuts, not shared project config /.mise.toml /.mise/ + +# aube workspace (site/ + docs-site/) — installed deps, not source. +# aube-lock.yaml IS committed (reproducible installs); node_modules isn't. +node_modules/ diff --git a/aube-lock.yaml b/aube-lock.yaml new file mode 100644 index 00000000..a2f5f29f --- /dev/null +++ b/aube-lock.yaml @@ -0,0 +1,4886 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + docs-site: + dependencies: + '@astrojs/markdown-remark': + specifier: ^7.2.0 + version: 7.2.1 + '@astrojs/starlight': + specifier: ^0.41.4 + version: 0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)) + astro: + specifier: ^7.1.3 + version: 7.1.3(@astrojs/markdown-remark@7.2.1) + + site: + devDependencies: + wrangler: + specifier: ^4 + version: 4.114.0 + +packages: + + '@astrojs/compiler-binding-darwin-arm64@0.3.1': + resolution: {integrity: sha512-IEmEF2fUIlTHtpeE/isyEGVOB14cEyh/LZOFYt6wn3jNyVpdC8aR5OZ+RzFUR/f+8ZDM1LaMwZKvoA7eMyJeFw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@astrojs/compiler-binding-darwin-x64@0.3.1': + resolution: {integrity: sha512-GF2kIxjpPDLsn94zbZNMsxEmkU828QqnmM7kiQJnaooS3jmI+I7kk6+oI6EpwOsK3femCMdcm+wmOsEqtGrmjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@astrojs/compiler-binding-linux-arm64-gnu@0.3.1': + resolution: {integrity: sha512-XJL3SDmOtVrqFhCirNcHwE91+IesJqlgNo23I4qW9QUYfwzm/TBZuH61fgqsb1ttgR1mMYz6ooPWs0JDhwMqpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-arm64-musl@0.3.1': + resolution: {integrity: sha512-xqE8BVbDoBueK/B47w30PtkVofUWJKGkwoMVE+EOMLf11rnoANxIAdA9FPqY+rng4oNI5ndHGsri1yPj2k8vZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-linux-x64-gnu@0.3.1': + resolution: {integrity: sha512-1y0StU1qiCuDFH3rmbRJXcxdfHxFPrES1Rd+RLffosvUR7I2cH5SF5SFnBN9vXpzpkmyElZm3Yr47iJBPN7vVA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-x64-musl@0.3.1': + resolution: {integrity: sha512-16q0fYf7kpbmdObZEeZJEup8hQv/whgNwVjrSvT8umrKwLDSnNIWiQpm09lQQu6bweZB0XyIvHwlPitvJhC+hg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-wasm32-wasi@0.3.1': + resolution: {integrity: sha512-cB456shIwDv/PrVT+2QG7LFndpHkVge5HjqADKZgGaAc9JHVktCtjSrcdkRQ+3tbkPazNKaTLRjXLIiz2NIx9g==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@astrojs/compiler-binding-win32-arm64-msvc@0.3.1': + resolution: {integrity: sha512-ur/9+If/yTE69mmeX5MqSZndL0HOyx67GeNZUy3N7wVdWpLz9UTJXwyWS4UR2PUQHitghjsM5xoX0Ge56WRVQQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@astrojs/compiler-binding-win32-x64-msvc@0.3.1': + resolution: {integrity: sha512-k0W+kDBzDkNZOqu4kElDvCOIbKw5Ut9S1WZ1Krj3KTgNuBERNKXsMMsRLLcbgfdMdbe7bTekQLshZrrvmYpmwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@astrojs/compiler-binding@0.3.1': + resolution: {integrity: sha512-DaAUj29AIBU2XdJ8uwcab8lW5O2pk9pY8AXkcMw0sw77nVa3oeTYRcO+Dvbbpoexf6ThMc0FMWYCQ/wN1/T7oQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@astrojs/compiler-rs@0.3.1': + resolution: {integrity: sha512-aT7xkgsbNoS6nriY5qKpbihK43slFHO41iqgHCTdOvn1ifaQxLCc5yXy+6GzAtiafoaC1zA7OwVXCXMsvUZOkg==} + engines: {node: '>=22.12.0'} + + '@astrojs/internal-helpers@0.10.1': + resolution: {integrity: sha512-5phcroT/vmOOrYuuAxtkbPixy5hePtlz9i8K4OeDv3dNK6/UQRuXPOSRTxIOBbUY5Sonw2UaxjbuVc43Mcir6Q==} + + '@astrojs/markdown-remark@7.2.1': + resolution: {integrity: sha512-jPVNIqTvk+yKviikszv/Y1U4jGUSKpp/Nw48QZV4qjWgp70j4Lkq3lhSDRbWwCfgKvEyO9GHuVbV1dM2WYXy1w==} + + '@astrojs/markdown-satteri@0.3.4': + resolution: {integrity: sha512-6Lvt/bQZEBW+zzdhPblvfZEy5PGEYJaUsUqaCgwHeRPxZJL1gc9I+DRLKWJjjYTWDzVUTzXlMq4WwSK+X34CVw==} + + '@astrojs/mdx@7.0.3': + resolution: {integrity: sha512-RxyIwU0uFam5ftwqKOjpIdhnFxZ/kEikeimLyQy3eGXbHT8WgRGzzesOIHVU8+m9TY8ag5WVOyvV24/GyqPdPQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/markdown-satteri': ^0.3.1 + astro: ^7.0.0 + peerDependenciesMeta: + '@astrojs/markdown-satteri': + optional: true + + '@astrojs/prism@4.0.2': + resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} + engines: {node: '>=22.12.0'} + + '@astrojs/sitemap@3.7.3': + resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==} + + '@astrojs/starlight@0.41.4': + resolution: {integrity: sha512-cRCKZhM2BKYViCakBiN68aVwPn5qj/XtMMq//G54xOWdXXcvic1gMMEI+veNlIKOqqC4QmIjcjk4jiFtlZ3mMg==} + peerDependencies: + '@astrojs/markdown-remark': ^7.2.0 + astro: ^7.0.2 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + + '@astrojs/telemetry@3.3.3': + resolution: {integrity: sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@bruits/satteri-darwin-arm64@0.9.5': + resolution: {integrity: sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==} + cpu: [arm64] + os: [darwin] + + '@bruits/satteri-darwin-x64@0.9.5': + resolution: {integrity: sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==} + cpu: [x64] + os: [darwin] + + '@bruits/satteri-linux-arm64-gnu@0.9.5': + resolution: {integrity: sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-arm64-musl@0.9.5': + resolution: {integrity: sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@bruits/satteri-linux-x64-gnu@0.9.5': + resolution: {integrity: sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-x64-musl@0.9.5': + resolution: {integrity: sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@bruits/satteri-wasm32-wasi@0.9.5': + resolution: {integrity: sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@bruits/satteri-win32-arm64-msvc@0.9.5': + resolution: {integrity: sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==} + cpu: [arm64] + os: [win32] + + '@bruits/satteri-win32-x64-msvc@0.9.5': + resolution: {integrity: sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==} + cpu: [x64] + os: [win32] + + '@capsizecss/unpack@4.0.1': + resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} + engines: {node: '>=18'} + + '@clack/core@1.4.3': + resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.7.0': + resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} + engines: {node: '>= 20.12.0'} + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: '>1.20260305.0 <2.0.0-0' + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20260722.1': + resolution: {integrity: sha512-vZOP8vIS3NwnuaO+gz0FZ7kIGeiO3bZmxV35Ph9zOXKSREhDFlH7wQ7mkCdhW3O4jnXsew+XT7b+DNEI2CcJGQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260722.1': + resolution: {integrity: sha512-EmIQymihDq6WNdER4+LF8Qn80yqayBUpJ+tkOO7wmY8pmgfyXjIUFNXotl21AHovTeu2seR7HdVUgeN/BilCWw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20260722.1': + resolution: {integrity: sha512-jvZ3k9fxcnEn04s80CgIYxQfpOyAiz/8qC42DP8EBa9tR27qWyg9wmm31zIobVlrgBZn/+8NfdP73avRGcQOjQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260722.1': + resolution: {integrity: sha512-BOSB55SMNdy+DA5uj2WirgiNanpHGis5PVvXH1wSfvjRKr4JGgWK+EZzxz0RFUo6QjjQQC/NimEzNZ7va7jmKg==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20260722.1': + resolution: {integrity: sha512-sYM8YgUpKnRz2xjvdJLX1Ojzoi4MlA4gk8WTTExhGydjYB2UTs5NIbv0ZmpKgMoK9io3ixgmiW56ZnTbcWOdiA==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@expressive-code/core@0.44.1': + resolution: {integrity: sha512-3dDo9N8D7hYrLNNMMWFovg3+aDUtnQm7c7z0GZc1c0LEFVBc0Q6lKG+tVT28gDadOvsgOANfCn35fgpe97Pmgg==} + + '@expressive-code/plugin-frames@0.44.1': + resolution: {integrity: sha512-HC/bdRao9225ApcgO/e3jn8ZOhldKO7ob1O/Tcipvtv7Vb5nMphZhMtD9uuywpvxkPYBHJi3504WhrKg05Dwqg==} + + '@expressive-code/plugin-shiki@0.44.1': + resolution: {integrity: sha512-YApiZt3buUzBwL5tqj8G+sYC5NjMjRCHgQwr9bmGl69rtcHy6fE9dooWUeKYB978fJT2BuxT5FeHcF47rA3SEg==} + + '@expressive-code/plugin-text-markers@0.44.1': + resolution: {integrity: sha512-B3BsJoJ8CFMlcIX9f+X9tcI3C4zPDO601+YuLi9GheSTNro7ZfqSjLptMQKBHOWZvxnAtY5zvIX7iO/qtBhNBg==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.2': + resolution: {integrity: sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.2': + resolution: {integrity: sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.2': + resolution: {integrity: sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.1': + resolution: {integrity: sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.1': + resolution: {integrity: sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.1': + resolution: {integrity: sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.1': + resolution: {integrity: sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.1': + resolution: {integrity: sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.1': + resolution: {integrity: sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.1': + resolution: {integrity: sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.1': + resolution: {integrity: sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': + resolution: {integrity: sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + resolution: {integrity: sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.2': + resolution: {integrity: sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.2': + resolution: {integrity: sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.2': + resolution: {integrity: sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.2': + resolution: {integrity: sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.2': + resolution: {integrity: sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.2': + resolution: {integrity: sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.2': + resolution: {integrity: sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.2': + resolution: {integrity: sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.2': + resolution: {integrity: sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==} + engines: {node: '>=20.9.0'} + + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.2': + resolution: {integrity: sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.2': + resolution: {integrity: sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.2': + resolution: {integrity: sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.2': + resolution: {integrity: sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + + '@pagefind/darwin-arm64@1.5.2': + resolution: {integrity: sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==} + cpu: [arm64] + os: [darwin] + + '@pagefind/darwin-x64@1.5.2': + resolution: {integrity: sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==} + cpu: [x64] + os: [darwin] + + '@pagefind/default-ui@1.5.2': + resolution: {integrity: sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg==} + + '@pagefind/freebsd-x64@1.5.2': + resolution: {integrity: sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==} + cpu: [x64] + os: [freebsd] + + '@pagefind/linux-arm64@1.5.2': + resolution: {integrity: sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==} + cpu: [arm64] + os: [linux] + + '@pagefind/linux-x64@1.5.2': + resolution: {integrity: sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==} + cpu: [x64] + os: [linux] + + '@pagefind/windows-arm64@1.5.2': + resolution: {integrity: sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==} + cpu: [arm64] + os: [win32] + + '@pagefind/windows-x64@1.5.2': + resolution: {integrity: sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==} + cpu: [x64] + os: [win32] + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@shikijs/core@4.3.1': + resolution: {integrity: sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.3.1': + resolution: {integrity: sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.3.1': + resolution: {integrity: sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==} + engines: {node: '>=20'} + + '@shikijs/langs@4.3.1': + resolution: {integrity: sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.3.1': + resolution: {integrity: sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==} + engines: {node: '>=20'} + + '@shikijs/themes@4.3.1': + resolution: {integrity: sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==} + engines: {node: '>=20'} + + '@shikijs/types@4.3.1': + resolution: {integrity: sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.17': + resolution: {integrity: sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==} + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.14': + resolution: {integrity: sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + am-i-vibing@0.4.0: + resolution: {integrity: sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==} + hasBin: true + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + astro-expressive-code@0.44.1: + resolution: {integrity: sha512-DT1LnCqbHasBKlvzJ3m6LR4VI94wwx3W9EV/YbP1te4rqjOHsvsezHYuqb5MeLWLftXms/1FA9QBbwCo43DnJQ==} + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0 + + astro@7.1.3: + resolution: {integrity: sha512-4dhPyAAXthf3xLEYnG8SeL7yr/nTPPABfY7e9YF0yuO+vK9Xp+8Q5j4xzsmL3GueukQv4oNwGNTBepLOiDGeJA==} + engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + peerDependencies: + '@astrojs/markdown-remark': 7.2.1 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + + bcp-47@2.1.1: + resolution: {integrity: sha512-KLw+H/gd2p4zly1X7Yh/qziuyae5/w/QFnvTng9eZL5fvszL7Whl3MBoWF8yxL7ksUjBfOD+OxkytiqbBpG+Fw==} + + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-selector-parser@3.3.0: + resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.8.2: + resolution: {integrity: sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + expressive-code@0.44.1: + resolution: {integrity: sha512-GakidxhapWDzpKLqEaFQ8wGk6gAqEtPQibu8+yPBfnDLgev5Vdsh1pasTxnrXL/mzIknyqeTwhMHTghdaiUrTg==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-tsconfig@5.0.0-beta.4: + resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} + engines: {node: '>=20.20.0'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + i18next@26.3.6: + resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} + peerDependencies: + typescript: ^5 || ^6 || ^7 + peerDependenciesMeta: + typescript: + optional: true + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@4.0.0: + resolution: {integrity: sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==} + engines: {node: '>=20'} + hasBin: true + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.3: + resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-directive@3.1.0: + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-directive@4.0.0: + resolution: {integrity: sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + miniflare@4.20260722.0: + resolution: {integrity: sha512-LW6ABMhCx/yIEFBLC/DO4yAhdm2T/G7jp7pr5T2kj895+CCIaHZqpMXdW9O6YE48LcYcCJChwWc8aEs1vpbTXw==} + engines: {node: '>=22.0.0'} + hasBin: true + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@1.0.1: + resolution: {integrity: sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + p-limit@7.3.1: + resolution: {integrity: sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==} + engines: {node: '>=20'} + + p-queue@9.3.3: + resolution: {integrity: sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==} + engines: {node: '>=20'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + + package-manager-detector@1.8.0: + resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} + + pagefind@1.5.2: + resolution: {integrity: sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==} + hasBin: true + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.4: + resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} + engines: {node: '>=4'} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-ancestry@0.1.0: + resolution: {integrity: sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==} + engines: {node: '>=18.0.0'} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-expressive-code@0.44.1: + resolution: {integrity: sha512-+VZgs7Evw4LXRN3owpoBNSTpYuW6GeOdjqcUT1TuY8o/4MGPtbd0EU7Bgrju7X8KrQ6SslOBAuGWJ5fV5TriJQ==} + + rehype-format@5.0.1: + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + rehype@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-directive@4.0.0: + resolution: {integrity: sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.3: + resolution: {integrity: sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + satteri@0.9.5: + resolution: {integrity: sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.35.2: + resolution: {integrity: sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==} + engines: {node: '>=20.9.0'} + + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + shiki@4.3.1: + resolution: {integrity: sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==} + engines: {node: '>=20'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sitemap@9.0.1: + resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==} + engines: {node: '>=20.19.5', npm: '>=10.8.2'} + hasBin: true + + smol-toml@1.7.1: + resolution: {integrity: sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stream-replace-string@2.0.0: + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + svgo@4.0.2: + resolution: {integrity: sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==} + engines: {node: '>=16'} + hasBin: true + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyclip@0.1.15: + resolution: {integrity: sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==} + engines: {node: ^16.14.0 || >= 17.3.0} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + ultrahtml@1.7.0: + resolution: {integrity: sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unstorage@1.17.5: + resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + url-extras@0.1.0: + resolution: {integrity: sha512-8tzwTeXFPuX/5PHuCDQE5Dd9Ts4rwoq2t9aIT+HS4iAVpmj5l4Ao7Q+BuuFjvWRqrLswBhQDk8O96ZicgCqQqw==} + engines: {node: '>=20'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@8.1.5: + resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + workerd@1.20260722.1: + resolution: {integrity: sha512-NycKuc1x2onvsRfGGpM093vRlLFU2zHDAM0+APpccfg4+gZxDGCH27RmdDvkeBuoZyYqgLo3oAfF6re4mvC3vQ==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.114.0: + resolution: {integrity: sha512-M65P25t5UHA1TIJfgZXDcj+YzVobgKdRguM2QPz0xnxLFuOcuE3ErgllDht0iaho7MS4o0g/Bb4YK2+GT+bibg==} + engines: {node: '>=22.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^5.20260722.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@astrojs/compiler-binding-darwin-arm64@0.3.1': + optional: true + + '@astrojs/compiler-binding-darwin-x64@0.3.1': + optional: true + + '@astrojs/compiler-binding-linux-arm64-gnu@0.3.1': + optional: true + + '@astrojs/compiler-binding-linux-arm64-musl@0.3.1': + optional: true + + '@astrojs/compiler-binding-linux-x64-gnu@0.3.1': + optional: true + + '@astrojs/compiler-binding-linux-x64-musl@0.3.1': + optional: true + + '@astrojs/compiler-binding-wasm32-wasi@0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@astrojs/compiler-binding-win32-arm64-msvc@0.3.1': + optional: true + + '@astrojs/compiler-binding-win32-x64-msvc@0.3.1': + optional: true + + '@astrojs/compiler-binding@0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + optionalDependencies: + '@astrojs/compiler-binding-darwin-arm64': 0.3.1 + '@astrojs/compiler-binding-darwin-x64': 0.3.1 + '@astrojs/compiler-binding-linux-arm64-gnu': 0.3.1 + '@astrojs/compiler-binding-linux-arm64-musl': 0.3.1 + '@astrojs/compiler-binding-linux-x64-gnu': 0.3.1 + '@astrojs/compiler-binding-linux-x64-musl': 0.3.1 + '@astrojs/compiler-binding-wasm32-wasi': 0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@astrojs/compiler-binding-win32-arm64-msvc': 0.3.1 + '@astrojs/compiler-binding-win32-x64-msvc': 0.3.1 + + '@astrojs/compiler-rs@0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@astrojs/compiler-binding': 0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + + '@astrojs/internal-helpers@0.10.1': + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + js-yaml: 4.3.0 + picomatch: 4.0.5 + retext-smartypants: 6.2.0 + shiki: 4.3.1 + smol-toml: 1.7.1 + unified: 11.0.5 + + '@astrojs/markdown-remark@7.2.1': + dependencies: + '@astrojs/internal-helpers': 0.10.1 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.3 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/markdown-satteri@0.3.4': + dependencies: + '@astrojs/internal-helpers': 0.10.1 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + satteri: 0.9.5 + + '@astrojs/mdx@7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.3(@astrojs/markdown-remark@7.2.1))': + dependencies: + '@astrojs/internal-helpers': 0.10.1 + '@astrojs/markdown-remark': 7.2.1 + '@astrojs/markdown-satteri': 0.3.4 + '@mdx-js/mdx': 3.1.1 + acorn: 8.17.0 + astro: 7.1.3(@astrojs/markdown-remark@7.2.1) + es-module-lexer: 2.3.1 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.3 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@4.0.2': + dependencies: + prismjs: 1.30.0 + + '@astrojs/sitemap@3.7.3': + dependencies: + sitemap: 9.0.1 + stream-replace-string: 2.0.0 + zod: 4.4.3 + + '@astrojs/starlight@0.41.4(@astrojs/markdown-remark@7.2.1)(astro@7.1.3(@astrojs/markdown-remark@7.2.1))': + dependencies: + '@astrojs/markdown-remark': 7.2.1 + '@astrojs/markdown-satteri': 0.3.4 + '@astrojs/mdx': 7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.3(@astrojs/markdown-remark@7.2.1)) + '@astrojs/sitemap': 3.7.3 + '@pagefind/default-ui': 1.5.2 + '@types/hast': 3.0.5 + '@types/js-yaml': 4.0.9 + '@types/mdast': 4.0.4 + astro: 7.1.3(@astrojs/markdown-remark@7.2.1) + astro-expressive-code: 0.44.1(astro@7.1.3(@astrojs/markdown-remark@7.2.1)) + bcp-47: 2.1.1 + hast-util-from-html: 2.0.3 + hast-util-select: 6.0.4 + hast-util-to-string: 3.0.1 + hastscript: 9.0.1 + i18next: 26.3.6 + js-yaml: 4.3.0 + klona: 2.0.6 + magic-string: 0.30.21 + mdast-util-directive: 3.1.0 + mdast-util-to-markdown: 2.1.2 + mdast-util-to-string: 4.0.0 + pagefind: 1.5.2 + rehype: 13.0.2 + rehype-format: 5.0.1 + remark-directive: 4.0.0 + satteri: 0.9.5 + ultrahtml: 1.7.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + - typescript + + '@astrojs/telemetry@3.3.3': + dependencies: + ci-info: 4.4.0 + dset: 3.1.4 + is-docker: 4.0.0 + package-manager-detector: 1.8.0 + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bruits/satteri-darwin-arm64@0.9.5': + optional: true + + '@bruits/satteri-darwin-x64@0.9.5': + optional: true + + '@bruits/satteri-linux-arm64-gnu@0.9.5': + optional: true + + '@bruits/satteri-linux-arm64-musl@0.9.5': + optional: true + + '@bruits/satteri-linux-x64-gnu@0.9.5': + optional: true + + '@bruits/satteri-linux-x64-musl@0.9.5': + optional: true + + '@bruits/satteri-wasm32-wasi@0.9.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@bruits/satteri-win32-arm64-msvc@0.9.5': + optional: true + + '@bruits/satteri-win32-x64-msvc@0.9.5': + optional: true + + '@capsizecss/unpack@4.0.1': + dependencies: + fontkitten: 1.0.3 + + '@clack/core@1.4.3': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.7.0': + dependencies: + '@clack/core': 1.4.3 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@cloudflare/kv-asset-handler@0.5.0': {} + + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260722.1)': + dependencies: + unenv: 2.0.0-rc.24 + workerd: 1.20260722.1 + + '@cloudflare/workerd-darwin-64@1.20260722.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20260722.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20260722.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20260722.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20260722.1': + optional: true + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@ctrl/tinycolor@4.2.0': {} + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@expressive-code/core@0.44.1': + dependencies: + '@ctrl/tinycolor': 4.2.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hastscript: 9.0.1 + postcss: 8.5.23 + postcss-nested: 6.2.0(postcss@8.5.23) + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + + '@expressive-code/plugin-frames@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + + '@expressive-code/plugin-shiki@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + shiki: 4.3.1 + + '@expressive-code/plugin-text-markers@0.44.1': + dependencies: + '@expressive-code/core': 0.44.1 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.1 + optional: true + + '@img/sharp-darwin-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.2 + optional: true + + '@img/sharp-darwin-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.1 + optional: true + + '@img/sharp-darwin-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.1': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.1': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.2': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.2': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.1': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.2': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.2': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + optional: true + + '@img/sharp-linux-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.1 + optional: true + + '@img/sharp-linux-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.2 + optional: true + + '@img/sharp-linux-arm@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.1 + optional: true + + '@img/sharp-linux-arm@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.2 + optional: true + + '@img/sharp-linux-ppc64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.1 + optional: true + + '@img/sharp-linux-ppc64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.2 + optional: true + + '@img/sharp-linux-riscv64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.1 + optional: true + + '@img/sharp-linux-riscv64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.2 + optional: true + + '@img/sharp-linux-s390x@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.1 + optional: true + + '@img/sharp-linux-s390x@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.2 + optional: true + + '@img/sharp-linux-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.1 + optional: true + + '@img/sharp-linux-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.2 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.3': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + optional: true + + '@img/sharp-wasm32@0.35.2': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-wasm32@0.35.3': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-win32-arm64@0.35.2': + optional: true + + '@img/sharp-win32-arm64@0.35.3': + optional: true + + '@img/sharp-win32-ia32@0.35.2': + optional: true + + '@img/sharp-win32-ia32@0.35.3': + optional: true + + '@img/sharp-win32-x64@0.35.2': + optional: true + + '@img/sharp-win32-x64@0.35.3': + optional: true + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@mdx-js/mdx@3.1.1': + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdx': 2.0.14 + acorn: 8.17.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.17.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@oslojs/encoding@1.1.0': {} + + '@oxc-project/types@0.139.0': {} + + '@pagefind/darwin-arm64@1.5.2': + optional: true + + '@pagefind/darwin-x64@1.5.2': + optional: true + + '@pagefind/default-ui@1.5.2': {} + + '@pagefind/freebsd-x64@1.5.2': + optional: true + + '@pagefind/linux-arm64@1.5.2': + optional: true + + '@pagefind/linux-x64@1.5.2': + optional: true + + '@pagefind/windows-arm64@1.5.2': + optional: true + + '@pagefind/windows-x64@1.5.2': + optional: true + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@rolldown/binding-android-arm64@1.1.5': + optional: true + + '@rolldown/binding-darwin-arm64@1.1.5': + optional: true + + '@rolldown/binding-darwin-x64@1.1.5': + optional: true + + '@rolldown/binding-freebsd-x64@1.1.5': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.1.5': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.1.5': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.1.5': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.1.5': + optional: true + + '@rolldown/binding-linux-x64-musl@1.1.5': + optional: true + + '@rolldown/binding-openharmony-arm64@1.1.5': + optional: true + + '@rolldown/binding-wasm32-wasi@1.1.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.1.5': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.1.5': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/pluginutils@5.4.0': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.5 + + '@shikijs/core@4.3.1': + dependencies: + '@shikijs/primitive': 4.3.1 + '@shikijs/types': 4.3.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.3.1': + dependencies: + '@shikijs/types': 4.3.1 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.3.1': + dependencies: + '@shikijs/types': 4.3.1 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.3.1': + dependencies: + '@shikijs/types': 4.3.1 + + '@shikijs/primitive@4.3.1': + dependencies: + '@shikijs/types': 4.3.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/themes@4.3.1': + dependencies: + '@shikijs/types': 4.3.1 + + '@shikijs/types@4.3.1': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sindresorhus/is@7.2.0': {} + + '@speed-highlight/core@1.2.17': {} + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/js-yaml@4.0.9': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.14': {} + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@types/sax@1.2.7': + dependencies: + '@types/node': 24.13.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.3': {} + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + am-i-vibing@0.4.0: + dependencies: + process-ancestry: 0.1.0 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + astring@1.9.0: {} + + astro-expressive-code@0.44.1(astro@7.1.3(@astrojs/markdown-remark@7.2.1)): + dependencies: + astro: 7.1.3(@astrojs/markdown-remark@7.2.1) + rehype-expressive-code: 0.44.1 + url-extras: 0.1.0 + + astro@7.1.3(@astrojs/markdown-remark@7.2.1): + dependencies: + '@astrojs/compiler-rs': 0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@astrojs/internal-helpers': 0.10.1 + '@astrojs/markdown-remark': 7.2.1 + '@astrojs/markdown-satteri': 0.3.4 + '@astrojs/telemetry': 3.3.3 + '@capsizecss/unpack': 4.0.1 + '@clack/prompts': 1.7.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.4.0 + am-i-vibing: 0.4.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 2.0.0 + cookie: 2.0.1 + devalue: 5.8.2 + diff: 8.0.4 + dset: 3.1.4 + es-module-lexer: 2.3.1 + esbuild: 0.28.1 + flattie: 1.1.1 + fontace: 0.4.1 + get-tsconfig: 5.0.0-beta.4 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + js-yaml: 4.3.0 + jsonc-parser: 3.3.1 + magic-string: 0.30.21 + magicast: 0.5.3 + mrmime: 2.0.1 + neotraverse: 1.0.1 + obug: 2.1.4 + p-limit: 7.3.1 + p-queue: 9.3.3 + package-manager-detector: 1.8.0 + piccolore: 0.1.3 + picomatch: 4.0.5 + semver: 7.8.5 + shiki: 4.3.1 + smol-toml: 1.7.1 + svgo: 4.0.2 + tinyclip: 0.1.15 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + ultrahtml: 1.7.0 + unifont: 0.7.4 + unstorage: 1.17.5 + vite: 8.1.5(esbuild@0.28.1) + vitefu: 1.1.3(vite@8.1.5(esbuild@0.28.1)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.4.3 + optionalDependencies: + sharp: 0.35.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - uploadthing + - yaml + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + bcp-47-match@2.0.3: {} + + bcp-47@2.1.1: + dependencies: + is-alphabetical: 2.0.1 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + + blake3-wasm@2.1.5: {} + + boolbase@1.0.0: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + common-ancestor-path@2.0.0: {} + + cookie-es@1.2.3: {} + + cookie@1.1.1: {} + + cookie@2.0.1: {} + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-selector-parser@3.3.0: {} + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.7: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + devalue@5.8.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.4: {} + + direction@2.0.1: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + error-stack-parser-es@1.0.5: {} + + es-module-lexer@2.3.1: {} + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.17.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escape-string-regexp@5.0.0: {} + + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.9 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + eventemitter3@5.0.4: {} + + expressive-code@0.44.1: + dependencies: + '@expressive-code/core': 0.44.1 + '@expressive-code/plugin-frames': 0.44.1 + '@expressive-code/plugin-shiki': 0.44.1 + '@expressive-code/plugin-text-markers': 0.44.1 + + extend@3.0.2: {} + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + + fdir@6.5.0(picomatch@4.0.5): + dependencies: + picomatch: 4.0.5 + + flattie@1.1.1: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + fsevents@2.3.3: + optional: true + + get-tsconfig@5.0.0-beta.4: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-slugger@2.0.0: {} + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.5 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.2.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.5 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.5 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.3 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.9 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + devlop: 1.1.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.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.5 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.5 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + http-cache-semantics@4.2.0: {} + + i18next@26.3.6: {} + + inline-style-parser@0.2.7: {} + + iron-webcrypto@1.2.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-docker@4.0.0: {} + + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + + js-yaml@4.3.0: + dependencies: + argparse: 2.0.1 + + jsonc-parser@3.3.1: {} + + kleur@4.1.5: {} + + klona@2.0.6: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + longest-streak@3.1.0: {} + + lru-cache@11.5.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.3: + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + source-map-js: 1.2.1 + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-directive@3.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.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.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-directive@4.0.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.9 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.9 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + miniflare@4.20260722.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.35.2 + undici: 7.28.0 + workerd: 1.20260722.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.16: {} + + neotraverse@1.0.1: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.4: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + obug@2.1.4: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.11: {} + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + p-limit@7.3.1: + dependencies: + yocto-queue: 1.2.2 + + p-queue@9.3.3: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-timeout@7.0.1: {} + + package-manager-detector@1.8.0: {} + + pagefind@1.5.2: + optionalDependencies: + '@pagefind/darwin-arm64': 1.5.2 + '@pagefind/darwin-x64': 1.5.2 + '@pagefind/freebsd-x64': 1.5.2 + '@pagefind/linux-arm64': 1.5.2 + '@pagefind/linux-x64': 1.5.2 + '@pagefind/windows-arm64': 1.5.2 + '@pagefind/windows-x64': 1.5.2 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-to-regexp@6.3.0: {} + + pathe@2.0.3: {} + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.5: {} + + postcss-nested@6.2.0(postcss@8.5.23): + dependencies: + postcss: 8.5.23 + postcss-selector-parser: 6.1.4 + + postcss-selector-parser@6.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.23: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prismjs@1.30.0: {} + + process-ancestry@0.1.0: {} + + property-information@7.2.0: {} + + radix3@1.1.2: {} + + readdirp@5.0.0: {} + + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.9 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.9 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.9 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-expressive-code@0.44.1: + dependencies: + expressive-code: 0.44.1 + + rehype-format@5.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-format: 1.1.0 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.5 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.5 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-directive@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-directive: 3.1.0 + micromark-extension-directive: 4.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.3: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + resolve-pkg-maps@1.0.0: {} + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + rolldown@1.1.5: + dependencies: + '@oxc-project/types': 0.139.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 + + satteri@0.9.5: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + optionalDependencies: + '@bruits/satteri-darwin-arm64': 0.9.5 + '@bruits/satteri-darwin-x64': 0.9.5 + '@bruits/satteri-linux-arm64-gnu': 0.9.5 + '@bruits/satteri-linux-arm64-musl': 0.9.5 + '@bruits/satteri-linux-x64-gnu': 0.9.5 + '@bruits/satteri-linux-x64-musl': 0.9.5 + '@bruits/satteri-wasm32-wasi': 0.9.5 + '@bruits/satteri-win32-arm64-msvc': 0.9.5 + '@bruits/satteri-win32-x64-msvc': 0.9.5 + + sax@1.6.1: {} + + semver@7.8.5: {} + + sharp@0.35.2: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.2 + '@img/sharp-darwin-x64': 0.35.2 + '@img/sharp-freebsd-wasm32': 0.35.2 + '@img/sharp-libvips-darwin-arm64': 1.3.1 + '@img/sharp-libvips-darwin-x64': 1.3.1 + '@img/sharp-libvips-linux-arm': 1.3.1 + '@img/sharp-libvips-linux-arm64': 1.3.1 + '@img/sharp-libvips-linux-ppc64': 1.3.1 + '@img/sharp-libvips-linux-riscv64': 1.3.1 + '@img/sharp-libvips-linux-s390x': 1.3.1 + '@img/sharp-libvips-linux-x64': 1.3.1 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 + '@img/sharp-linux-arm': 0.35.2 + '@img/sharp-linux-arm64': 0.35.2 + '@img/sharp-linux-ppc64': 0.35.2 + '@img/sharp-linux-riscv64': 0.35.2 + '@img/sharp-linux-s390x': 0.35.2 + '@img/sharp-linux-x64': 0.35.2 + '@img/sharp-linuxmusl-arm64': 0.35.2 + '@img/sharp-linuxmusl-x64': 0.35.2 + '@img/sharp-webcontainers-wasm32': 0.35.2 + '@img/sharp-win32-arm64': 0.35.2 + '@img/sharp-win32-ia32': 0.35.2 + '@img/sharp-win32-x64': 0.35.2 + + sharp@0.35.3: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + optional: true + + shiki@4.3.1: + dependencies: + '@shikijs/core': 4.3.1 + '@shikijs/engine-javascript': 4.3.1 + '@shikijs/engine-oniguruma': 4.3.1 + '@shikijs/langs': 4.3.1 + '@shikijs/themes': 4.3.1 + '@shikijs/types': 4.3.1 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + sisteransi@1.0.5: {} + + sitemap@9.0.1: + dependencies: + '@types/node': 24.13.3 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.6.1 + + smol-toml@1.7.1: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + stream-replace-string@2.0.0: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + supports-color@10.2.2: {} + + svgo@4.0.2: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.2.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + + tiny-inflate@1.0.3: {} + + tinyclip@0.1.15: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tslib@2.8.1: + optional: true + + ufo@1.6.4: {} + + ultrahtml@1.7.0: {} + + uncrypto@0.1.3: {} + + undici-types@7.18.2: {} + + undici@7.28.0: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.4: + dependencies: + css-tree: 3.2.1 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.5: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.2 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + + url-extras@0.1.0: {} + + util-deprecate@1.0.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@8.1.5(esbuild@0.28.1): + dependencies: + esbuild: 0.28.1 + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.23 + rolldown: 1.1.5 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + + vitefu@1.1.3(vite@8.1.5(esbuild@0.28.1)): + dependencies: + vite: 8.1.5(esbuild@0.28.1) + + web-namespaces@2.0.1: {} + + workerd@1.20260722.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260722.1 + '@cloudflare/workerd-darwin-arm64': 1.20260722.1 + '@cloudflare/workerd-linux-64': 1.20260722.1 + '@cloudflare/workerd-linux-arm64': 1.20260722.1 + '@cloudflare/workerd-windows-64': 1.20260722.1 + + wrangler@4.114.0: + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260722.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.1 + miniflare: 4.20260722.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260722.1 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ws@8.21.0: {} + + xxhash-wasm@1.1.0: {} + + yargs-parser@22.0.0: {} + + yocto-queue@1.2.2: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.17 + cookie: 1.1.1 + youch-core: 0.3.3 + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/aube-workspace.yaml b/aube-workspace.yaml new file mode 100644 index 00000000..a5c7fb6c --- /dev/null +++ b/aube-workspace.yaml @@ -0,0 +1,6 @@ +packages: + - "site" + - "docs-site" +allowBuilds: + esbuild: true + workerd: true diff --git a/docs-site/.gitignore b/docs-site/.gitignore new file mode 100644 index 00000000..dab5dd66 --- /dev/null +++ b/docs-site/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.astro/ +dist/ diff --git a/docs-site/README.md b/docs-site/README.md new file mode 100644 index 00000000..353b4861 --- /dev/null +++ b/docs-site/README.md @@ -0,0 +1,28 @@ +# agentflare docs + +Documentation for agentflare's `flare-docs` module, built with +[Astro Starlight](https://starlight.astro.build). A workspace member of the root +aube-workspace.yaml alongside `../site`, but a standalone project day to day — no +install/build coupling to `../site`; the two connect only at deploy time (see +`../site/README.md#docs-docs`). + +## Develop + +```bash +aube install # or, from the repo root: mise run install +aube dev # or: mise run dev:docs — localhost:4321/docs +``` + +## Build + +```bash +aube build # or: mise run build:docs — -> dist/ +``` + +`base: "/docs"` in `astro.config.mjs` means the build only makes sense mounted at +`agentflare.dev/docs` — `aube preview` serves it that way locally too. + +## Content + +`src/content/docs/*.md` / `*.mdx`. Page order and labels are set in `astro.config.mjs`'s +`sidebar` config, not inferred from the filesystem. diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs new file mode 100644 index 00000000..468c6285 --- /dev/null +++ b/docs-site/astro.config.mjs @@ -0,0 +1,42 @@ +import { defineConfig } from "astro/config"; +import starlight from "@astrojs/starlight"; + +// Independent project, own dev workflow (mise + aube) — see README.md. Built +// with `base: "/docs"` because the output is only ever served mounted at +// agentflare.dev/docs; site/'s deploy step copies dist/ into site/public/docs +// right before `wrangler deploy`. Not built directly into site/ — that's the +// whole point of splitting this out. +export default defineConfig({ + site: "https://agentflare.dev", + base: "/docs", + integrations: [ + starlight({ + title: "agentflare docs", + description: "Documentation for agentflare's flare-docs — always-current package docs for your AI coding agent.", + logo: { + src: "./src/assets/logo.svg", + alt: "agentflare", + }, + social: [{ icon: "github", label: "GitHub", href: "https://github.com/getappz/agentflare" }], + customCss: ["./src/styles/custom.css"], + // Starlight appends the page's full path from the project root itself + // (src/content/docs/...) — baseUrl must stop at the project root. + editLink: { + baseUrl: "https://github.com/getappz/agentflare/edit/master/docs-site/", + }, + sidebar: [ + { + label: "flare-docs", + items: [ + { label: "Overview", slug: "index" }, + { label: "Compare", slug: "compare" }, + { label: "Supported languages", slug: "how-it-works" }, + { label: "Using it from your agent", slug: "mcp-tool" }, + { label: "CLI reference", slug: "cli" }, + { label: "Examples", slug: "examples" }, + ], + }, + ], + }), + ], +}); diff --git a/docs-site/package.json b/docs-site/package.json new file mode 100644 index 00000000..0837d7f5 --- /dev/null +++ b/docs-site/package.json @@ -0,0 +1,15 @@ +{ + "name": "agentflare-docs", + "private": true, + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview" + }, + "dependencies": { + "@astrojs/starlight": "^0.41.4", + "astro": "^7.1.3" + } +} diff --git a/docs-site/public/favicon.svg b/docs-site/public/favicon.svg new file mode 100644 index 00000000..6420703f --- /dev/null +++ b/docs-site/public/favicon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/docs-site/src/assets/logo.svg b/docs-site/src/assets/logo.svg new file mode 100644 index 00000000..7c4e64ab --- /dev/null +++ b/docs-site/src/assets/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs-site/src/content.config.ts b/docs-site/src/content.config.ts new file mode 100644 index 00000000..7fbcf2c3 --- /dev/null +++ b/docs-site/src/content.config.ts @@ -0,0 +1,7 @@ +import { defineCollection } from "astro:content"; +import { docsLoader } from "@astrojs/starlight/loaders"; +import { docsSchema } from "@astrojs/starlight/schema"; + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), +}; diff --git a/docs-site/src/content/docs/cli.md b/docs-site/src/content/docs/cli.md new file mode 100644 index 00000000..4ae51d30 --- /dev/null +++ b/docs-site/src/content/docs/cli.md @@ -0,0 +1,62 @@ +--- +title: CLI reference +description: agentflare docs — search, get, list, and refresh from the command line. +--- + +The same cache backing the MCP `docs` tool is reachable directly from the CLI, under +`agentflare docs`. + +## `agentflare docs search ` + +Search cached documentation. + +```bash +agentflare docs search "serde deserialize" --limit 10 +``` + +| Flag | Default | Notes | +|---|---|---| +| `--limit` | `10` | Capped at 50 | + +## `agentflare docs get ` + +Print a package's docs, reading from cache if present — fetching and storing it +otherwise. + +```bash +agentflare docs get serde --version latest +agentflare docs get hono --ecosystem npm +agentflare docs get @types/node # scoped name -> npm, no --ecosystem needed +agentflare docs get requests --ecosystem python +``` + +| Flag | Default | Notes | +|---|---|---| +| `--version`, `-v` | `latest` | | +| `--ecosystem`, `-e` | inferred | `rust`, `npm`, or `python`. Defaults to `rust` unless the package name is scoped. | + +## `agentflare docs list` + +Lists every cached document (summaries only — see the +[MCP tool reference](/docs/mcp-tool/#list) for the paging shape; the CLI prints the same +JSON the MCP tool returns). + +```bash +agentflare docs list +``` + +## `agentflare docs refresh ` + +Forces a fresh fetch, bypassing the cache — use when a package shipped a new version and +the cached copy is stale. + +```bash +agentflare docs refresh tokio --version 1.42.0 +``` + +Accepts the same `--version` / `--ecosystem` flags as `get`. + +## Exit codes + +A store I/O failure or a fetch error prints to stderr and exits `1`. An unrecognized +`--ecosystem` value exits `2`, distinct from a runtime failure. diff --git a/docs-site/src/content/docs/compare.md b/docs-site/src/content/docs/compare.md new file mode 100644 index 00000000..b0f7585d --- /dev/null +++ b/docs-site/src/content/docs/compare.md @@ -0,0 +1,51 @@ +--- +title: How it compares +description: How flare-docs stacks up against other ways of getting current docs into an AI coding agent. +--- + +`flare-docs` isn't the only tool solving "my agent's training data is out of date." Here's +how it's different from the other common approaches. + +## vs. Context7 + +[Context7](https://context7.com) is the best-known tool for this — a hosted service that +pulls current docs and code examples for a huge range of libraries and languages, and any +AI coding tool can connect to it as an MCP server. + +| | flare-docs | Context7 | +|---|---|---| +| Setup | Built into agentflare — nothing to install | A separate MCP server you add to your agent's config | +| Account required | No | Not for basic use, but you'll need one (with an API key) to get past the lowest rate limits | +| Usage limits | None imposed by flare-docs — you're only bound by docs.rs's/npm's/PyPI's own normal usage | Free tier is capped at a few hundred requests a month, tighter still without an account | +| Where lookups happen | Fetched once, cached locally on your machine | A hosted lookup, typically on every request | +| Works offline | Yes, once a package is cached | No, needs network access | +| Where your queries go | Nowhere but docs.rs/npm/PyPI — no third party sees what you're looking up | Through Context7's hosted service | +| Source of the docs | The primary registry itself — the same rustdoc-JSON `rustdoc` produces, a package's own published TypeScript types, or its own type stubs | Context7's own indexing pipeline across many sources | +| Language coverage | Rust, npm/TypeScript, and Python today | Very broad — most popular languages and frameworks | + +**Where flare-docs wins:** it's already part of your toolchain (nothing extra to install +or authenticate), there's no usage cap to run into mid-project, it works with no network +at all once something's cached, and your lookups never pass through a third party. For a +Rust, npm, or Python project, that adds up to fewer moving parts and nothing that can +rate-limit you or go down on you. + +**Where Context7 wins:** breadth. If you need docs for a language or framework outside +Rust/npm/Python, it's the better — currently the only — choice of the two. + +In short: for Rust, npm, and Python, reach for `flare-docs` first — it's already there +and has no limits to worry about. For everything else, Context7 fills the gap. + +## vs. relying on the model's memory + +The default, if you use neither: your agent writes code based on whatever it remembers +from training. That's fine for stable, long-established APIs, but it's the source of the +classic failure mode — confidently generated code that calls a method that was renamed or +removed two major versions ago. Both `flare-docs` and Context7 exist to fix exactly this. + +## vs. manually searching the web + +Some agents fall back to a general web search when they're unsure. That works, but it's +slower, less precise (search results mix outdated blog posts with current docs), and +gives the agent unstructured HTML to parse instead of the library's actual reference +docs. `flare-docs` fetches the source of truth directly — docs.rs for Rust, a package's +own published types for npm — so there's no guessing which search result is trustworthy. diff --git a/docs-site/src/content/docs/examples.md b/docs-site/src/content/docs/examples.md new file mode 100644 index 00000000..6784666f --- /dev/null +++ b/docs-site/src/content/docs/examples.md @@ -0,0 +1,56 @@ +--- +title: Examples +description: Everyday scenarios for using flare-docs, from the terminal or through your agent. +--- + +## You're about to use a crate you've never touched before + +Ask your agent to use it, and it'll check `flare-docs` on its own before writing code. +Want to see the docs yourself first? + +```bash +agentflare docs get tokio +``` + +## You just bumped a dependency's version + +Your agent's cached copy is now out of date. Tell it to refresh, or do it yourself: + +```bash +agentflare docs refresh reqwest --version 0.13.0 +``` + +## You know roughly what you need, but not the exact package + +```bash +agentflare docs search "http client with retries" +``` + +Searches everything already cached — useful when you're not sure which crate or +package actually provides what you're after. + +## A scoped npm package + +```bash +agentflare docs get @types/node +``` + +No extra flags needed — a scoped name like `@types/node` is always npm. + +## A Python package + +```bash +agentflare docs get requests --ecosystem python +``` + +Python packages always need `--ecosystem python` — unlike npm's `@scope/pkg`, there's +no naming convention that marks a package as Python, so it can't be inferred. + +## Seeing everything you've cached so far + +```bash +agentflare docs list +``` + +Handy for checking what's already available offline before you go somewhere without a +network connection. diff --git a/docs-site/src/content/docs/how-it-works.md b/docs-site/src/content/docs/how-it-works.md new file mode 100644 index 00000000..def24ba0 --- /dev/null +++ b/docs-site/src/content/docs/how-it-works.md @@ -0,0 +1,44 @@ +--- +title: Supported languages +description: Which languages and package registries flare-docs covers, and how it picks between them. +--- + +`flare-docs` currently covers three ecosystems: + +- **Rust** — any crate published on [docs.rs](https://docs.rs). +- **npm** — any package on the npm registry, using its published TypeScript types (or, + for packages that don't ship their own types, the community-maintained + [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) types instead). +- **Python** — any package on PyPI, using its type stubs (or, for packages that don't + ship their own, the community-maintained [typeshed](https://github.com/python/typeshed) + stubs instead). + +## You usually don't need to specify which one + +Most of the time, `flare-docs` figures out the right registry on its own: + +- A scoped package name like `@types/node` or `@babel/core` is always npm — no other + supported registry uses that naming style. +- Everything else defaults to Rust — including Python packages, which have no + comparable naming marker, so an unscoped Python package always needs an explicit + `--ecosystem=python`. + +If you (or your agent) need to be explicit, both the CLI and your agent can pass an +`--ecosystem`/`ecosystem` value of `rust`, `npm`, or `python` — see the +[CLI reference](/docs/cli/) and [Using it from your agent](/docs/mcp-tool/). + +## If you guess wrong + +Looking up a package under the wrong ecosystem doesn't just fail silently — the error +tells you which one to try instead, for example: + +``` +"express" was not found on docs.rs — if it is a Node package, retry with ecosystem="npm"; +if it is a Python package, retry with ecosystem="python" +``` + +## More languages + +Rust, npm, and Python are what's supported today. If you need something else, +[Context7](https://context7.com) covers a much broader range of languages and +frameworks — see [how it compares](/docs/compare/). diff --git a/docs-site/src/content/docs/index.mdx b/docs-site/src/content/docs/index.mdx new file mode 100644 index 00000000..6847f21c --- /dev/null +++ b/docs-site/src/content/docs/index.mdx @@ -0,0 +1,42 @@ +--- +title: flare-docs +description: Always-current package documentation for your AI coding agent — built into agentflare, no setup required. +--- + +If you've ever watched your AI coding agent confidently write code against a library +version that doesn't exist anymore, `flare-docs` is the fix. It's a built-in part of +agentflare that fetches the **real, current documentation** for a package the moment +your agent needs it — instead of relying on whatever the model happened to memorize +during training, which goes stale the day a library ships a new version. + +It works the same way tools like [Context7](https://context7.com) do — see +[how it compares](/docs/compare/) — except it's already part of agentflare, so there's +nothing extra to install or configure. + +## What's supported + +- **Rust crates**, pulled straight from [docs.rs](https://docs.rs). +- **npm packages**, pulled from their published TypeScript types (with a fallback for + packages that don't ship their own types). +- **Python packages**, pulled from their type stubs (with the same kind of fallback). + +See [Supported languages](/docs/how-it-works/) for details. + +## Do you need to do anything? + +No. If you're using agentflare, your agent already has this available and will reach +for it on its own when it's about to write code against a library. You don't need to +run any commands yourself for it to work. + +That said, two things are worth knowing: + +- **You can look things up yourself too**, straight from the terminal — see the + [CLI reference](/docs/cli/). +- **After upgrading a dependency**, it's worth telling your agent to refresh its cached + copy so it isn't working from the old version — see [Examples](/docs/examples/). + +## Why it's fast + +The first time a package is looked up, `flare-docs` fetches and caches it. Every lookup +after that — by you or your agent — is instant and works offline, because it's reading +from that local cache instead of making a network call. diff --git a/docs-site/src/content/docs/mcp-tool.md b/docs-site/src/content/docs/mcp-tool.md new file mode 100644 index 00000000..5197bdc2 --- /dev/null +++ b/docs-site/src/content/docs/mcp-tool.md @@ -0,0 +1,27 @@ +--- +title: Using it from your agent +description: What your AI coding agent can do with flare-docs, automatically. +--- + +If your AI coding agent is connected to agentflare, it already has `flare-docs` +available as a tool — nothing to turn on. When it's about to write code against a +library it isn't confident about, it can: + +- **Look up a package's docs** — by name, and optionally a specific version. +- **Search** across everything it's already fetched, when it knows roughly what it + needs but not the exact package. +- **Refresh** a package after you've upgraded it, so it isn't working from a stale + cached copy. + +You don't need to prompt your agent to do this — it's just another tool it has access +to, the same way it can read a file or run a command. You'll typically notice it +happening as a quiet step before the agent writes code that uses something new to it. + +## Configuring your own agent or MCP client + +If you're setting up an MCP client yourself (rather than using agentflare's own +gateway), the tool is called `docs` and takes an `action` of `search`, `get`, `list`, +or `refresh`, plus a package name and optional ecosystem/version. The +[CLI reference](/docs/cli/) documents the same four operations with the exact flags — +it's the easiest way to see what's available, since the CLI and the agent-facing tool +do the same things. diff --git a/docs-site/src/fonts/LICENSE.txt b/docs-site/src/fonts/LICENSE.txt new file mode 100644 index 00000000..75ef8ea5 --- /dev/null +++ b/docs-site/src/fonts/LICENSE.txt @@ -0,0 +1,90 @@ +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/docs-site/src/fonts/commit-mono-400.woff2 b/docs-site/src/fonts/commit-mono-400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d455b20d88c06a54f9a9137956113ec921496f2f GIT binary patch literal 48128 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
    9v@zn6jPo-|M5dY4VBX$|{< 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 literal 0 HcmV?d00001 diff --git a/docs-site/src/styles/custom.css b/docs-site/src/styles/custom.css new file mode 100644 index 00000000..1ca8796c --- /dev/null +++ b/docs-site/src/styles/custom.css @@ -0,0 +1,121 @@ +/* + * agentflare design system, ported from site/public/index.html — same tokens, + * same dark/light convention. Starlight and agentflare's landing page both + * key off [data-theme="dark"|"light"] on :root, so Starlight's built-in theme + * toggle flips both var sets at once with no extra JS. + */ + +/* Commit Mono (OFL) — self-hosted, same font as the landing page */ +@font-face { + font-family: "Commit Mono"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("../fonts/commit-mono-400.woff2") format("woff2"); +} +@font-face { + font-family: "Commit Mono"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("../fonts/commit-mono-700.woff2") format("woff2"); +} + +:root { + color-scheme: light dark; + --bg: #0b0d12; + --bg-2: #0e1119; + --surface: #14171f; + --surface-2: #1a1e29; + --line: #232838; + --line-soft: #1c202c; + --ink: #edeef2; + --ink-dim: #c3c8d4; + --muted: #8a90a0; + --faint: #5a6072; + --flare-warm: #ffb020; + --flare-hot: #ff5e3a; + --flare-soft: #ffd37a; + --good: #4ade80; + --code-bg: #0a0c11; + --r: 14px; + --r-sm: 10px; + --mono: "Commit Mono", ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, + "Liberation Mono", monospace; + --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; +} +:root[data-theme="light"] { + color-scheme: light; + --bg: #f4f5f8; + --bg-2: #eef0f4; + --surface: #ffffff; + --surface-2: #f7f8fb; + --line: #e1e4ec; + --line-soft: #eaecf2; + --ink: #141720; + --ink-dim: #333a49; + --muted: #5c6478; + --faint: #8a91a2; + --flare-warm: #c2760a; + --flare-hot: #e14a22; + --flare-soft: #b96a0a; + --code-bg: #0b0d12; +} + +/* ---- Map agentflare's tokens onto Starlight's theme variables ---- */ +:root { + --sl-color-bg: var(--bg); + --sl-color-bg-nav: var(--bg-2); + --sl-color-bg-sidebar: var(--bg-2); + --sl-color-bg-inline-code: var(--surface-2); + --sl-color-bg-accent: var(--flare-warm); + --sl-color-white: var(--ink); + --sl-color-text: var(--ink-dim); + --sl-color-text-accent: var(--flare-soft); + --sl-color-text-invert: #160a02; + --sl-color-gray-1: var(--ink-dim); + --sl-color-gray-2: var(--muted); + --sl-color-gray-3: var(--muted); + --sl-color-gray-4: var(--faint); + --sl-color-gray-5: var(--line); + --sl-color-gray-6: var(--surface); + --sl-color-black: var(--bg); + --sl-color-accent-low: color-mix(in srgb, var(--flare-warm) 22%, var(--bg)); + --sl-color-accent: var(--flare-warm); + --sl-color-accent-high: var(--flare-soft); + --sl-color-hairline-light: var(--line); + --sl-color-hairline: var(--line-soft); + --sl-color-hairline-shade: var(--line); + --sl-font: var(--sans); + --sl-font-mono: var(--mono); + --sl-shadow-sm: 0 1px 1px rgba(0, 0, 0, 0.24); + --sl-shadow-md: 0 8px 24px -8px rgba(0, 0, 0, 0.4); + --sl-shadow-lg: var(--shadow, 0 24px 60px -20px rgba(0, 0, 0, 0.6)); +} +:root[data-theme="light"] { + --sl-color-gray-6: var(--surface); + --sl-color-gray-7: var(--bg-2); + --sl-color-black: var(--ink); + --sl-color-accent-low: color-mix(in srgb, var(--flare-warm) 14%, var(--bg)); +} + +/* ---- agentflare's signature: mono headings, tight tracking ---- */ +.sl-markdown-content :is(h1, h2, h3, h4, h5, h6), +.site-title, +[class^="hero"] h1 { + font-family: var(--mono); + font-weight: 650; + letter-spacing: -0.02em; +} + +/* Same flare gradient used for the landing page's accent text/rules */ +.sl-markdown-content a { + text-decoration-color: color-mix(in srgb, var(--flare-warm) 50%, transparent); +} +.sl-markdown-content code:not(pre code) { + border-radius: var(--r-sm); +} +.sl-markdown-content pre, +.expressive-code { + border-radius: var(--r); +} diff --git a/docs-site/tsconfig.json b/docs-site/tsconfig.json new file mode 100644 index 00000000..8bf91d3b --- /dev/null +++ b/docs-site/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..d71e748d --- /dev/null +++ b/mise.toml @@ -0,0 +1,30 @@ +[tools] +aube = "latest" + +[tasks.install] +description = "Install JS deps for the whole workspace (site + docs-site)" +run = "aube install" + +[tasks."dev:site"] +description = "Run the agentflare.dev landing page + Worker dev server" +depends = ["install"] +run = "aube run dev --filter agentflare-web" + +[tasks."dev:docs"] +description = "Run the flare-docs Starlight dev server" +depends = ["install"] +run = "aube run dev --filter agentflare-docs" + +[tasks."build:docs"] +description = "Build the flare-docs Starlight site (docs-site/dist)" +depends = ["install"] +run = "aube run build --filter agentflare-docs" + +[tasks.deploy] +description = "Build docs, copy into site/public/docs, and deploy agentflare.dev" +depends = ["install"] +run = "aube run deploy --filter agentflare-web" + +[tasks.tail] +description = "Tail live Cloudflare Worker logs for agentflare.dev" +run = "aube run tail --filter agentflare-web" diff --git a/package.json b/package.json new file mode 100644 index 00000000..f30ea196 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "agentflare-web-monorepo", + "private": true, + "version": "0.0.0", + "description": "JS workspace root for agentflare.dev — links site/ (landing page + Worker) and docs-site/ (flare-docs documentation) under one aube install, each still independently runnable.", + "scripts": { + "dev:site": "aube run dev --filter agentflare-web", + "dev:docs": "aube run dev --filter agentflare-docs", + "deploy": "aube run deploy --filter agentflare-web" + } +} diff --git a/site/.gitignore b/site/.gitignore index 146ba7da..6c53ade7 100644 --- a/site/.gitignore +++ b/site/.gitignore @@ -3,3 +3,7 @@ # deps node_modules/ + +# Generated Starlight build output for agentflare.dev/docs — built fresh by +# `aube deploy` (`aube run build:docs` + `aube run copy:docs`), not committed. +/public/docs/ diff --git a/site/README.md b/site/README.md index 3fad99bb..ed961f75 100644 --- a/site/README.md +++ b/site/README.md @@ -4,34 +4,67 @@ The landing site for agentflare, deployed to **Cloudflare Workers** with static assets — the same setup pattern as the sarvo apps (`apps/web`: a Worker with an `assets` binding + a custom-domain route). +Part of a small aube-linked monorepo rooted at the repo root (`/aube-workspace.yaml`, +`/package.json`, `/mise.toml`) alongside [`docs-site/`](../docs-site). One `aube install` +at the repo root installs both; each package still runs its own `dev`/`build` standalone. +See the repo root `mise.toml` for the task shortcuts (`mise run `, `mise tasks ls` +to list them) and "Docs" below for how the two packages actually connect. + ```text site/ ├── wrangler.jsonc # Worker config — assets binding + agentflare.dev custom domain -├── package.json # dev / deploy / tail scripts (wrangler only, no build step) +├── package.json # dev / build:docs / copy:docs / deploy / tail scripts ├── src/ │ └── worker.ts # serves ./public from ASSETS; proxies /install.sh + /install.ps1 → raw GitHub └── public/ ├── index.html # the site — self-contained (inline CSS/JS, SVG favicon, self-hosted Commit Mono) ├── 404.html # on-brand not-found page + ├── docs/ # copied from ../../docs-site/dist by `aube deploy` — not hand-edited └── fonts/ # Commit Mono woff2 (400 + 700) + OFL LICENSE.txt + +docs-site/ # sibling workspace package, NOT nested in site/ — see "Docs" below ``` -There is **no build step** — `public/index.html` is hand-authored and shipped as-is. +The landing page has **no build step** — `public/index.html` is hand-authored and shipped +as-is. `/docs` is the exception: its content is built by the separate `docs-site/` +package and copied into `public/docs/` only during `aube deploy`. ## Deploy ```bash -cd site -npm install # or: aube install — pulls wrangler -npm run deploy # wrangler deploy +mise run install # aube install, from the repo root — installs site/ + docs-site/ +mise run deploy # build docs-site, copy into public/docs, wrangler deploy ``` +Equivalent without `mise` tasks, from `site/`: `aube install && aube deploy`. + `wrangler deploy` uploads `public/` to the `ASSETS` binding, bundles `src/worker.ts`, and (first deploy only) provisions the `agentflare.dev` + `www.agentflare.dev` custom domains declared in `wrangler.jsonc`. The apex zone must already be on this Cloudflare account; Wrangler creates the custom-domain records. -Local preview: `npm run dev` (serves on `localhost:8787`). Live logs: `npm run tail`. +Local preview: `mise run dev:site` (serves on `localhost:8787`). Live logs: `mise run tail`. + +## Docs (`/docs`) + +[`docs-site/`](../docs-site) is a sibling workspace package (`agentflare-docs` in +`aube-workspace.yaml`) — an [Astro Starlight](https://starlight.astro.build) project +documenting agentflare's `flare-docs` module. It's deliberately **not** nested under +`site/`: day to day, `site/`'s own `dev`/`build` never touch it, and vice versa — only +the shared root `aube install` links them. See `docs-site/README.md` for its standalone +workflow (`mise run dev:docs`, or `cd docs-site && aube dev`). + +The two connect at exactly one point — deploy: + +1. `aube run build:docs` builds `docs-site/` via the workspace filter + (`aube run build --filter agentflare-docs`), producing `docs-site/dist/`. +2. `aube run copy:docs` copies that output into `public/docs/`. +3. `wrangler deploy` uploads `public/` (landing page + copied docs) as one static bundle, + so `/docs` deploys from the same `public/` upload with no separate Worker or route. + +`aube deploy` (or `mise run deploy`) runs all three. `public/docs/` is generated, not +hand-edited — add `/public/docs/` to `site/.gitignore` so the copied build output isn't +committed. ## What the Worker does diff --git a/site/package.json b/site/package.json index 43c649f9..94875bcd 100644 --- a/site/package.json +++ b/site/package.json @@ -5,7 +5,9 @@ "description": "Landing site for agentflare — agentflare.dev (Cloudflare Workers + static assets)", "scripts": { "dev": "wrangler dev", - "deploy": "wrangler deploy", + "build:docs": "aube run build --filter agentflare-docs", + "copy:docs": "rm -rf public/docs && cp -R ../docs-site/dist public/docs", + "deploy": "aube run build:docs && aube run copy:docs && wrangler deploy", "tail": "wrangler tail" }, "devDependencies": { diff --git a/site/public/index.html b/site/public/index.html index 4eeb29be..8e447ed8 100644 --- a/site/public/index.html +++ b/site/public/index.html @@ -278,6 +278,7 @@ Coordinate Numbers Install + Docs + + + + + + + diff --git a/dashboard/web/list.html b/dashboard/web/list.html index 9ee29b3a..52257237 100644 --- a/dashboard/web/list.html +++ b/dashboard/web/list.html @@ -53,6 +53,7 @@ List Webhooks Claims + Jobs Cost diff --git a/dashboard/web/shell.html b/dashboard/web/shell.html index d0e16ebc..ff6770ef 100644 --- a/dashboard/web/shell.html +++ b/dashboard/web/shell.html @@ -61,6 +61,7 @@ List Webhooks Claims + Jobs Cost diff --git a/dashboard/web/webhooks.html b/dashboard/web/webhooks.html index 10f2cf9f..7d2929f5 100644 --- a/dashboard/web/webhooks.html +++ b/dashboard/web/webhooks.html @@ -53,6 +53,7 @@ List Webhooks Claims + Jobs Cost diff --git a/src/dashboard/server.rs b/src/dashboard/server.rs index 9b03c150..6b5577b8 100644 --- a/src/dashboard/server.rs +++ b/src/dashboard/server.rs @@ -1,13 +1,16 @@ +use agentflare_jobs::{AgentJob, JobState, Queue}; use axum::response::sse::{Event, KeepAlive, Sse}; use axum::{ - Router, - extract::Query, + Json, Router, + extract::{Path, Query, State}, http::{StatusCode, Uri, header}, response::{IntoResponse, Response}, routing::get, }; +use std::io::Read; use rust_embed::RustEmbed; use serde::Deserialize; +use std::path::PathBuf; #[derive(RustEmbed)] #[folder = "dashboard/web/"] @@ -133,6 +136,35 @@ async fn cost_handler(Query(q): Query) -> Response { const TICK: std::time::Duration = std::time::Duration::from_secs(3); const COST_REFRESH: std::time::Duration = std::time::Duration::from_secs(30); +/// How often to sweep finished jobs (and their stdout/stderr log files) out +/// of the queue, and how old a finished job must be before it's eligible. +/// Without this, `agent_jobs` rows and job-logs/ files accumulate forever — +/// nothing else ever calls `Queue::cleanup`. +const JOB_CLEANUP_INTERVAL: std::time::Duration = std::time::Duration::from_secs(3600); +const JOB_RETENTION_SECS: i64 = 7 * 24 * 3600; + +/// Runs for the lifetime of the process (like `snapshot_broadcaster`'s +/// producer task): wakes on `JOB_CLEANUP_INTERVAL`, deletes finished jobs +/// older than `JOB_RETENTION_SECS`. The blocking SQLite + filesystem work +/// happens off the async worker threads via `spawn_blocking`. +fn spawn_job_cleanup(queue: agentflare_jobs::Queue) { + tokio::spawn(async move { + let mut ticker = tokio::time::interval(JOB_CLEANUP_INTERVAL); + loop { + ticker.tick().await; + let queue = queue.clone(); + let result = + tokio::task::spawn_blocking(move || queue.cleanup(JOB_RETENTION_SECS)).await; + match result { + Ok(Ok(0)) => {} + Ok(Ok(deleted)) => eprintln!("agentflare-jobs: cleaned up {deleted} old job(s)"), + Ok(Err(e)) => eprintln!("agentflare-jobs: cleanup failed: {e}"), + Err(e) => eprintln!("agentflare-jobs: cleanup task panicked: {e}"), + } + } + }); +} + /// Single shared broadcast of the live `{ claims, cost_today }` snapshot. Every /// `/events` client subscribes to this one channel, so there is no per-client /// work — the producer below runs at most one refresh cycle per `TICK`, @@ -225,7 +257,224 @@ fn mime_for(p: &str) -> &'static str { } } -pub fn router() -> Router { +/// Body for `POST /api/jobs`. Only `command` is required; everything else +/// falls back to `AgentJob::new`'s defaults (300s timeout, 3 retries). +#[derive(Deserialize)] +struct SubmitJobRequest { + command: String, + #[serde(default)] + args: Vec, + #[serde(default)] + env: Vec<(String, String)>, + cwd: Option, + timeout_secs: Option, +} + +async fn submit_job_handler( + State(queue): State, + Json(req): Json, +) -> Response { + if req.command.trim().is_empty() { + return (StatusCode::BAD_REQUEST, "command must not be empty").into_response(); + } + let mut job = AgentJob::new(req.command).args(req.args); + for (k, v) in req.env { + job = job.env(k, v); + } + if let Some(cwd) = req.cwd { + job = job.cwd(cwd); + } + if let Some(secs) = req.timeout_secs { + job = job.timeout(secs); + } + match queue.enqueue(&job) { + Ok(info) => (StatusCode::CREATED, Json(info)).into_response(), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("failed to enqueue job: {e}"), + ) + .into_response(), + } +} + +#[derive(Deserialize)] +struct JobsQuery { + id: Option, + state: Option, +} + +/// `GET /api/jobs?id=` fetches one job; `GET /api/jobs[?state=]` +/// lists the most recent 100, optionally filtered by state. +async fn jobs_handler(State(queue): State, Query(q): Query) -> Response { + if let Some(id) = q.id { + return match queue.get(&id) { + Ok(info) => Json(info).into_response(), + Err(_) => (StatusCode::NOT_FOUND, "job not found").into_response(), + }; + } + let state_filter = match q.state.as_deref() { + None => None, + Some("queued") => Some(JobState::Queued), + Some("running") => Some(JobState::Running), + Some("exited") => Some(JobState::Exited), + Some("killed") => Some(JobState::Killed), + Some("failed") => Some(JobState::Failed), + Some(other) => { + return ( + StatusCode::BAD_REQUEST, + format!("invalid `state` value {other:?}"), + ) + .into_response(); + } + }; + match queue.list(state_filter) { + Ok(jobs) => Json(jobs).into_response(), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("failed to list jobs: {e}"), + ) + .into_response(), + } +} + +/// SSE stream of the live job list. Each subscriber independently polls +/// `queue.list(None)` on the same `TICK` cadence as the existing event +/// stream — cheap enough (SQLite LIMIT 100) that a shared broadcaster is +/// overkill for typical dashboard usage (1-2 tabs). +async fn jobs_events_handler( + State(queue): State, +) -> Sse>> { + let (tx, rx) = tokio::sync::mpsc::unbounded_channel::< + Result, + >(); + tokio::spawn(async move { + let mut ticker = tokio::time::interval(TICK); + loop { + ticker.tick().await; + let list = tokio::task::spawn_blocking({ + let queue = queue.clone(); + move || queue.list(None) + }) + .await + .unwrap_or(Ok(vec![])) + .unwrap_or(vec![]); + let json = serde_json::to_string(&list).unwrap_or_else(|_| "[]".to_string()); + if tx.send(Ok(Event::default().data(json))).is_err() { + break; + } + } + }); + Sse::new(tokio_stream::wrappers::UnboundedReceiverStream::new(rx)) + .keep_alive(KeepAlive::default()) +} + +/// `GET /api/jobs/:id/stream` — SSE stream that tails the job's stdout log +/// file incrementally. +/// +/// While the job is queued or running, we poll every 300ms: check the +/// current job state (`queue.get(id)`), read any new bytes from the stdout +/// file, and push them as SSE `data:` events. Once the job reaches a +/// terminal state (exited/failed/killed), any remaining buffered content is +/// flushed, a final `event: done\ndata:` frame is sent, and the stream +/// closes. +async fn jobs_stream_handler( + State(queue): State, + Path(id): Path, +) -> Response { + // 404 on unknown id before spawning anything. + if queue.get(&id).is_err() { + return (StatusCode::NOT_FOUND, "job not found").into_response(); + } + let (tx, rx) = tokio::sync::mpsc::unbounded_channel::< + Result, + >(); + tokio::spawn(async move { + let mut interval = tokio::time::interval(std::time::Duration::from_millis(300)); + let mut offset: u64 = 0; + let mut file: Option = None; + loop { + interval.tick().await; + let info = match tokio::task::spawn_blocking({ + let queue = queue.clone(); + let id = id.clone(); + move || queue.get(&id) + }) + .await + { + Ok(Ok(info)) => info, + _ => { + let _ = tx.send(Ok(Event::default().data("").event("done"))); + break; + } + }; + let terminal = info.state.is_terminal(); + if file.is_none() { + if let Some(ref out) = info.output { + let p = &out.stdout_path; + if p.exists() { + match std::fs::File::open(p) { + Ok(f) => file = Some(f), + Err(_) => { + if terminal { + let _ = tx + .send(Ok(Event::default().data("").event("done"))); + } + break; + } + } + } + } + if file.is_none() { + if terminal { + let _ = tx.send(Ok(Event::default().data("").event("done"))); + break; + } + continue; + } + } + if let Some(ref mut f) = file { + use std::io::Seek as _; + let _ = f.seek(std::io::SeekFrom::Start(offset)); + let mut buf = Vec::new(); + match f.read_to_end(&mut buf) { + Ok(n) if n > 0 => { + offset += n as u64; + // Lossy, not strict: `buf` is a raw byte window that + // can split a multi-byte UTF-8 char across polls, and + // `offset` has already moved past it — a strict parse + // would silently and permanently drop those bytes + // from the live view instead of showing a stray + // replacement char at the boundary. + let text = String::from_utf8_lossy(&buf).into_owned(); + if tx.send(Ok(Event::default().data(text))).is_err() { + break; + } + } + Ok(_) => {} + Err(_) => {} + } + } + if terminal { + let _ = tx.send(Ok(Event::default().data("").event("done"))); + break; + } + } + }); + Sse::new(tokio_stream::wrappers::UnboundedReceiverStream::new(rx)) + .keep_alive(KeepAlive::default()) + .into_response() +} + +/// Submit/fetch/stream endpoints as their own state-scoped sub-router. +fn jobs_router(queue: Queue) -> Router { + Router::new() + .route("/api/jobs", get(jobs_handler).post(submit_job_handler)) + .route("/api/jobs/events", get(jobs_events_handler)) + .route("/api/jobs/{id}/stream", get(jobs_stream_handler)) + .with_state(queue) +} + +pub fn router(queue: Queue) -> Router { Router::new() .route("/api/claims", get(claims_handler)) .route("/api/pm/workspaces", get(pm_workspaces_handler)) @@ -237,6 +486,7 @@ pub fn router() -> Router { .route("/api/webhooks", get(webhooks_handler)) .route("/api/cost", get(cost_handler)) .route("/events", get(events_handler)) + .merge(jobs_router(queue)) .nest("/artifacts", super::artifacts::router()) .merge(flare_proxy::router()) .fallback(static_handler) @@ -254,6 +504,25 @@ pub async fn run(host: &str, port: u16, open: bool, yes_expose: bool) { eprintln!("pass --yes-expose to bind anyway (trusted networks only)."); std::process::exit(1); } + // `agent_jobs` is relational state, so it lives in the single + // source-of-truth `agentflare.db` (see `db.rs`'s header comment) rather + // than a new file — this just opens its own `Connection` to that same + // path and runs its own (non-overlapping) migration for that one table. + // Job stdout/stderr logs are rebuildable artifacts, not DB state, so + // those still get their own directory. + let queue = Queue::open( + &crate::db::agentflare_db_path(), + crate::state::state_dir().join("job-logs"), + ) + .expect("failed to open job queue"); + // Kept alive for the rest of `run()` (which never returns in normal + // operation) so its worker threads keep polling the queue; there is no + // graceful in-process shutdown path today (see `daemon::stop_daemon`, + // which relies on SIGTERM/SIGKILL), so neither does this. + let mut worker_pool = agentflare_jobs::WorkerPool::new(queue.clone()); + worker_pool.start(2); + spawn_job_cleanup(queue.clone()); + let listener = tokio::net::TcpListener::bind((host, port)) .await .expect("failed to bind dashboard server"); @@ -266,7 +535,7 @@ pub async fn run(host: &str, port: u16, open: bool, yes_expose: bool) { if open { crate::dashboard::open_browser(&url); } - axum::serve(listener, router()) + axum::serve(listener, router(queue)) .await .expect("dashboard server error"); } @@ -275,6 +544,11 @@ pub async fn run(host: &str, port: u16, open: bool, yes_expose: bool) { mod tests { use super::*; + fn test_queue() -> Queue { + let dir = tempfile::tempdir().unwrap(); + Queue::open_memory(dir.path().join("logs")).unwrap() + } + #[tokio::test] async fn claims_endpoint_returns_json_array() { let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) @@ -282,7 +556,7 @@ mod tests { .unwrap(); let addr = listener.local_addr().unwrap(); tokio::spawn(async move { - axum::serve(listener, router()).await.unwrap(); + axum::serve(listener, router(test_queue())).await.unwrap(); }); let body = reqwest::get(format!("http://{addr}/api/claims")) .await @@ -293,6 +567,80 @@ mod tests { assert!(body.starts_with('['), "expected JSON array, got: {body}"); } + #[tokio::test] + async fn jobs_endpoint_round_trips_submit_and_fetch() { + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(test_queue())).await.unwrap(); + }); + + let (cmd, args): (&str, Vec<&str>) = if cfg!(windows) { + ("cmd", vec!["/c", "exit 0"]) + } else { + ("true", vec![]) + }; + let client = reqwest::Client::new(); + let submit_resp = client + .post(format!("http://{addr}/api/jobs")) + .json(&serde_json::json!({ "command": cmd, "args": args })) + .send() + .await + .unwrap(); + assert_eq!(submit_resp.status(), StatusCode::CREATED); + let submitted: serde_json::Value = submit_resp.json().await.unwrap(); + assert_eq!(submitted["state"], "queued"); + assert_eq!(submitted["command"], cmd); + let id = submitted["id"].as_str().unwrap().to_string(); + + let fetch_resp = reqwest::get(format!("http://{addr}/api/jobs?id={id}")) + .await + .unwrap(); + assert_eq!(fetch_resp.status(), StatusCode::OK); + let fetched: serde_json::Value = fetch_resp.json().await.unwrap(); + assert_eq!(fetched["id"], id); + assert_eq!( + fetched["command"], cmd, + "list/get should surface the job's command, not just its id" + ); + } + + #[tokio::test] + async fn jobs_endpoint_rejects_empty_command() { + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(test_queue())).await.unwrap(); + }); + let client = reqwest::Client::new(); + let resp = client + .post(format!("http://{addr}/api/jobs")) + .json(&serde_json::json!({ "command": "" })) + .send() + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + } + + #[tokio::test] + async fn jobs_endpoint_404s_unknown_id() { + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(test_queue())).await.unwrap(); + }); + let resp = reqwest::get(format!("http://{addr}/api/jobs?id=does-not-exist")) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } + #[test] fn is_local_bind_recognizes_loopback_only() { assert!(is_local_bind("127.0.0.1")); @@ -371,6 +719,116 @@ mod tests { assert_eq!(resp.status(), StatusCode::BAD_REQUEST); } + #[tokio::test] + async fn jobs_events_endpoint_streams_job_list() { + use tokio_stream::StreamExt as _; + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + let queue = test_queue(); + // Submit a job so the list isn't empty. + let job = agentflare_jobs::AgentJob::new("true"); + queue.enqueue(&job).unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(queue)).await.unwrap(); + }); + let resp = reqwest::get(format!("http://{addr}/api/jobs/events")) + .await + .unwrap(); + let mut stream = resp.bytes_stream(); + let first = tokio::time::timeout(std::time::Duration::from_secs(10), stream.next()) + .await + .expect("first SSE frame within 10s") + .expect("stream item") + .unwrap(); + let text = String::from_utf8(first.to_vec()).unwrap(); + let data_line = text + .lines() + .find_map(|l| l.strip_prefix("data: ")) + .expect("SSE data line"); + let v: serde_json::Value = serde_json::from_str(data_line).unwrap(); + assert!(v.is_array(), "expected JSON array, got: {v}"); + assert!(!v.as_array().unwrap().is_empty(), "expected at least one job"); + } + + #[tokio::test] + async fn jobs_stream_endpoint_404s_unknown_id() { + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(test_queue())).await.unwrap(); + }); + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + let resp = reqwest::get(format!("http://{addr}/api/jobs/does-not-exist/stream")) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } + + #[tokio::test] + async fn jobs_stream_endpoint_streams_stdout_of_finished_job() { + use tokio_stream::StreamExt as _; + let dir = tempfile::tempdir().unwrap(); + let queue = Queue::open_memory(dir.path().join("logs")).unwrap(); + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + let job = agentflare_jobs::AgentJob::new("echo").arg("hello from job"); + let info = queue.enqueue(&job).unwrap(); + let id = info.id.clone(); + let log_dir = queue.log_dir().to_path_buf(); + std::fs::create_dir_all(&log_dir).unwrap(); + let stdout_path = log_dir.join(format!("{id}.stdout")); + std::fs::write(&stdout_path, b"hello from job\n").unwrap(); + let output = agentflare_jobs::JobOutput { + exit_code: Some(0), + timed_out: false, + stdout_path: stdout_path.clone(), + stderr_path: log_dir.join(format!("{id}.stderr")), + stdout_total_bytes: 16, + stderr_total_bytes: 0, + }; + queue.complete(&id, &output, true).unwrap(); + tokio::spawn(async move { + axum::serve(listener, router(queue)).await.unwrap(); + }); + // Give the server a moment to start. + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + let resp = reqwest::get(format!("http://{addr}/api/jobs/{id}/stream")) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + let mut stream = resp.bytes_stream(); + // Collect all SSE frames with a timeout. + let mut all_text = String::new(); + loop { + match tokio::time::timeout( + std::time::Duration::from_secs(5), + stream.next(), + ) + .await + { + Ok(Some(Ok(chunk))) => { + all_text.push_str(&String::from_utf8_lossy(&chunk)); + if all_text.contains("event: done") { + break; + } + } + Ok(Some(Err(_))) => break, + Ok(None) => break, + Err(_) => break, + } + } + assert!( + all_text.contains("hello from job"), + "expected stdout content in stream, got: {all_text}" + ); + } + #[tokio::test] async fn events_endpoint_streams_claims_and_cost_snapshot() { use tokio_stream::StreamExt as _; @@ -379,7 +837,7 @@ mod tests { .unwrap(); let addr = listener.local_addr().unwrap(); tokio::spawn(async move { - axum::serve(listener, router()).await.unwrap(); + axum::serve(listener, router(test_queue())).await.unwrap(); }); let resp = reqwest::get(format!("http://{addr}/events")).await.unwrap(); let mut stream = resp.bytes_stream(); @@ -401,8 +859,31 @@ mod tests { ); } + // The PATH_LOCK guard below is intentionally held across `.await` + // points: it must stay held for this whole test so no other test can + // reset AGENTFLARE_HOME_OVERRIDE out from under it (a real race, not + // just a lint nit — see the comment at the lock acquisition). Safe here + // because `#[tokio::test]` gives each test its own current-thread + // runtime on its own OS thread, so no other task ever contends for this + // thread while the guard is held. + #[allow(clippy::await_holding_lock)] #[tokio::test] async fn run_serves_normally_on_local_bind_without_yes_expose() { + // `run()` now opens a real, writable job queue under + // `state::state_dir()` (`~/.agentflare` by default). Route it at a + // throwaway home for the duration of this test — same lock + + // env-var mechanism `paths::test_support::with_temp_home` uses, but + // inlined because that helper's guard is sync-only and would reset + // the override before the `.await`s below ever run. + let _guard = agent_registry::detect::PATH_LOCK + .lock() + .unwrap_or_else(|e| e.into_inner()); + let home_dir = tempfile::tempdir().unwrap(); + unsafe { + // SAFETY: PATH_LOCK serializes all env mutation in this test binary. + std::env::set_var("AGENTFLARE_HOME_OVERRIDE", home_dir.path()); + } + // Probe an ephemeral port, then hand that exact port to `run()` — // `run()` takes a fixed port rather than returning the bound address, // so this is the only way to know where to connect afterward. Only @@ -427,6 +908,12 @@ mod tests { } tokio::time::sleep(std::time::Duration::from_millis(100)).await; } + + unsafe { + // SAFETY: still under PATH_LOCK. + std::env::remove_var("AGENTFLARE_HOME_OVERRIDE"); + } + assert!( started, "expected dashboard to serve on a local bind without --yes-expose" From 1779a05fd9fd0c2954fc4286a2b530abae26fe6e Mon Sep 17 00:00:00 2001 From: shiva Date: Thu, 30 Jul 2026 19:18:08 +0530 Subject: [PATCH 14/19] fix(agentflare-jobs): key log files by job id so live tail actually works while running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code review on the jobs-streaming PR found the live tail was completely non-functional for in-progress jobs: jobs_stream_handler only opened the stdout file once JobInfo.output was populated, which only happens after a job reaches a terminal state, and Supervisor generated its own random id for log filenames independent of the job's own queue id — so there was no way to even locate a running job's log path. The stream would sit idle the whole time a job ran, then dump everything in one lump the instant it finished. Fixes this by having Supervisor::new take the job's own id and name its log files from it, so jobs_stream_handler can derive the path directly via queue.log_dir().join("{id}.stdout") without waiting on completion. Adds a regression test that drives a real job through a real WorkerPool and asserts output arrives while the job is still 'running', not just after it exits — the previous test only covered an already-finished job, which is exactly why this slipped through. Also fixes two smaller issues from the same review pass in src/dashboard/server.rs: jobs_handler and the jobs_stream_handler 404 pre-check ran synchronous SQLite calls inline on the async path instead of via spawn_blocking (inconsistent with the SSE handlers doing the same calls correctly), and jobs_events_handler silently swallowed list errors into an empty list instead of logging them. Also fixes test_queue() dropping its TempDir immediately, which left log_dir pointing at an already-deleted path. --- crates/agentflare-jobs/src/supervisor.rs | 7 +- crates/agentflare-jobs/src/worker.rs | 1 + crates/agentflare-jobs/tests/queue_test.rs | 9 +- .../agentflare-jobs/tests/supervisor_test.rs | 3 + src/dashboard/server.rs | 177 +++++++++++++++--- 5 files changed, 166 insertions(+), 31 deletions(-) diff --git a/crates/agentflare-jobs/src/supervisor.rs b/crates/agentflare-jobs/src/supervisor.rs index 8032b591..2a48c494 100644 --- a/crates/agentflare-jobs/src/supervisor.rs +++ b/crates/agentflare-jobs/src/supervisor.rs @@ -18,7 +18,13 @@ pub struct Supervisor { } impl Supervisor { + /// `id` names the log files (`{id}.stdout`/`{id}.stderr`) — callers + /// running this under `agentflare-jobs::Queue` must pass the job's own + /// queue id, not a fresh one, so a running job's log path is derivable + /// from its id alone (`queue.log_dir().join(format!("{id}.stdout"))`) + /// without waiting for the job to finish and report it back. pub fn new( + id: String, command: String, args: Vec, env: Vec<(String, String)>, @@ -27,7 +33,6 @@ impl Supervisor { kill_after_secs: u64, log_dir: PathBuf, ) -> Self { - let id = db_kit::ids::new_id(); let stdout_path = log_dir.join(format!("{id}.stdout")); let stderr_path = log_dir.join(format!("{id}.stderr")); Self { diff --git a/crates/agentflare-jobs/src/worker.rs b/crates/agentflare-jobs/src/worker.rs index eb9ad330..097848a3 100644 --- a/crates/agentflare-jobs/src/worker.rs +++ b/crates/agentflare-jobs/src/worker.rs @@ -48,6 +48,7 @@ fn worker_loop(queue: &Queue, running: &AtomicBool) { match queue.dequeue() { Ok(Some((id, job))) => { let mut sup = Supervisor::new( + id.clone(), job.command.clone(), job.args.clone(), job.env.clone(), diff --git a/crates/agentflare-jobs/tests/queue_test.rs b/crates/agentflare-jobs/tests/queue_test.rs index 71b84d4b..de9420b6 100644 --- a/crates/agentflare-jobs/tests/queue_test.rs +++ b/crates/agentflare-jobs/tests/queue_test.rs @@ -1,8 +1,10 @@ use agentflare_jobs::{AgentJob, JobState, Queue}; fn test_queue() -> Queue { - let dir = tempfile::tempdir().unwrap(); - Queue::open_memory(dir.path().join("logs")).unwrap() + // `.keep()` so the dir outlives this function — otherwise the returned + // `Queue`'s `log_dir` would point at an already-deleted path. + let dir = tempfile::tempdir().unwrap().keep(); + Queue::open_memory(dir.join("logs")).unwrap() } fn true_cmd() -> (&'static str, Vec<&'static str>) { @@ -47,6 +49,7 @@ fn complete_sets_exited() { q.enqueue(&AgentJob::new(cmd).args(args)).unwrap(); let (id, job) = q.dequeue().unwrap().unwrap(); let sup = agentflare_jobs::Supervisor::new( + id.clone(), job.command.clone(), job.args.clone(), vec![], @@ -76,6 +79,7 @@ fn complete_persists_stdout_and_stderr_byte_counts() { q.enqueue(&AgentJob::new(cmd).args(args)).unwrap(); let (id, job) = q.dequeue().unwrap().unwrap(); let mut supervisor = agentflare_jobs::Supervisor::new( + id.clone(), job.command.clone(), job.args.clone(), vec![], @@ -189,6 +193,7 @@ fn cleanup_removes_old_jobs_and_their_log_files() { q.enqueue(&AgentJob::new(cmd).args(args)).unwrap(); let (id, job) = q.dequeue().unwrap().unwrap(); let mut supervisor = agentflare_jobs::Supervisor::new( + id.clone(), job.command.clone(), job.args.clone(), vec![], diff --git a/crates/agentflare-jobs/tests/supervisor_test.rs b/crates/agentflare-jobs/tests/supervisor_test.rs index 7533a167..26f5c381 100644 --- a/crates/agentflare-jobs/tests/supervisor_test.rs +++ b/crates/agentflare-jobs/tests/supervisor_test.rs @@ -10,6 +10,7 @@ fn sup( ) -> (TempDir, Supervisor) { let log_tmp = tempfile::tempdir().unwrap(); let supervisor = Supervisor::new( + "test-job".to_string(), command.to_string(), args.iter().map(|s| s.to_string()).collect(), vec![], @@ -82,6 +83,7 @@ fn env_vars_are_propagated_to_child() { }; let log_tmp = tempfile::tempdir().unwrap(); let mut supervisor = Supervisor::new( + "test-job".to_string(), cmd.to_string(), args.iter().map(|s| s.to_string()).collect(), vec![("SUPERVISOR_TEST_VAR".to_string(), "hello-env".to_string())], @@ -108,6 +110,7 @@ fn cwd_is_applied_to_child() { }; let log_tmp = tempfile::tempdir().unwrap(); let mut supervisor = Supervisor::new( + "test-job".to_string(), cmd.to_string(), args.iter().map(|s| s.to_string()).collect(), vec![], diff --git a/src/dashboard/server.rs b/src/dashboard/server.rs index 6b5577b8..6efd1bd0 100644 --- a/src/dashboard/server.rs +++ b/src/dashboard/server.rs @@ -305,11 +305,25 @@ struct JobsQuery { /// `GET /api/jobs?id=` fetches one job; `GET /api/jobs[?state=]` /// lists the most recent 100, optionally filtered by state. +/// +/// `queue.get`/`queue.list` hit SQLite synchronously, so both go through +/// `spawn_blocking` rather than running inline on the async request path — +/// matching the SSE handlers below, which do the same for identical calls. async fn jobs_handler(State(queue): State, Query(q): Query) -> Response { if let Some(id) = q.id { - return match queue.get(&id) { - Ok(info) => Json(info).into_response(), - Err(_) => (StatusCode::NOT_FOUND, "job not found").into_response(), + let got = tokio::task::spawn_blocking({ + let queue = queue.clone(); + move || queue.get(&id) + }) + .await; + return match got { + Ok(Ok(info)) => Json(info).into_response(), + Ok(Err(_)) => (StatusCode::NOT_FOUND, "job not found").into_response(), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("job lookup task failed: {e}"), + ) + .into_response(), }; } let state_filter = match q.state.as_deref() { @@ -327,13 +341,19 @@ async fn jobs_handler(State(queue): State, Query(q): Query) -> .into_response(); } }; - match queue.list(state_filter) { - Ok(jobs) => Json(jobs).into_response(), - Err(e) => ( + let listed = tokio::task::spawn_blocking(move || queue.list(state_filter)).await; + match listed { + Ok(Ok(jobs)) => Json(jobs).into_response(), + Ok(Err(e)) => ( StatusCode::INTERNAL_SERVER_ERROR, format!("failed to list jobs: {e}"), ) .into_response(), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("job list task failed: {e}"), + ) + .into_response(), } } @@ -351,13 +371,22 @@ async fn jobs_events_handler( let mut ticker = tokio::time::interval(TICK); loop { ticker.tick().await; - let list = tokio::task::spawn_blocking({ + let listed = tokio::task::spawn_blocking({ let queue = queue.clone(); move || queue.list(None) }) - .await - .unwrap_or(Ok(vec![])) - .unwrap_or(vec![]); + .await; + let list = match listed { + Ok(Ok(list)) => list, + Ok(Err(e)) => { + eprintln!("[dashboard/server] jobs_events: list failed: {e}"); + vec![] + } + Err(e) => { + eprintln!("[dashboard/server] jobs_events: task failed: {e}"); + vec![] + } + }; let json = serde_json::to_string(&list).unwrap_or_else(|_| "[]".to_string()); if tx.send(Ok(Event::default().data(json))).is_err() { break; @@ -371,20 +400,35 @@ async fn jobs_events_handler( /// `GET /api/jobs/:id/stream` — SSE stream that tails the job's stdout log /// file incrementally. /// +/// The stdout path is derived directly from `queue.log_dir()` and the job's +/// own id (`Supervisor` names its log files `{id}.stdout`/`{id}.stderr` for +/// exactly this reason) rather than read from `JobInfo.output`, which is +/// only populated once the job reaches a terminal state — waiting on it +/// would mean this stream never emits anything until the job is already +/// finished, defeating the point of a *live* tail. +/// /// While the job is queued or running, we poll every 300ms: check the /// current job state (`queue.get(id)`), read any new bytes from the stdout -/// file, and push them as SSE `data:` events. Once the job reaches a -/// terminal state (exited/failed/killed), any remaining buffered content is -/// flushed, a final `event: done\ndata:` frame is sent, and the stream -/// closes. +/// file (which may not exist yet if the job is still queued), and push them +/// as SSE `data:` events. Once the job reaches a terminal state +/// (exited/failed/killed), any remaining buffered content is flushed, a +/// final `event: done\ndata:` frame is sent, and the stream closes. async fn jobs_stream_handler( State(queue): State, Path(id): Path, ) -> Response { // 404 on unknown id before spawning anything. - if queue.get(&id).is_err() { + let exists = tokio::task::spawn_blocking({ + let queue = queue.clone(); + let id = id.clone(); + move || queue.get(&id).is_ok() + }) + .await + .unwrap_or(false); + if !exists { return (StatusCode::NOT_FOUND, "job not found").into_response(); } + let stdout_path = queue.log_dir().join(format!("{id}.stdout")); let (tx, rx) = tokio::sync::mpsc::unbounded_channel::< Result, >(); @@ -409,18 +453,14 @@ async fn jobs_stream_handler( }; let terminal = info.state.is_terminal(); if file.is_none() { - if let Some(ref out) = info.output { - let p = &out.stdout_path; - if p.exists() { - match std::fs::File::open(p) { - Ok(f) => file = Some(f), - Err(_) => { - if terminal { - let _ = tx - .send(Ok(Event::default().data("").event("done"))); - } - break; + if stdout_path.exists() { + match std::fs::File::open(&stdout_path) { + Ok(f) => file = Some(f), + Err(_) => { + if terminal { + let _ = tx.send(Ok(Event::default().data("").event("done"))); } + break; } } } @@ -545,8 +585,12 @@ mod tests { use super::*; fn test_queue() -> Queue { - let dir = tempfile::tempdir().unwrap(); - Queue::open_memory(dir.path().join("logs")).unwrap() + // `.keep()` so the dir outlives this function — otherwise the + // returned `Queue`'s `log_dir` would point at an already-deleted + // path (harmless for tests that never touch logs, but a footgun for + // ones that do). + let dir = tempfile::tempdir().unwrap().keep(); + Queue::open_memory(dir.join("logs")).unwrap() } #[tokio::test] @@ -829,6 +873,83 @@ mod tests { ); } + #[tokio::test] + async fn jobs_stream_endpoint_tails_output_of_a_still_running_job() { + // Regression: the stream used to key off `JobInfo.output`, which is + // only populated once the job is already terminal — so it emitted + // nothing at all until the job finished, then dumped everything in + // one lump. This drives a real job through a real `WorkerPool` and + // asserts the first chunk arrives (and the job is still `running`) + // well before the job's own sleep would let it finish. + use tokio_stream::StreamExt as _; + let dir = tempfile::tempdir().unwrap(); + let queue = Queue::open_memory(dir.path().join("logs")).unwrap(); + let mut pool = agentflare_jobs::WorkerPool::new(queue.clone()); + pool.start(1); + + let (cmd, args): (&str, Vec<&str>) = if cfg!(windows) { + ("cmd", vec!["/c", "echo tick1 & timeout /t 2 & echo tick2"]) + } else { + ("sh", vec!["-c", "echo tick1; sleep 2; echo tick2"]) + }; + let info = queue.enqueue(&agentflare_jobs::AgentJob::new(cmd).args(args)).unwrap(); + let id = info.id.clone(); + + let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) + .await + .unwrap(); + let addr = listener.local_addr().unwrap(); + let queue_for_router = queue.clone(); + tokio::spawn(async move { + axum::serve(listener, router(queue_for_router)).await.unwrap(); + }); + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + + let resp = reqwest::get(format!("http://{addr}/api/jobs/{id}/stream")) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + let mut stream = resp.bytes_stream(); + + let mut all_text = String::new(); + let mut state_at_first_tick: Option = None; + loop { + match tokio::time::timeout(std::time::Duration::from_secs(5), stream.next()).await { + Ok(Some(Ok(chunk))) => { + all_text.push_str(&String::from_utf8_lossy(&chunk)); + if state_at_first_tick.is_none() && all_text.contains("tick1") { + let fetched: serde_json::Value = + reqwest::get(format!("http://{addr}/api/jobs?id={id}")) + .await + .unwrap() + .json() + .await + .unwrap(); + state_at_first_tick = + Some(fetched["state"].as_str().unwrap_or("").to_string()); + } + if all_text.contains("event: done") { + break; + } + } + Ok(Some(Err(_))) => break, + Ok(None) => break, + Err(_) => break, + } + } + pool.shutdown(); + + assert_eq!( + state_at_first_tick.as_deref(), + Some("running"), + "expected the job to still be running when the first chunk arrived, got: {state_at_first_tick:?}" + ); + assert!( + all_text.contains("tick1") && all_text.contains("tick2"), + "expected both ticks in stream, got: {all_text}" + ); + } + #[tokio::test] async fn events_endpoint_streams_claims_and_cost_snapshot() { use tokio_stream::StreamExt as _; From 1a1aece4e5d2fc13bd65dc3ca31c910188eeaf26 Mon Sep 17 00:00:00 2001 From: shiva Date: Thu, 30 Jul 2026 19:18:31 +0530 Subject: [PATCH 15/19] fix(daemon): close TOCTOU race between concurrent serve invocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ServeArgs::run() checked is_daemon_running() then wrote its pid file as two separate steps with nothing serializing them, so two direct `agentflare serve` invocations (e.g. on different --port values) started within moments of each other could both pass the check before either had written its pid file, recreating the exact multi-instance bug this singleton check exists to prevent. Adds a dedicated short-timeout lock file for this check-then-write section. It has to be a different lock from daemon_start_lock_path(): start_daemon() holds that one for its whole ~5s spawn-and-poll window, and the process it spawns calls back into this same check via `serve --_foreground-daemon` — sharing one lock would deadlock the two. --- src/cli/serve.rs | 33 ++++++++++++++++++++++----------- src/daemon.rs | 32 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/cli/serve.rs b/src/cli/serve.rs index b0eae1ac..b00e7c44 100644 --- a/src/cli/serve.rs +++ b/src/cli/serve.rs @@ -26,17 +26,28 @@ pub struct ServeArgs { impl ServeArgs { pub fn run(self) { - if let Some(pid) = crate::daemon::is_daemon_running() { - eprintln!("agentflare dashboard is already running (pid {pid})."); - eprintln!( - "stop it first with `agentflare daemon stop`, or use the running instance instead of starting another." - ); - std::process::exit(1); - } - if let Err(e) = crate::daemon::write_pid_file() { - eprintln!( - "warning: failed to record daemon pid ({e}); `agentflare daemon status`/`stop` won't see this instance." - ); + // Scoped so the lock is released before `dashboard::serve` (which + // never returns in normal operation) rather than held for the + // server's whole lifetime. + { + let guard = crate::daemon::acquire_singleton_lock(); + if let Err(ref e) = guard { + eprintln!( + "warning: failed to acquire daemon singleton lock ({e}); proceeding without race protection against a concurrent `serve` invocation." + ); + } + if let Some(pid) = crate::daemon::is_daemon_running() { + eprintln!("agentflare dashboard is already running (pid {pid})."); + eprintln!( + "stop it first with `agentflare daemon stop`, or use the running instance instead of starting another." + ); + std::process::exit(1); + } + if let Err(e) = crate::daemon::write_pid_file() { + eprintln!( + "warning: failed to record daemon pid ({e}); `agentflare daemon status`/`stop` won't see this instance." + ); + } } crate::dashboard::serve(&self.host, self.port, self.open, self.yes_expose); } diff --git a/src/daemon.rs b/src/daemon.rs index 4bcbb71e..81811df8 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -16,6 +16,12 @@ pub fn daemon_start_lock_path() -> PathBuf { .unwrap_or_else(|| std::env::temp_dir().join("agentflare-daemon.start.lock")) } +fn daemon_singleton_lock_path() -> PathBuf { + dirs::runtime_dir() + .map(|d| d.join("agentflare").join("daemon.singleton.lock")) + .unwrap_or_else(|| std::env::temp_dir().join("agentflare-daemon.singleton.lock")) +} + pub fn cleanup_daemon_files() { let pid_path = daemon_pid_path(); let _ = std::fs::remove_file(&pid_path); @@ -37,7 +43,25 @@ impl Drop for LockGuard { } pub fn acquire_start_lock() -> Result { - let lock_path = daemon_start_lock_path(); + acquire_lock(daemon_start_lock_path(), Duration::from_secs(5)) +} + +/// Serializes the is_daemon_running-check + write_pid_file critical section +/// in `ServeArgs::run()`, so two `agentflare serve` invocations racing each +/// other (e.g. on different `--port`s, started within moments of each other) +/// can't both pass the check before either has written its pid file. +/// +/// Deliberately a *different* lock file from `daemon_start_lock_path()`: +/// `start_daemon()` holds that lock for its whole ~5s spawn-and-poll window, +/// and the process it spawns calls back into this same check via +/// `serve --_foreground-daemon` — sharing one lock would deadlock the two +/// (parent waiting on the child's pid file while holding the lock the child +/// needs to write it). +pub fn acquire_singleton_lock() -> Result { + acquire_lock(daemon_singleton_lock_path(), Duration::from_secs(2)) +} + +fn acquire_lock(lock_path: PathBuf, timeout: Duration) -> Result { if let Some(parent) = lock_path.parent() { std::fs::create_dir_all(parent).map_err(|e| format!("create lock dir {parent:?}: {e}"))?; } @@ -47,7 +71,7 @@ pub fn acquire_start_lock() -> Result { .truncate(false) .open(&lock_path) .map_err(|e| format!("open lock file: {e}"))?; - let deadline = std::time::Instant::now() + Duration::from_secs(5); + let deadline = std::time::Instant::now() + timeout; loop { if file.try_lock_exclusive().is_ok() { return Ok(LockGuard { @@ -56,9 +80,9 @@ pub fn acquire_start_lock() -> Result { }); } if std::time::Instant::now() >= deadline { - return Err("could not acquire daemon start lock within 5s".to_string()); + return Err(format!("could not acquire lock within {timeout:?}")); } - std::thread::sleep(Duration::from_millis(100)); + std::thread::sleep(Duration::from_millis(50)); } } From 4583cd568db0e859d690bf87e4719c2539ef0b72 Mon Sep 17 00:00:00 2001 From: shiva Date: Thu, 30 Jul 2026 19:18:35 +0530 Subject: [PATCH 16/19] fix(dashboard): close stale job stream before selecting a new one selectJob() opened a new EventSource without closing detailSource from a previously selected job, so its events could keep appending into the newly selected job's detailOutput. Not reachable through the current UI (the list view is hidden while a job is selected), but a latent resource leak and cross-talk bug for any future code path that calls selectJob twice in a row. --- dashboard/web/jobs.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dashboard/web/jobs.html b/dashboard/web/jobs.html index abe73ff6..f878b47e 100644 --- a/dashboard/web/jobs.html +++ b/dashboard/web/jobs.html @@ -197,6 +197,13 @@

    Job &1 & echo world 1>&2"]) + ("cmd", vec!["/c", "echo hello & echo world 1>&2"]) } else { ("sh", vec!["-c", "echo hello; echo world 1>&2"]) }; diff --git a/crates/agentflare-jobs/tests/supervisor_test.rs b/crates/agentflare-jobs/tests/supervisor_test.rs index 26f5c381..2486cb10 100644 --- a/crates/agentflare-jobs/tests/supervisor_test.rs +++ b/crates/agentflare-jobs/tests/supervisor_test.rs @@ -131,7 +131,7 @@ fn cwd_is_applied_to_child() { #[test] fn stdout_and_stderr_are_captured_separately() { let (cmd, args) = if cfg!(windows) { - ("cmd", vec!["/c", "echo out-line 1>&1 & echo err-line 1>&2"]) + ("cmd", vec!["/c", "echo out-line & echo err-line 1>&2"]) } else { ("sh", vec!["-c", "echo out-line; echo err-line 1>&2"]) }; diff --git a/src/dashboard/server.rs b/src/dashboard/server.rs index 6efd1bd0..0b17c246 100644 --- a/src/dashboard/server.rs +++ b/src/dashboard/server.rs @@ -7,9 +7,9 @@ use axum::{ response::{IntoResponse, Response}, routing::get, }; -use std::io::Read; use rust_embed::RustEmbed; use serde::Deserialize; +use std::io::Read; use std::path::PathBuf; #[derive(RustEmbed)] @@ -364,9 +364,8 @@ async fn jobs_handler(State(queue): State, Query(q): Query) -> async fn jobs_events_handler( State(queue): State, ) -> Sse>> { - let (tx, rx) = tokio::sync::mpsc::unbounded_channel::< - Result, - >(); + let (tx, rx) = + tokio::sync::mpsc::unbounded_channel::>(); tokio::spawn(async move { let mut ticker = tokio::time::interval(TICK); loop { @@ -413,10 +412,7 @@ async fn jobs_events_handler( /// as SSE `data:` events. Once the job reaches a terminal state /// (exited/failed/killed), any remaining buffered content is flushed, a /// final `event: done\ndata:` frame is sent, and the stream closes. -async fn jobs_stream_handler( - State(queue): State, - Path(id): Path, -) -> Response { +async fn jobs_stream_handler(State(queue): State, Path(id): Path) -> Response { // 404 on unknown id before spawning anything. let exists = tokio::task::spawn_blocking({ let queue = queue.clone(); @@ -429,9 +425,8 @@ async fn jobs_stream_handler( return (StatusCode::NOT_FOUND, "job not found").into_response(); } let stdout_path = queue.log_dir().join(format!("{id}.stdout")); - let (tx, rx) = tokio::sync::mpsc::unbounded_channel::< - Result, - >(); + let (tx, rx) = + tokio::sync::mpsc::unbounded_channel::>(); tokio::spawn(async move { let mut interval = tokio::time::interval(std::time::Duration::from_millis(300)); let mut offset: u64 = 0; @@ -793,7 +788,10 @@ mod tests { .expect("SSE data line"); let v: serde_json::Value = serde_json::from_str(data_line).unwrap(); assert!(v.is_array(), "expected JSON array, got: {v}"); - assert!(!v.as_array().unwrap().is_empty(), "expected at least one job"); + assert!( + !v.as_array().unwrap().is_empty(), + "expected at least one job" + ); } #[tokio::test] @@ -850,12 +848,7 @@ mod tests { // Collect all SSE frames with a timeout. let mut all_text = String::new(); loop { - match tokio::time::timeout( - std::time::Duration::from_secs(5), - stream.next(), - ) - .await - { + match tokio::time::timeout(std::time::Duration::from_secs(5), stream.next()).await { Ok(Some(Ok(chunk))) => { all_text.push_str(&String::from_utf8_lossy(&chunk)); if all_text.contains("event: done") { @@ -892,7 +885,9 @@ mod tests { } else { ("sh", vec!["-c", "echo tick1; sleep 2; echo tick2"]) }; - let info = queue.enqueue(&agentflare_jobs::AgentJob::new(cmd).args(args)).unwrap(); + let info = queue + .enqueue(&agentflare_jobs::AgentJob::new(cmd).args(args)) + .unwrap(); let id = info.id.clone(); let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0)) @@ -901,7 +896,9 @@ mod tests { let addr = listener.local_addr().unwrap(); let queue_for_router = queue.clone(); tokio::spawn(async move { - axum::serve(listener, router(queue_for_router)).await.unwrap(); + axum::serve(listener, router(queue_for_router)) + .await + .unwrap(); }); tokio::time::sleep(std::time::Duration::from_millis(100)).await; From 180afca6031fafb732d439fc01e14efbcc198a7c Mon Sep 17 00:00:00 2001 From: shiva Date: Thu, 30 Jul 2026 19:48:05 +0530 Subject: [PATCH 18/19] fix(ci): replace Windows 'timeout /t' with a redirection-safe ping sleep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit timeout /t exits instantly with 'INPUT REDIRECTION IS NOT SUPPORTED' when stdin isn't a real console — which it never is under Supervisor (Stdio::null()). Both the new still-running-job stream test and timeout_kills_long_running_process used it as their Windows sleep stand-in, so the whole job finished near-instantly on Windows instead of actually running for the intended duration. Switches both to the standard ping-against-loopback idiom, which doesn't touch stdin. --- crates/agentflare-jobs/tests/supervisor_test.rs | 6 +++++- src/dashboard/server.rs | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/agentflare-jobs/tests/supervisor_test.rs b/crates/agentflare-jobs/tests/supervisor_test.rs index 2486cb10..28a15f03 100644 --- a/crates/agentflare-jobs/tests/supervisor_test.rs +++ b/crates/agentflare-jobs/tests/supervisor_test.rs @@ -55,7 +55,11 @@ fn exit_failure_reports_nonzero_code() { #[test] fn timeout_kills_long_running_process() { let (cmd, args) = if cfg!(windows) { - ("cmd", vec!["/c", "timeout /t 30"]) + // `timeout /t` refuses to run with redirected stdin ("INPUT + // REDIRECTION IS NOT SUPPORTED") and exits instantly instead of + // sleeping — `ping` against loopback is the standard + // redirection-safe stand-in for a long delay on Windows. + ("cmd", vec!["/c", "ping -n 31 127.0.0.1 >nul"]) } else { ("sleep", vec!["30"]) }; diff --git a/src/dashboard/server.rs b/src/dashboard/server.rs index 0b17c246..f99be454 100644 --- a/src/dashboard/server.rs +++ b/src/dashboard/server.rs @@ -881,7 +881,14 @@ mod tests { pool.start(1); let (cmd, args): (&str, Vec<&str>) = if cfg!(windows) { - ("cmd", vec!["/c", "echo tick1 & timeout /t 2 & echo tick2"]) + // `timeout /t` refuses to run with redirected stdin ("INPUT + // REDIRECTION IS NOT SUPPORTED") and exits instantly instead of + // sleeping — `ping` against loopback is the standard + // redirection-safe stand-in for a ~2s delay on Windows. + ( + "cmd", + vec!["/c", "echo tick1 & ping -n 3 127.0.0.1 >nul & echo tick2"], + ) } else { ("sh", vec!["-c", "echo tick1; sleep 2; echo tick2"]) }; From 02a58a76738239e72d92b5217a1843bade8ad3f3 Mon Sep 17 00:00:00 2001 From: shiva Date: Thu, 30 Jul 2026 19:54:34 +0530 Subject: [PATCH 19/19] fix(agentflare-jobs): close lost-wakeup race in wait_for_work/wake_workers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shutdown_returns_promptly_even_when_workers_are_idle flaked in CI (1.0003s instead of <300ms) — notify_all() alone only wakes threads already parked in wait_for, so a wake_workers() call landing between a worker's dequeue-check and its wait_for_work call was silently lost until the 1s fallback timeout. This was a real, if narrow, race in the notify design, not just a CI timing fluke — low local contention just made it rare enough to not reproduce. Fixes it with the standard predicate+Condvar pattern: a pending-signal bool guarded by the same lock, checked before ever blocking. A wake that arrives first is observed immediately when wait_for_work runs; one that arrives during the wait still notifies as before. No more lost-wakeup window in either ordering. Verified with 15 repeated local runs after the fix, all well under the timeout. --- crates/agentflare-jobs/src/queue.rs | 46 ++++++++++++++++++----------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/crates/agentflare-jobs/src/queue.rs b/crates/agentflare-jobs/src/queue.rs index 30a57061..96fabdf5 100644 --- a/crates/agentflare-jobs/src/queue.rs +++ b/crates/agentflare-jobs/src/queue.rs @@ -11,10 +11,13 @@ pub struct Queue { log_dir: PathBuf, // Wakes idle workers the moment a job becomes available (fresh enqueue, // or a retry going back to 'queued'), instead of them finding out only - // on their next poll. The paired Mutex<()> exists only because - // Condvar::wait_for needs a guard to attach to — there's no shared Rust - // state to protect, the real "state" lives in SQLite. - notify: Arc<(Mutex<()>, Condvar)>, + // on their next poll. The bool is a pending-signal flag, not app state: + // `notify_all()` alone only wakes threads already parked in `wait_for`, + // so a wake that lands between a worker's dequeue-check and its call to + // `wait_for_work` would otherwise be lost until the fallback timeout — + // the flag makes the signal durable across that race by having + // `wait_for_work` check it (under the same lock) before ever blocking. + notify: Arc<(Mutex, Condvar)>, } #[derive(Debug, thiserror::Error)] @@ -65,7 +68,7 @@ impl Queue { Ok(Self { conn: Arc::new(Mutex::new(conn)), log_dir, - notify: Arc::new((Mutex::new(()), Condvar::new())), + notify: Arc::new((Mutex::new(false), Condvar::new())), }) } @@ -74,7 +77,7 @@ impl Queue { Ok(Self { conn: Arc::new(Mutex::new(conn)), log_dir, - notify: Arc::new((Mutex::new(()), Condvar::new())), + notify: Arc::new((Mutex::new(false), Condvar::new())), }) } @@ -83,23 +86,32 @@ impl Queue { } /// Blocks the calling (worker) thread until a job becomes available or - /// `timeout` elapses, whichever comes first. The timeout is a safety net - /// against a missed wakeup (e.g. a notify firing just before this call - /// starts waiting) — normal pickup is near-instant via `notify`, not the - /// timeout. + /// `timeout` elapses, whichever comes first. Checks the pending-signal + /// flag before blocking, so a `wake_workers` call that landed just + /// before this one (e.g. between this worker's dequeue-check and this + /// call) is still observed immediately instead of being lost until + /// `timeout` — normal pickup is near-instant via `notify`, not the + /// timeout, in either ordering. pub fn wait_for_work(&self, timeout: Duration) { let (lock, cvar) = &*self.notify; - let mut guard = lock.lock(); - cvar.wait_for(&mut guard, timeout); + let mut signaled = lock.lock(); + if !*signaled { + cvar.wait_for(&mut signaled, timeout); + } + *signaled = false; } - /// Wakes every thread parked in `wait_for_work`, whether or not there's - /// actually a job for them (they just re-check `dequeue` either way). - /// Called after enqueueing/re-queueing a job, and by `WorkerPool::shutdown` - /// so workers notice a stop request immediately rather than up to + /// Wakes every thread parked in `wait_for_work` (or the next one to call + /// it, per the flag above), whether or not there's actually a job for + /// them — they just re-check `dequeue` either way. Called after + /// enqueueing/re-queueing a job, and by `WorkerPool::shutdown` so + /// workers notice a stop request immediately rather than up to /// `timeout` later. pub fn wake_workers(&self) { - self.notify.1.notify_all(); + let (lock, cvar) = &*self.notify; + let mut signaled = lock.lock(); + *signaled = true; + cvar.notify_all(); } pub fn enqueue(&self, job: &crate::types::AgentJob) -> Result {