From d6f2218756cdb0995e766c3455aedc3febbacbf8 Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Thu, 20 Aug 2026 19:32:56 +0000 Subject: [PATCH 01/13] Drop strict tool schemas on Claude routes --- strix/agents/factory.py | 57 ++++++++++++++++++++++----- strix/config/models.py | 15 +++++++ strix/core/runner.py | 6 +++ tests/test_agent_tool_registration.py | 16 ++++++++ tests/test_models.py | 22 +++++++++++ 5 files changed, 106 insertions(+), 10 deletions(-) diff --git a/strix/agents/factory.py b/strix/agents/factory.py index 9d599a54..a4833539 100644 --- a/strix/agents/factory.py +++ b/strix/agents/factory.py @@ -2,6 +2,7 @@ from __future__ import annotations +import dataclasses import inspect import json import logging @@ -222,6 +223,17 @@ def _with_coerced_arguments(tool: FunctionTool) -> FunctionTool: return tool +def _with_strictness(tool: FunctionTool, strict_schemas: bool) -> FunctionTool: + """Drop strict JSON-schema mode when the route can't take it (see + ``supports_strict_tool_schemas``); the tool stays functionally identical. + + Returns a copy so the shared tool singletons keep their declared mode. + """ + if strict_schemas or not tool.strict_json_schema: + return tool + return dataclasses.replace(tool, strict_json_schema=False) + + def _function_tool_with_error_result(tool: FunctionTool) -> FunctionTool: invoke_tool = tool.on_invoke_tool @@ -285,24 +297,38 @@ def _bound_custom_tool(tool: CustomTool) -> CustomTool: return tool -def _configure_filesystem_tools(toolset: Any, *, chat_completions: bool) -> None: +def _configure_filesystem_tools( + toolset: Any, *, chat_completions: bool, strict_schemas: bool = True +) -> None: for name, tool in vars(toolset).items(): if chat_completions: if isinstance(tool, CustomTool): setattr(toolset, name, _custom_tool_as_function_tool(tool)) elif isinstance(tool, FunctionTool): setattr( - toolset, name, _function_tool_with_error_result(_with_coerced_arguments(tool)) + toolset, + name, + _function_tool_with_error_result( + _with_strictness(_with_coerced_arguments(tool), strict_schemas) + ), ) elif isinstance(tool, CustomTool): setattr(toolset, name, _bound_custom_tool(tool)) elif isinstance(tool, FunctionTool): - setattr(toolset, name, _with_bounded_result(_with_coerced_arguments(tool))) + setattr( + toolset, + name, + _with_bounded_result( + _with_strictness(_with_coerced_arguments(tool), strict_schemas) + ), + ) -def _make_filesystem_configurator(*, chat_completions: bool) -> Any: +def _make_filesystem_configurator(*, chat_completions: bool, strict_schemas: bool) -> Any: def configure(toolset: Any) -> None: - _configure_filesystem_tools(toolset, chat_completions=chat_completions) + _configure_filesystem_tools( + toolset, chat_completions=chat_completions, strict_schemas=strict_schemas + ) return configure @@ -406,11 +432,13 @@ def _wrap_write_stdin(tool: FunctionTool) -> FunctionTool: return tool -def _configure_shell_tools(toolset: Any, *, chat_completions: bool) -> None: +def _configure_shell_tools( + toolset: Any, *, chat_completions: bool, strict_schemas: bool = True +) -> None: for name, tool in vars(toolset).items(): if not isinstance(tool, FunctionTool): continue - wrapped = _with_coerced_arguments(tool) + wrapped = _with_strictness(_with_coerced_arguments(tool), strict_schemas) if tool.name == "exec_command": wrapped = _wrap_exec_command(wrapped) elif tool.name == "write_stdin": @@ -420,9 +448,11 @@ def _configure_shell_tools(toolset: Any, *, chat_completions: bool) -> None: setattr(toolset, name, wrapped) -def _make_shell_configurator(*, chat_completions: bool) -> Any: +def _make_shell_configurator(*, chat_completions: bool, strict_schemas: bool) -> Any: def configure(toolset: Any) -> None: - _configure_shell_tools(toolset, chat_completions=chat_completions) + _configure_shell_tools( + toolset, chat_completions=chat_completions, strict_schemas=strict_schemas + ) return configure @@ -568,6 +598,7 @@ def build_strix_agent( is_whitebox: bool = False, interactive: bool = False, chat_completions_tools: bool = False, + strict_tool_schemas: bool = True, system_prompt_context: dict[str, Any] | None = None, extra_tools: Sequence[Tool] | None = None, instructions_override: str | None = None, @@ -577,6 +608,8 @@ def build_strix_agent( Args: chat_completions_tools: Wrap SDK custom tools as function tools when the selected backend cannot accept Responses custom tools. + strict_tool_schemas: Send function tools as strict-schema tools. Off + for routes that reject a toolset this size as strict. extra_tools: Additional tools for this scan agent only, on top of any registered via ``register_agent_tools``. instructions_override: Use this verbatim as the system prompt instead @@ -604,7 +637,7 @@ def build_strix_agent( tools = [*_BASE_TOOLS, *agent_tools, agent_finish] _ensure_unique_tool_names(tools) tools = [ - _with_bounded_result(_with_coerced_arguments(tool)) + _with_bounded_result(_with_strictness(_with_coerced_arguments(tool), strict_tool_schemas)) if isinstance(tool, FunctionTool) else tool for tool in tools @@ -630,11 +663,13 @@ def build_strix_agent( Filesystem( configure_tools=_make_filesystem_configurator( chat_completions=chat_completions_tools, + strict_schemas=strict_tool_schemas, ), ), Shell( configure_tools=_make_shell_configurator( chat_completions=chat_completions_tools, + strict_schemas=strict_tool_schemas, ), ), ], @@ -647,6 +682,7 @@ def make_child_factory( is_whitebox: bool = False, interactive: bool = False, chat_completions_tools: bool = False, + strict_tool_schemas: bool = True, system_prompt_context: dict[str, Any] | None = None, ) -> Any: """Return the runner-owned builder used by ``spawn_child_agent``. @@ -665,6 +701,7 @@ def make_child_factory( is_whitebox=is_whitebox, interactive=interactive, chat_completions_tools=chat_completions_tools, + strict_tool_schemas=strict_tool_schemas, system_prompt_context=system_prompt_context, ) diff --git a/strix/config/models.py b/strix/config/models.py index e632bb06..f6848ca4 100644 --- a/strix/config/models.py +++ b/strix/config/models.py @@ -749,6 +749,18 @@ def uses_chat_completions_tool_schema(model_name: str, settings: Settings) -> bo return not model_supports_reasoning(model_name) +def supports_strict_tool_schemas(model_name: str) -> bool: + """Return whether the route accepts strict tool schemas for Strix's toolset. + + Claude caps a request at 20 strict tools and 16 union-typed parameters + across all strict schemas. Strix ships ~30 tools and the strict dialect + turns every optional parameter into a nullable union, so both caps are + exceeded and the request is rejected outright. + """ + name = model_name.strip().lower() + return not any(marker in name for marker in _ANTHROPIC_MODEL_MARKERS) + + def model_supports_reasoning(model_name: str) -> bool: import litellm @@ -845,6 +857,9 @@ def is_known_openai_bare_model(model_name: str) -> bool: return bool(entry and entry.get("litellm_provider") == "openai") +_ANTHROPIC_MODEL_MARKERS = ("anthropic", "claude", "sonnet", "opus", "haiku") + + def is_claude_model(model_name: str) -> bool: return "claude" in (model_name or "").strip().lower() diff --git a/strix/core/runner.py b/strix/core/runner.py index b4afdfaf..0dfe75d0 100644 --- a/strix/core/runner.py +++ b/strix/core/runner.py @@ -22,6 +22,7 @@ from strix.config import load_settings from strix.config.models import ( StrixProvider, configure_sdk_model_defaults, + supports_strict_tool_schemas, uses_chat_completions_tool_schema, ) from strix.config.settings import DEFAULT_MAX_TURNS @@ -175,6 +176,9 @@ async def run_strix_scan( ) logger.info("LLM model resolved: %s", resolved_model) chat_completions_tools = uses_chat_completions_tool_schema(resolved_model, settings) + strict_tool_schemas = supports_strict_tool_schemas(resolved_model) + if not strict_tool_schemas: + logger.info("Sending non-strict tool schemas: %s caps strict tools", resolved_model) if coordinator is None: coordinator = AgentCoordinator() @@ -306,6 +310,7 @@ async def run_strix_scan( is_whitebox=is_whitebox, interactive=interactive, chat_completions_tools=chat_completions_tools, + strict_tool_schemas=strict_tool_schemas, system_prompt_context=root_context, instructions_override=root_instructions, ) @@ -324,6 +329,7 @@ async def run_strix_scan( is_whitebox=is_whitebox, interactive=interactive, chat_completions_tools=chat_completions_tools, + strict_tool_schemas=strict_tool_schemas, system_prompt_context=scope_context, ) diff --git a/tests/test_agent_tool_registration.py b/tests/test_agent_tool_registration.py index 7d002bdc..12f88f74 100644 --- a/tests/test_agent_tool_registration.py +++ b/tests/test_agent_tool_registration.py @@ -112,3 +112,19 @@ def test_wait_for_agents_is_available_in_both_modes() -> None: for interactive in (True, False): agent = factory.build_strix_agent(is_root=True, interactive=interactive) assert "wait_for_agents" in [t.name for t in agent.tools] + + +def test_strict_tool_schemas_can_be_disabled_per_route() -> None: + """Claude routes cap strict tools; the toolset must be sendable without strict.""" + agent = factory.build_strix_agent(is_root=True, strict_tool_schemas=False) + + function_tools = [t for t in agent.tools if isinstance(t, FunctionTool)] + assert function_tools + assert not any(t.strict_json_schema for t in function_tools) + + +def test_disabling_strict_leaves_shared_tools_untouched() -> None: + factory.build_strix_agent(is_root=True, strict_tool_schemas=False) + agent = factory.build_strix_agent(is_root=True) + + assert any(t.strict_json_schema for t in agent.tools if isinstance(t, FunctionTool)) diff --git a/tests/test_models.py b/tests/test_models.py index 10b01cc5..04bb2875 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,6 +9,7 @@ from strix.config.models import ( RECOMMENDED_MODEL_NAMES, is_recommended_or_frontier_model, request_timeout_extra_args, + supports_strict_tool_schemas, ) @@ -90,3 +91,24 @@ def test_frontier_model_families_are_accepted(model_name: str) -> None: ) def test_non_frontier_models_are_rejected(model_name: str) -> None: assert not is_recommended_or_frontier_model(model_name) + + +@pytest.mark.parametrize( + "model_name", + [ + "anthropic/claude-sonnet-4-6", + "bedrock/anthropic.claude-opus-4-8-v1:0", + "vertex_ai/claude-sonnet-5", + "Sonnet-5", + ], +) +def test_claude_routes_reject_strict_tool_schemas(model_name: str) -> None: + assert not supports_strict_tool_schemas(model_name) + + +@pytest.mark.parametrize( + "model_name", + ["openai/gpt-5.4", "gpt-5.4", "gemini/gemini-3.1-pro-preview", "deepseek/deepseek-v4"], +) +def test_other_routes_keep_strict_tool_schemas(model_name: str) -> None: + assert supports_strict_tool_schemas(model_name) From deb2057e20a60012eda4dcefce50f255a86a4d11 Mon Sep 17 00:00:00 2001 From: oyasumi <121568595+kusonooyasumi@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:36:01 -0400 Subject: [PATCH 02/13] fix(tui): preserve cost when state is truncated (#1086) Co-authored-by: oyasumi --- strix/interface/tui/backend/projection.py | 6 +++-- tests/test_tui_backend_server.py | 28 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/strix/interface/tui/backend/projection.py b/strix/interface/tui/backend/projection.py index 22fa957e..3469aa4d 100644 --- a/strix/interface/tui/backend/projection.py +++ b/strix/interface/tui/backend/projection.py @@ -146,7 +146,9 @@ def bounded_state_projection(state: dict[str, Any]) -> dict[str, Any]: } for message in state["messages"][-5:] ] - state["usage"] = {} + state["usage"] = { + key: state["usage"][key] for key in ("total_tokens", "cost") if key in state["usage"] + } state["error"] = terminal_projection(state["error"], max_string=512) state["model_warning"] = terminal_projection(state["model_warning"], max_string=256) state["caido_url"] = terminal_projection(state["caido_url"], max_string=256) @@ -173,7 +175,7 @@ def bounded_state_projection(state: dict[str, Any]) -> dict[str, Any]: "model_warning": "", "caido_url": None, "messages": [], - "usage": {}, + "usage": state["usage"], "subscription": state["subscription"], "viewer_status": state["viewer_status"], "viewer_url": None, diff --git a/tests/test_tui_backend_server.py b/tests/test_tui_backend_server.py index d3e08088..eb4e3239 100644 --- a/tests/test_tui_backend_server.py +++ b/tests/test_tui_backend_server.py @@ -13,7 +13,7 @@ from agents.tool import ToolOutputImage from strix.config.settings import DEFAULT_MAX_TURNS from strix.interface.tui.backend.controller import TuiController -from strix.interface.tui.backend.projection import terminal_projection +from strix.interface.tui.backend.projection import bounded_state_projection, terminal_projection from strix.interface.tui.backend.protocol import ( MAX_COMMAND_BYTES, PROTOCOL_CAPABILITIES, @@ -215,7 +215,11 @@ def test_unicode_heavy_setup_state_stays_within_control_frame_limit() -> None: "Any", SimpleNamespace( caido_url="https://δΎ‹γˆ.example/" + "道" * 10_000, - get_total_llm_usage=lambda: {f"model-{index}": "θ²»" * 10_000 for index in range(20)}, + get_total_llm_usage=lambda: { + "total_tokens": 720_400, + "cost": 20.0, + **{f"model-{index}": "πŸ”’" * 10_000 for index in range(20)}, + }, ), ) server = TuiBackendServer(controller) @@ -226,6 +230,26 @@ def test_unicode_heavy_setup_state_stays_within_control_frame_limit() -> None: assert len(encoded) <= MAX_COMMAND_BYTES assert "πŸ”’".encode() in encoded assert snapshot["projection_truncated"] is True + assert snapshot["usage"] == {"total_tokens": 720_400, "cost": 20.0} + + +def test_defensive_state_projection_preserves_usage_summary() -> None: + controller = TuiController(args()) + controller.report_state = cast( + "Any", + SimpleNamespace( + caido_url=None, + get_total_llm_usage=lambda: {"total_tokens": 720_400, "cost": 20.0}, + ), + ) + state = controller.snapshot() + state["provider"] = None + state["future_oversized_field"] = "x" * 100_000 + + snapshot = bounded_state_projection(state) + + assert snapshot["projection_truncated"] is True + assert snapshot["usage"] == {"total_tokens": 720_400, "cost": 20.0} @pytest.mark.asyncio From fe758af4fca92e566f49b599f96178f83105b13e Mon Sep 17 00:00:00 2001 From: OpenPay Date: Thu, 20 Aug 2026 23:40:12 +0300 Subject: [PATCH 03/13] fix(tui): use single space after ordered-list marker (#1043) --- .../interface/tui/internal/render/agent_message.go | 2 +- .../interface/tui/internal/render/markdown_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/strix/interface/tui/internal/render/agent_message.go b/strix/interface/tui/internal/render/agent_message.go index 84715223..a1ca50aa 100644 --- a/strix/interface/tui/internal/render/agent_message.go +++ b/strix/interface/tui/internal/render/agent_message.go @@ -100,7 +100,7 @@ func applyMarkdownStyles(text string) string { case strings.HasPrefix(line, "- "), strings.HasPrefix(line, "* "): out.WriteString(Col(Green).Render("β€’ ") + inlineFormat(line[2:])) case len(line) > 2 && line[0] >= '0' && line[0] <= '9' && (line[1:3] == ". " || line[1:3] == ") "): - out.WriteString(Col(Green).Render(string(line[0])+". ") + inlineFormat(line[2:])) + out.WriteString(Col(Green).Render(line[:2]+" ") + inlineFormat(line[3:])) case line == "---" || line == "***" || line == "___": out.WriteString(Col(Green).Render(strings.Repeat("─", 40))) default: diff --git a/strix/interface/tui/internal/render/markdown_test.go b/strix/interface/tui/internal/render/markdown_test.go index cd701e26..a887f995 100644 --- a/strix/interface/tui/internal/render/markdown_test.go +++ b/strix/interface/tui/internal/render/markdown_test.go @@ -72,6 +72,19 @@ func TestNonTablePipeLinesAreLeftAlone(t *testing.T) { } } +func TestMarkdownOrderedListsUseSingleSpaceAfterMarker(t *testing.T) { + out := renderAssistantMarkdown("1. hello\n2) world") + plain := ansi.Strip(out) + for _, want := range []string{"1. hello", "2) world"} { + if !strings.Contains(plain, want) { + t.Fatalf("ordered list item %q missing: %q", want, plain) + } + } + if strings.Contains(plain, "1. hello") || strings.Contains(plain, "2) world") { + t.Fatalf("double space after the list marker: %q", plain) + } +} + func TestInlineFormatKeepsNonEmphasisMarkers(t *testing.T) { literal := []string{ "ls *.py *.go", From e152c4c7c037a895b039d5fbdf469ac7b17a5ee9 Mon Sep 17 00:00:00 2001 From: RAJVARDHAN PATIL <95933896+vardhans07@users.noreply.github.com> Date: Fri, 21 Aug 2026 02:11:04 +0530 Subject: [PATCH 04/13] fix(report): raise RuntimeError on non-object run.json (fixes #1109) (#1116) --- strix/interface/cli_args.py | 2 +- tests/test_cli_target_list.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/strix/interface/cli_args.py b/strix/interface/cli_args.py index d354106a..42ebf18d 100644 --- a/strix/interface/cli_args.py +++ b/strix/interface/cli_args.py @@ -346,7 +346,7 @@ def _load_resume_state(args: argparse.Namespace, parser: argparse.ArgumentParser ) try: state = read_run_record(run_dir) - except RuntimeError as exc: + except (RuntimeError, TypeError) as exc: parser.error(f"--resume {args.resume}: run.json unreadable: {exc}") args.targets_info = state.get("targets_info") or [] diff --git a/tests/test_cli_target_list.py b/tests/test_cli_target_list.py index 9372ce5e..6ba4ca22 100644 --- a/tests/test_cli_target_list.py +++ b/tests/test_cli_target_list.py @@ -227,3 +227,18 @@ def test_resume_still_requires_targets_or_a_workspace( cli_main.parse_arguments() assert "has no targets_info" in capsys.readouterr().err + +def test_resume_non_object_run_json_exits(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]) -> None: + monkeypatch.chdir(tmp_path) + run_dir = tmp_path / "strix_runs" / "pentest_abcd" + run_dir.mkdir(parents=True) + (run_dir / "run.json").write_text("[]", encoding="utf-8") + + monkeypatch.setattr(sys, "argv", ["strix", "--resume", "pentest_abcd"]) + with pytest.raises(SystemExit) as exc_info: + cli_main.parse_arguments() + + assert exc_info.value.code == 2 + captured = capsys.readouterr() + assert "run.json unreadable" in captured.err + assert "not an object" in captured.err From b5ef93e7447297a06c158cd7140c3c25ba2c9dc5 Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Fri, 14 Aug 2026 15:06:58 +0000 Subject: [PATCH 05/13] feat(skills): add target-specific security testing skills (web app, API, OWASP Top 10, code review) --- AGENTS.md | 7 +++ README.md | 2 +- docs/integrations/coding-agents.mdx | 4 ++ skills/api-security-testing/SKILL.md | 56 +++++++++++++++++ .../SKILL.md | 57 +++++++++++++++++ skills/owasp-top-10-testing/SKILL.md | 62 +++++++++++++++++++ skills/web-app-penetration-testing/SKILL.md | 54 ++++++++++++++++ 7 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 skills/api-security-testing/SKILL.md create mode 100644 skills/find-security-vulnerabilities-in-code/SKILL.md create mode 100644 skills/owasp-top-10-testing/SKILL.md create mode 100644 skills/web-app-penetration-testing/SKILL.md diff --git a/AGENTS.md b/AGENTS.md index de2eac86..5356ef48 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,13 @@ npx skills add usestrix/strix - `fix-security-vulnerabilities-with-strix` β€” remediate findings and re-run Strix to verify - `ci-security-scanning-with-strix` β€” add PR scanning to CI/CD (self-hosted CLI or managed app) +Target-specific workflows built on the same engine: + +- `web-app-penetration-testing` β€” black-box pentest of a live web app or staging site +- `api-security-testing` β€” REST/GraphQL APIs and the OWASP API Security Top 10 (BOLA/IDOR, authz) +- `owasp-top-10-testing` β€” systematic OWASP Top 10 assessment with honest per-category coverage +- `find-security-vulnerabilities-in-code` β€” white-box review of a repo or working tree + **Two ways to run, same engine β€” pick per situation:** - **Open-source CLI (self-hosted):** free, fully local, BYO LLM key, needs Docker. Best for local dev loops, air-gapped/offline, and full control. diff --git a/README.md b/README.md index 96816114..9a160090 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Strix is agent-ready. Give Claude Code, Cursor, Codex, or any [SKILL.md-compatib npx skills add usestrix/strix ``` -This installs four skills: **penetration-testing-with-strix** (run headless scans and read results), **managed-pentesting-with-strix** (drive the managed [app.strix.ai](https://app.strix.ai) platform via REST β€” no local Docker or LLM key), **fix-security-vulnerabilities-with-strix** (remediate + re-scan to verify), and **ci-security-scanning-with-strix** (PR scanning in CI). Agents can run Strix two ways with the same engine β€” the open-source CLI locally, or the managed cloud when there's no local infra β€” and read [`AGENTS.md`](AGENTS.md) for a quick reference, [docs.strix.ai/llms.txt](https://docs.strix.ai/llms.txt) for the CLI docs, and [docs.app.strix.ai](https://docs.app.strix.ai) for the API. +This installs eight skills: **penetration-testing-with-strix** (run headless scans and read results), **managed-pentesting-with-strix** (drive the managed [app.strix.ai](https://app.strix.ai) platform via REST β€” no local Docker or LLM key), **fix-security-vulnerabilities-with-strix** (remediate + re-scan to verify), **ci-security-scanning-with-strix** (PR scanning in CI), plus target-specific workflows: **web-app-penetration-testing**, **api-security-testing**, **owasp-top-10-testing**, and **find-security-vulnerabilities-in-code**. Agents can run Strix two ways with the same engine β€” the open-source CLI locally, or the managed cloud when there's no local infra β€” and read [`AGENTS.md`](AGENTS.md) for a quick reference, [docs.strix.ai/llms.txt](https://docs.strix.ai/llms.txt) for the CLI docs, and [docs.app.strix.ai](https://docs.app.strix.ai) for the API. --- diff --git a/docs/integrations/coding-agents.mdx b/docs/integrations/coding-agents.mdx index fa2cea63..e027283c 100644 --- a/docs/integrations/coding-agents.mdx +++ b/docs/integrations/coding-agents.mdx @@ -19,6 +19,10 @@ npx skills add usestrix/strix | `managed-pentesting-with-strix` | Drive the managed [app.strix.ai](https://app.strix.ai) platform over REST β€” no local Docker or LLM key needed | | `fix-security-vulnerabilities-with-strix` | Triage findings, fix root causes, and re-run Strix to verify each fix | | `ci-security-scanning-with-strix` | Add PR security scanning to GitHub Actions or any CI (self-hosted CLI or managed app) | +| `web-app-penetration-testing` | Black-box pentest of a live web app or staging site β€” scope, credentials, and multi-account access-control testing | +| `api-security-testing` | Test a REST/GraphQL API against the OWASP API Security Top 10 β€” schema-driven enumeration, BOLA/IDOR, authz | +| `owasp-top-10-testing` | Systematic OWASP Top 10 assessment with honest per-category coverage | +| `find-security-vulnerabilities-in-code` | White-box security review of a repo or working tree, with exploits to confirm findings | Install a single skill with `npx skills add usestrix/strix --skill penetration-testing-with-strix`, or use one without installing: diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md new file mode 100644 index 00000000..d421a128 --- /dev/null +++ b/skills/api-security-testing/SKILL.md @@ -0,0 +1,56 @@ +--- +name: api-security-testing +description: Security-test a REST, GraphQL, or gRPC API with Strix β€” autonomous agents that enumerate endpoints from an OpenAPI/GraphQL schema (or by crawling), then actually exploit the API-specific vulnerability classes the OWASP API Security Top 10 covers: broken object-level authorization (BOLA/IDOR), broken function-level authorization, excessive data exposure, mass assignment, injection, SSRF, and auth/token flaws. Every finding comes with a working proof-of-concept request. Use when the user asks to pentest, security-test, audit, or find vulnerabilities in an API, endpoint, or backend service. +license: Apache-2.0 +metadata: + author: usestrix + homepage: https://docs.strix.ai +--- + +# Security-test an API + +APIs fail differently from web UIs: there's no rendered surface to crawl, the interesting bugs are authorization-shaped rather than injection-shaped, and the same endpoint behaves differently per token. This workflow targets those specifics with Strix's autonomous agents. + +Install, LLM setup, full CLI flags, and the managed-cloud path are in the **penetration-testing-with-strix** skill. Read it if `strix --version` fails or the target isn't an API. + +## 1. Gather what the agents need + +APIs are near-impossible to test blind, so collect first: + +| Input | Why it matters | +|---|---| +| **Schema** β€” OpenAPI/Swagger URL or file, GraphQL endpoint (introspection), or `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage. | +| **Two sets of credentials/tokens**, ideally in different tenants | BOLA/IDOR β€” the #1 API vulnerability class β€” can only be *proven* by accessing tenant A's objects with tenant B's token. | +| **A low-privilege and a high-privilege token** | Required to prove broken function-level authorization (a `user` calling admin-only routes). | +| **Example object IDs** | Lets agents test ID tampering immediately instead of hunting for valid identifiers. | +| **Out-of-scope routes** | Payments, mass notification, destructive admin endpoints. | +| **Rate limits / WAF** in front of the API | Avoids agents burning budget on throttled requests; mention them so testing adapts. | + +Ask the user for anything missing β€” don't fabricate tokens or scan an API they don't own. + +## 2. Run the scan + +```bash +strix -n -t https://api.staging.example.com --max-budget 20 \ + --instruction "OpenAPI spec: https://api.staging.example.com/openapi.json. +Tenant A token: (org 1111, user id 11, order id 501). +Tenant B token: (org 2222, user id 22). +Admin token: . +Focus: BOLA/IDOR across orgs, function-level authz on /admin/*, mass assignment on PATCH /users/{id}, excessive data exposure in list responses. +Out of scope: POST /billing/*, POST /notifications/broadcast." +``` + +- **Add the backend source for depth:** `-t ./services/api -t https://api.staging.example.com`. With code access the agents can reason about authorization checks and object ownership rather than inferring them from responses. +- **GraphQL:** point at the GraphQL endpoint and say whether introspection is enabled; call out that you want batching/aliasing abuse, depth/complexity limits, and per-field authorization tested. +- **Internal/private APIs** unreachable from your machine: use the managed platform's network connector β€” see **managed-pentesting-with-strix**. +- Use `--instruction-file` when the credential/context block gets long, and keep tokens out of shell history and out of committed files. + +## 3. Verify findings + +`strix_runs//penetration_test_report.md` first, then `vulnerabilities/*.md` β€” each contains the exact request that proved the issue. Replay it (e.g. with `curl`) before reporting; for authorization findings, confirm the response really contains the other tenant's data rather than an empty 200. + +`findings.sarif` uploads to GitHub code scanning; `vulnerabilities.json` is the structured index for ticketing. + +## 4. Fix, re-test, and keep it tested + +Remediate with **fix-security-vulnerabilities-with-strix** (fix the authorization check, not the single endpoint), then re-run against the same target to prove the exploit is dead. Wire it into pull-request CI with **ci-security-scanning-with-strix** so new endpoints get tested as they ship. diff --git a/skills/find-security-vulnerabilities-in-code/SKILL.md b/skills/find-security-vulnerabilities-in-code/SKILL.md new file mode 100644 index 00000000..da939a1e --- /dev/null +++ b/skills/find-security-vulnerabilities-in-code/SKILL.md @@ -0,0 +1,57 @@ +--- +name: find-security-vulnerabilities-in-code +description: Find security vulnerabilities in a codebase or repository with Strix β€” a white-box AI security review that reads your source, reasons about the actual data flow and authorization model, then exploits what it finds in a live sandbox so every reported issue has a working proof-of-concept instead of a noisy static-analysis alert. Covers injection, XSS, SSRF, broken access control and IDOR, insecure deserialization, secrets in code, unsafe dependencies, and business-logic flaws. Use when the user asks to security-scan, security-review, or audit their code, repo, or pull request for vulnerabilities. +license: Apache-2.0 +metadata: + author: usestrix + homepage: https://docs.strix.ai +--- + +# Find security vulnerabilities in code + +White-box security review with Strix: the agents read the source to build a model of routes, sinks, and authorization checks, then attempt real exploitation. Findings come with a proof-of-concept, so the output is a short list of proven issues rather than the hundreds of "potential" hits a pattern-matching scanner produces. + +Install, LLM setup, all flags, and the managed-cloud path are in the **penetration-testing-with-strix** skill. + +## Run it + +```bash +# Local working tree +strix -n -t ./ --scan-mode standard --max-budget 15 + +# A GitHub repo directly +strix -n -t https://github.com/org/app --max-budget 15 + +# Large monorepo: bind-mount instead of copying in +strix -n --mount ./huge-monorepo --max-budget 20 +``` + +Two things sharply improve results: + +1. **Add a running instance of the app.** `-t ./ -t http://host.docker.internal:3000` lets the agents confirm exploitability against live behavior instead of reasoning about it statically β€” this is the difference between "this looks unsafe" and a validated finding. If nothing is running, static-only findings should be described as unconfirmed. +2. **Scope the review.** Point at the risky subtree and say what matters: + ```bash + strix -n -t ./services/api --max-budget 15 \ + --instruction "Focus on the authorization layer in src/auth and every route under src/routes/admin. Multi-tenant app: tenant id comes from the JWT. Flag any query that filters by object id without also filtering by tenant." + ``` + Tenancy model, trust boundaries, and which inputs are attacker-controlled are things the agents can't infer reliably β€” tell them. + +## Reviewing a pull request instead of the whole repo + +For diff-scoped review of a branch or PR (and blocking merges on findings), use **ci-security-scanning-with-strix** β€” it covers diff scoping, PR comments, and SARIF upload to GitHub code scanning. The managed platform can also review PRs directly via API (**managed-pentesting-with-strix**). + +## Read the results + +In `strix_runs//`: `penetration_test_report.md` (start here), `vulnerabilities/*.md` (one per finding, with PoC and remediation), `vulnerabilities.json` / `.csv`, `findings.sarif` (upload to code scanning), `run.json`. + +Before reporting to the user, open each finding and check the PoC actually demonstrates impact. Report file and line alongside the exploit so the fix is obvious. + +Exit `0` means nothing exploitable was proven in what was analyzed β€” not that the codebase is clean. Check `run.json` status and cost against `--max-budget`, and note which paths went unreviewed if the run was capped. + +## Complementary tooling + +This is exploit-validated review, not an exhaustive inventory. Keep a dependency scanner (SCA) and secret scanning in place for complete coverage of known-CVE dependencies and committed credentials; use this for the logic, authorization, and injection bugs those tools structurally can't find. + +## Fix and verify + +Hand results to **fix-security-vulnerabilities-with-strix**: patch the root cause (the shared authorization helper, not the one route), then re-run Strix to prove the exploit no longer works. diff --git a/skills/owasp-top-10-testing/SKILL.md b/skills/owasp-top-10-testing/SKILL.md new file mode 100644 index 00000000..642c2c55 --- /dev/null +++ b/skills/owasp-top-10-testing/SKILL.md @@ -0,0 +1,62 @@ +--- +name: owasp-top-10-testing +description: Test an application against the OWASP Top 10 with Strix β€” autonomous AI agents that attempt real exploits for each category (broken access control, cryptographic failures, injection, insecure design, misconfiguration, vulnerable components, auth failures, integrity failures, logging gaps, SSRF) and report only what they could actually prove, mapped back to the category with a proof-of-concept. Also covers the OWASP API Security Top 10. Use when the user asks for an OWASP Top 10 assessment, OWASP compliance testing, or a security review mapped to OWASP categories. +license: Apache-2.0 +metadata: + author: usestrix + homepage: https://docs.strix.ai +--- + +# Test against the OWASP Top 10 + +The OWASP Top 10 is a taxonomy of risk categories, not a test suite β€” so "OWASP Top 10 testing" means exercising each category against the real application and reporting what's actually exploitable. Strix's agents do the exploitation; this skill covers running it category-by-category and honestly reporting coverage. + +Install, LLM setup, and the managed-cloud alternative: **penetration-testing-with-strix**. + +## What is and isn't testable by an agent + +Be straight with the user about this β€” claiming a clean sweep of all ten is misleading. + +| Category (2021) | Coverage | +|---|---| +| A01 Broken Access Control | **Strong** β€” needs two accounts (and a privileged one) to prove cross-user/tenant and privilege-escalation access. | +| A02 Cryptographic Failures | **Partial** β€” transport config, weak/absent encryption of data in transit, tokens and secrets exposed in responses; at-rest crypto needs source or infra review. | +| A03 Injection | **Strong** β€” SQL/NoSQL/command/template injection and XSS, exploit-validated. | +| A04 Insecure Design | **Partial** β€” business-logic abuse (price/quantity tampering, workflow skipping, race conditions) is found where reachable; design intent still needs human review. | +| A05 Security Misconfiguration | **Strong** β€” debug endpoints, verbose errors, permissive CORS, missing hardening, default credentials, exposed admin surfaces. | +| A06 Vulnerable & Outdated Components | **Partial** β€” version fingerprinting plus dependency review when source is supplied; use a dedicated SCA tool for exhaustive dependency inventory. | +| A07 Identification & Auth Failures | **Strong** β€” auth bypass, weak session/token handling, password-reset and MFA flaws. | +| A08 Software & Data Integrity Failures | **Partial** β€” insecure deserialization and unsigned-update paths where reachable; CI/CD supply-chain integrity is out of scope for a runtime scan. | +| A09 Logging & Monitoring Failures | **Not testable from outside** β€” requires reviewing the logging/alerting pipeline; state this rather than reporting it as passed. | +| A10 SSRF | **Strong** β€” exploit-validated, including blind SSRF via out-of-band callbacks. | + +For APIs, run the same exercise against the **OWASP API Security Top 10** (BOLA, broken function-level authz, mass assignment, excessive data exposure) using the **api-security-testing** skill. + +## Run it + +Maximum category coverage comes from giving the agents both the source and a running instance, plus credentials at two privilege levels: + +```bash +strix -n \ + -t https://github.com/org/app \ + -t https://staging.example.com \ + --scan-mode deep --max-budget 30 \ + --instruction "OWASP Top 10 (2021) assessment. Cover every category systematically and map each finding to its category. +Accounts: userA@example.com/ (org 1), userB@example.com/ (org 2), admin@example.com/. +Prioritise A01 (cross-org and privilege escalation), A03, A05, A07, A10. +Out of scope: /billing/*, outbound email." +``` + +- `--scan-mode deep` matters here: systematically walking ten categories is not a quick scan. +- Without a second account, A01 results are structurally incomplete β€” say so in the report rather than leaving it implied. +- Need an auditor-facing PDF mapped to categories? Run it through the managed platform and pull the technical report (**managed-pentesting-with-strix**). + +## Report honestly + +From `strix_runs//`, group `vulnerabilities/*.md` by OWASP category and state, per category: what was attempted, what was proven, and what couldn't be assessed (A09 always, A02/A06/A08 partially). Verify each PoC yourself before it goes in front of the user. + +A `0` exit code means nothing exploitable was proven **in what was analyzed** β€” check `run.json` status and cost against `--max-budget`; a budget-capped run is not a completed assessment. + +## Then fix and re-test + +Remediate with **fix-security-vulnerabilities-with-strix** and re-run to prove each exploit is closed. For ongoing coverage as the app changes, gate pull requests using **ci-security-scanning-with-strix**. diff --git a/skills/web-app-penetration-testing/SKILL.md b/skills/web-app-penetration-testing/SKILL.md new file mode 100644 index 00000000..b792166d --- /dev/null +++ b/skills/web-app-penetration-testing/SKILL.md @@ -0,0 +1,54 @@ +--- +name: web-app-penetration-testing +description: Pentest a web app or website end to end β€” black-box testing of a live URL, staging environment, or local dev server that finds and exploits real vulnerabilities (auth bypass, broken access control, IDOR, injection, XSS, SSRF, business logic) and proves each one with a working proof-of-concept instead of a signature match. Runs with Strix, either the self-hosted open-source CLI or the managed app.strix.ai cloud. Use when the user asks to pentest, hack, security-test, or audit their web app, website, web application, or staging site. +license: Apache-2.0 +metadata: + author: usestrix + homepage: https://docs.strix.ai +--- + +# Pentest a web application + +Black-box (and optionally source-assisted) penetration testing of a running web app with Strix's autonomous agents. Every reported finding is validated with a working exploit, so there are no signature-based false positives to triage. + +Install, LLM setup, all CLI flags, and the managed-cloud alternative are covered in the **penetration-testing-with-strix** skill β€” read it if the target isn't a running web app, or if `strix --version` fails. This skill is the web-app-specific workflow. + +## 1. Confirm authorization and scope + +Before running anything, establish: + +- **The target is the user's** (or they're explicitly authorized to test it). Never pentest a third-party site on a hunch. +- **Which environment.** Prefer staging over production; agents send real exploit payloads and will create/modify data. +- **Out-of-scope paths** β€” payment flows, mass-email endpoints, admin destructive actions, third-party SSO providers. +- **Credentials.** Most real vulnerabilities live behind login. Without a test account, the agents only ever see the marketing surface. + +Ask for anything missing rather than guessing. + +## 2. Run the scan + +```bash +strix -n -t https://staging.example.com --max-budget 20 \ + --instruction "Test account: qa@example.com / . In scope: /app/*, /api/*. Do not touch /billing or send email. Focus on access control between the two seeded orgs." +``` + +Notes that matter for web apps specifically: + +- **Give it credentials via `--instruction`** (or `--instruction-file` for anything long), including how to log in if the flow is unusual (magic link, SSO, MFA-exempt test user). +- **Two accounts beat one.** Multi-tenant IDOR and broken-access-control bugs β€” consistently the highest-impact class in web apps β€” can only be proven when the agent can attempt cross-account access. +- **Add the repo for white-box depth** when you have the source: `-t https://github.com/org/app -t https://staging.example.com` (or a local path). Source access materially improves coverage of business-logic and authorization flaws. +- **Localhost works.** Point at `http://host.docker.internal:3000` (Docker Desktop) so the sandbox can reach a dev server on the host. +- `--scan-mode quick` for a fast dev-loop pass, `standard` (~30 min) for a normal review, `deep` for pre-release assurance. Always set `--max-budget`. + +For a hosted run with no Docker/LLM key, or when the user wants a shareable dashboard and an auditor-ready PDF, use the cloud path in **managed-pentesting-with-strix** instead β€” same engine, same findings. + +## 3. Review results + +Read `strix_runs//penetration_test_report.md` first, then per-finding files in `vulnerabilities/`. Each contains the PoC β€” re-run it yourself to confirm before reporting to the user. + +Exit codes: `0` no validated vulns in what was analyzed, `2` vulnerabilities found, `1` fatal error. A `0` is not proof of full coverage β€” if the budget or turn cap was hit the scan wraps up early, so check `run.json` status and cost against `--max-budget` before calling the app clean. + +## 4. Fix and verify + +Hand findings to the **fix-security-vulnerabilities-with-strix** skill: patch the root cause, then re-run Strix against the same target to prove the exploit no longer works. Re-testing is the only reliable confirmation a fix landed. + +To keep the app tested on every change rather than once, wire Strix into CI with **ci-security-scanning-with-strix**. From 1b36343eea69c8eae66a7ace5f65423934e25025 Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Fri, 14 Aug 2026 15:07:26 +0000 Subject: [PATCH 06/13] fix(skills): avoid unquoted colon in api-security-testing description --- skills/api-security-testing/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md index d421a128..ebfaba98 100644 --- a/skills/api-security-testing/SKILL.md +++ b/skills/api-security-testing/SKILL.md @@ -1,6 +1,6 @@ --- name: api-security-testing -description: Security-test a REST, GraphQL, or gRPC API with Strix β€” autonomous agents that enumerate endpoints from an OpenAPI/GraphQL schema (or by crawling), then actually exploit the API-specific vulnerability classes the OWASP API Security Top 10 covers: broken object-level authorization (BOLA/IDOR), broken function-level authorization, excessive data exposure, mass assignment, injection, SSRF, and auth/token flaws. Every finding comes with a working proof-of-concept request. Use when the user asks to pentest, security-test, audit, or find vulnerabilities in an API, endpoint, or backend service. +description: Security-test a REST, GraphQL, or gRPC API with Strix β€” autonomous agents that enumerate endpoints from an OpenAPI/GraphQL schema (or by crawling), then actually exploit the API-specific vulnerability classes the OWASP API Security Top 10 covers β€” broken object-level authorization (BOLA/IDOR), broken function-level authorization, excessive data exposure, mass assignment, injection, SSRF, and auth/token flaws. Every finding comes with a working proof-of-concept request. Use when the user asks to pentest, security-test, audit, or find vulnerabilities in an API, endpoint, or backend service. license: Apache-2.0 metadata: author: usestrix From 634cb9824196698f1de4f8c53faa9415dcd58e0f Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Fri, 14 Aug 2026 15:12:04 +0000 Subject: [PATCH 07/13] docs(skills): use current OWASP editions (Top 10:2025, API Top 10 2023) --- skills/api-security-testing/SKILL.md | 10 ++++---- skills/owasp-top-10-testing/SKILL.md | 38 +++++++++++++++------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md index ebfaba98..2d60673d 100644 --- a/skills/api-security-testing/SKILL.md +++ b/skills/api-security-testing/SKILL.md @@ -1,6 +1,6 @@ --- name: api-security-testing -description: Security-test a REST, GraphQL, or gRPC API with Strix β€” autonomous agents that enumerate endpoints from an OpenAPI/GraphQL schema (or by crawling), then actually exploit the API-specific vulnerability classes the OWASP API Security Top 10 covers β€” broken object-level authorization (BOLA/IDOR), broken function-level authorization, excessive data exposure, mass assignment, injection, SSRF, and auth/token flaws. Every finding comes with a working proof-of-concept request. Use when the user asks to pentest, security-test, audit, or find vulnerabilities in an API, endpoint, or backend service. +description: Security-test a REST, GraphQL, or gRPC API with Strix β€” autonomous agents that enumerate endpoints from an OpenAPI/GraphQL schema (or by crawling), then actually exploit the API-specific vulnerability classes in the OWASP API Security Top 10 (2023) β€” broken object-level authorization (BOLA/IDOR), broken object property level authorization (excessive data exposure and mass assignment), broken function-level authorization, unrestricted resource consumption, SSRF, injection, and auth/token flaws. Every finding comes with a working proof-of-concept request. Use when the user asks to pentest, security-test, audit, or find vulnerabilities in an API, endpoint, or backend service. license: Apache-2.0 metadata: author: usestrix @@ -9,7 +9,7 @@ metadata: # Security-test an API -APIs fail differently from web UIs: there's no rendered surface to crawl, the interesting bugs are authorization-shaped rather than injection-shaped, and the same endpoint behaves differently per token. This workflow targets those specifics with Strix's autonomous agents. +APIs fail differently from web UIs: there's no rendered surface to crawl, the interesting bugs are authorization-shaped rather than injection-shaped, and the same endpoint behaves differently per token. This workflow targets those specifics with Strix's autonomous agents, using the current [OWASP API Security Top 10 (2023)](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) as the coverage checklist. For the web-app equivalent, the current edition is the OWASP Top 10:2025 β€” see **owasp-top-10-testing**. Install, LLM setup, full CLI flags, and the managed-cloud path are in the **penetration-testing-with-strix** skill. Read it if `strix --version` fails or the target isn't an API. @@ -20,8 +20,8 @@ APIs are near-impossible to test blind, so collect first: | Input | Why it matters | |---|---| | **Schema** β€” OpenAPI/Swagger URL or file, GraphQL endpoint (introspection), or `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage. | -| **Two sets of credentials/tokens**, ideally in different tenants | BOLA/IDOR β€” the #1 API vulnerability class β€” can only be *proven* by accessing tenant A's objects with tenant B's token. | -| **A low-privilege and a high-privilege token** | Required to prove broken function-level authorization (a `user` calling admin-only routes). | +| **Two sets of credentials/tokens**, ideally in different tenants | BOLA/IDOR β€” API1:2023, still the #1 API risk β€” can only be *proven* by accessing tenant A's objects with tenant B's token. | +| **A low-privilege and a high-privilege token** | Required to prove broken function-level authorization (API5:2023 β€” a `user` calling admin-only routes). | | **Example object IDs** | Lets agents test ID tampering immediately instead of hunting for valid identifiers. | | **Out-of-scope routes** | Payments, mass notification, destructive admin endpoints. | | **Rate limits / WAF** in front of the API | Avoids agents burning budget on throttled requests; mention them so testing adapts. | @@ -36,7 +36,7 @@ strix -n -t https://api.staging.example.com --max-budget 20 \ Tenant A token: (org 1111, user id 11, order id 501). Tenant B token: (org 2222, user id 22). Admin token: . -Focus: BOLA/IDOR across orgs, function-level authz on /admin/*, mass assignment on PATCH /users/{id}, excessive data exposure in list responses. +Focus: BOLA across orgs (API1), function-level authz on /admin/* (API5), object property level authz on PATCH /users/{id} β€” both mass assignment and over-exposed fields in list responses (API3), unrestricted resource consumption (API4). Out of scope: POST /billing/*, POST /notifications/broadcast." ``` diff --git a/skills/owasp-top-10-testing/SKILL.md b/skills/owasp-top-10-testing/SKILL.md index 642c2c55..ae57864d 100644 --- a/skills/owasp-top-10-testing/SKILL.md +++ b/skills/owasp-top-10-testing/SKILL.md @@ -1,6 +1,6 @@ --- name: owasp-top-10-testing -description: Test an application against the OWASP Top 10 with Strix β€” autonomous AI agents that attempt real exploits for each category (broken access control, cryptographic failures, injection, insecure design, misconfiguration, vulnerable components, auth failures, integrity failures, logging gaps, SSRF) and report only what they could actually prove, mapped back to the category with a proof-of-concept. Also covers the OWASP API Security Top 10. Use when the user asks for an OWASP Top 10 assessment, OWASP compliance testing, or a security review mapped to OWASP categories. +description: Test an application against the OWASP Top 10 with Strix β€” autonomous AI agents that attempt real exploits for each category of the current OWASP Top 10:2025 (broken access control including SSRF, security misconfiguration, software supply chain failures, cryptographic failures, injection, insecure design, authentication failures, integrity failures, logging and alerting failures, mishandling of exceptional conditions) and report only what they could actually prove, mapped back to the category with a proof-of-concept. Also covers the OWASP API Security Top 10 (2023). Use when the user asks for an OWASP Top 10 assessment, OWASP compliance testing, or a security review mapped to OWASP categories. license: Apache-2.0 metadata: author: usestrix @@ -9,7 +9,9 @@ metadata: # Test against the OWASP Top 10 -The OWASP Top 10 is a taxonomy of risk categories, not a test suite β€” so "OWASP Top 10 testing" means exercising each category against the real application and reporting what's actually exploitable. Strix's agents do the exploitation; this skill covers running it category-by-category and honestly reporting coverage. +The OWASP Top 10 is a taxonomy of risk categories, not a test suite β€” "OWASP Top 10 testing" means exercising each category against the real application and reporting what's actually exploitable. Strix's agents do the exploitation; this skill covers running it category-by-category and reporting coverage honestly. + +**Use the current edition: [OWASP Top 10:2025](https://owasp.org/Top10/)** (8th installment, superseding 2021). Ask the user before targeting an older edition β€” some compliance checklists still reference 2021, and a report labelled with the wrong edition is misleading. Key differences from 2021: **SSRF is folded into A01**, **A03 Software Supply Chain Failures** expands the old "Vulnerable and Outdated Components", and **A10 Mishandling of Exceptional Conditions** is new; A02 Security Misconfiguration moved 5β†’2. Install, LLM setup, and the managed-cloud alternative: **penetration-testing-with-strix**. @@ -17,20 +19,20 @@ Install, LLM setup, and the managed-cloud alternative: **penetration-testing-wit Be straight with the user about this β€” claiming a clean sweep of all ten is misleading. -| Category (2021) | Coverage | +| Category (2025) | Coverage | |---|---| -| A01 Broken Access Control | **Strong** β€” needs two accounts (and a privileged one) to prove cross-user/tenant and privilege-escalation access. | -| A02 Cryptographic Failures | **Partial** β€” transport config, weak/absent encryption of data in transit, tokens and secrets exposed in responses; at-rest crypto needs source or infra review. | -| A03 Injection | **Strong** β€” SQL/NoSQL/command/template injection and XSS, exploit-validated. | -| A04 Insecure Design | **Partial** β€” business-logic abuse (price/quantity tampering, workflow skipping, race conditions) is found where reachable; design intent still needs human review. | -| A05 Security Misconfiguration | **Strong** β€” debug endpoints, verbose errors, permissive CORS, missing hardening, default credentials, exposed admin surfaces. | -| A06 Vulnerable & Outdated Components | **Partial** β€” version fingerprinting plus dependency review when source is supplied; use a dedicated SCA tool for exhaustive dependency inventory. | -| A07 Identification & Auth Failures | **Strong** β€” auth bypass, weak session/token handling, password-reset and MFA flaws. | -| A08 Software & Data Integrity Failures | **Partial** β€” insecure deserialization and unsigned-update paths where reachable; CI/CD supply-chain integrity is out of scope for a runtime scan. | -| A09 Logging & Monitoring Failures | **Not testable from outside** β€” requires reviewing the logging/alerting pipeline; state this rather than reporting it as passed. | -| A10 SSRF | **Strong** β€” exploit-validated, including blind SSRF via out-of-band callbacks. | +| A01 Broken Access Control (incl. SSRF) | **Strong** β€” cross-user/tenant access, privilege escalation, IDOR, and SSRF (including blind, via out-of-band callbacks) are all exploit-validated. Needs two accounts plus a privileged one to prove the authorization half. | +| A02 Security Misconfiguration | **Strong** β€” debug endpoints, verbose errors, permissive CORS, missing hardening, default credentials, exposed admin surfaces. | +| A03 Software Supply Chain Failures | **Partial** β€” version fingerprinting, and vulnerable/outdated dependency review when source is supplied. Build-system and distribution-infrastructure compromise (the broader half of this category) is out of scope for a runtime scan β€” pair with SCA plus build-provenance controls. | +| A04 Cryptographic Failures | **Partial** β€” transport config, unencrypted data in transit, secrets and tokens leaked in responses. At-rest crypto and key management need source or infra review. | +| A05 Injection | **Strong** β€” SQL/NoSQL/command/template injection and XSS, exploit-validated. | +| A06 Insecure Design | **Partial** β€” business-logic abuse (price/quantity tampering, workflow skipping, race conditions) is found where reachable; design intent still needs human review and threat modelling. | +| A07 Authentication Failures | **Strong** β€” auth bypass, weak session/token handling, password-reset and MFA flaws. | +| A08 Software or Data Integrity Failures | **Partial** β€” insecure deserialization and unsigned-update paths where reachable; CI/CD trust boundaries are not runtime-testable. | +| A09 Security Logging & Alerting Failures | **Not testable from outside** β€” requires reviewing the logging and alerting pipeline. State this rather than reporting it as passed. | +| A10 Mishandling of Exceptional Conditions | **Partial** β€” agents actively probe error handling and fail-open behavior (malformed input, forced errors, race and timeout conditions) and report what leaks or bypasses a control; exhaustive coverage of internal error paths needs source review. | -For APIs, run the same exercise against the **OWASP API Security Top 10** (BOLA, broken function-level authz, mass assignment, excessive data exposure) using the **api-security-testing** skill. +For APIs, run the same exercise against the **OWASP API Security Top 10 (2023)** β€” API1 BOLA, API3 Broken Object Property Level Authorization (2019's excessive data exposure + mass assignment merged), API5 broken function-level authorization β€” using the **api-security-testing** skill. ## Run it @@ -41,19 +43,19 @@ strix -n \ -t https://github.com/org/app \ -t https://staging.example.com \ --scan-mode deep --max-budget 30 \ - --instruction "OWASP Top 10 (2021) assessment. Cover every category systematically and map each finding to its category. + --instruction "OWASP Top 10:2025 assessment. Cover every category systematically and map each finding to its 2025 category id. Accounts: userA@example.com/ (org 1), userB@example.com/ (org 2), admin@example.com/. -Prioritise A01 (cross-org and privilege escalation), A03, A05, A07, A10. +Prioritise A01 (cross-org access, privilege escalation, SSRF), A02, A05, A07, A10. Out of scope: /billing/*, outbound email." ``` - `--scan-mode deep` matters here: systematically walking ten categories is not a quick scan. - Without a second account, A01 results are structurally incomplete β€” say so in the report rather than leaving it implied. -- Need an auditor-facing PDF mapped to categories? Run it through the managed platform and pull the technical report (**managed-pentesting-with-strix**). +- Need an auditor-facing PDF? Run it through the managed platform and pull the technical report (**managed-pentesting-with-strix**). ## Report honestly -From `strix_runs//`, group `vulnerabilities/*.md` by OWASP category and state, per category: what was attempted, what was proven, and what couldn't be assessed (A09 always, A02/A06/A08 partially). Verify each PoC yourself before it goes in front of the user. +From `strix_runs//`, group `vulnerabilities/*.md` by category and state, per category: what was attempted, what was proven, and what couldn't be assessed (A09 always; A03/A04/A06/A08/A10 partially). Label the report with the edition used. Verify each PoC yourself before it goes in front of the user. A `0` exit code means nothing exploitable was proven **in what was analyzed** β€” check `run.json` status and cost against `--max-budget`; a budget-capped run is not a completed assessment. From 9099710cef9600222cb7f62a5b77f9c18db5105d Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Thu, 20 Aug 2026 20:28:44 +0000 Subject: [PATCH 08/13] docs(skills): fix nonexistent --mount flag, document real targeting flags, add application-security-testing skill - Remove --mount from two skills: the flag does not exist in the CLI. Local paths are mounted writable when passed with -t. - Document --target-list, --scope-mode, --diff-base, and OpenAPI/Postman targets, so agents stop putting spec URLs in --instruction prose. - Add the application-security-testing skill as the entry point for whole-product AppSec requests, routing each asset to the right workflow. - Drop contractions and Latin abbreviations across the skill prose. --- AGENTS.md | 1 + README.md | 2 +- docs/integrations/coding-agents.mdx | 1 + skills/api-security-testing/SKILL.md | 19 +++--- skills/application-security-testing/SKILL.md | 66 +++++++++++++++++++ .../ci-security-scanning-with-strix/SKILL.md | 10 +-- .../SKILL.md | 13 ++-- .../SKILL.md | 4 +- skills/managed-pentesting-with-strix/SKILL.md | 8 +-- skills/owasp-top-10-testing/SKILL.md | 4 +- .../penetration-testing-with-strix/SKILL.md | 24 ++++--- skills/web-app-penetration-testing/SKILL.md | 4 +- 12 files changed, 120 insertions(+), 36 deletions(-) create mode 100644 skills/application-security-testing/SKILL.md diff --git a/AGENTS.md b/AGENTS.md index 5356ef48..b347278b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,6 +17,7 @@ npx skills add usestrix/strix Target-specific workflows built on the same engine: +- `application-security-testing` β€” whole-product AppSec review: pick the right test per asset, then rank the results - `web-app-penetration-testing` β€” black-box pentest of a live web app or staging site - `api-security-testing` β€” REST/GraphQL APIs and the OWASP API Security Top 10 (BOLA/IDOR, authz) - `owasp-top-10-testing` β€” systematic OWASP Top 10 assessment with honest per-category coverage diff --git a/README.md b/README.md index 9a160090..ddec31db 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Strix is agent-ready. Give Claude Code, Cursor, Codex, or any [SKILL.md-compatib npx skills add usestrix/strix ``` -This installs eight skills: **penetration-testing-with-strix** (run headless scans and read results), **managed-pentesting-with-strix** (drive the managed [app.strix.ai](https://app.strix.ai) platform via REST β€” no local Docker or LLM key), **fix-security-vulnerabilities-with-strix** (remediate + re-scan to verify), **ci-security-scanning-with-strix** (PR scanning in CI), plus target-specific workflows: **web-app-penetration-testing**, **api-security-testing**, **owasp-top-10-testing**, and **find-security-vulnerabilities-in-code**. Agents can run Strix two ways with the same engine β€” the open-source CLI locally, or the managed cloud when there's no local infra β€” and read [`AGENTS.md`](AGENTS.md) for a quick reference, [docs.strix.ai/llms.txt](https://docs.strix.ai/llms.txt) for the CLI docs, and [docs.app.strix.ai](https://docs.app.strix.ai) for the API. +This installs nine skills: **penetration-testing-with-strix** (run headless scans and read results), **managed-pentesting-with-strix** (drive the managed [app.strix.ai](https://app.strix.ai) platform via REST β€” no local Docker or LLM key), **fix-security-vulnerabilities-with-strix** (remediate + re-scan to verify), **ci-security-scanning-with-strix** (PR scanning in CI), plus target-specific workflows: **application-security-testing**, **web-app-penetration-testing**, **api-security-testing**, **owasp-top-10-testing**, and **find-security-vulnerabilities-in-code**. Agents can run Strix two ways with the same engine β€” the open-source CLI locally, or the managed cloud when there's no local infra β€” and read [`AGENTS.md`](AGENTS.md) for a quick reference, [docs.strix.ai/llms.txt](https://docs.strix.ai/llms.txt) for the CLI docs, and [docs.app.strix.ai](https://docs.app.strix.ai) for the API. --- diff --git a/docs/integrations/coding-agents.mdx b/docs/integrations/coding-agents.mdx index e027283c..59e598f1 100644 --- a/docs/integrations/coding-agents.mdx +++ b/docs/integrations/coding-agents.mdx @@ -19,6 +19,7 @@ npx skills add usestrix/strix | `managed-pentesting-with-strix` | Drive the managed [app.strix.ai](https://app.strix.ai) platform over REST β€” no local Docker or LLM key needed | | `fix-security-vulnerabilities-with-strix` | Triage findings, fix root causes, and re-run Strix to verify each fix | | `ci-security-scanning-with-strix` | Add PR security scanning to GitHub Actions or any CI (self-hosted CLI or managed app) | +| `application-security-testing` | Assess a whole product: choose the right test for each asset, then rank the findings into one remediation plan | | `web-app-penetration-testing` | Black-box pentest of a live web app or staging site β€” scope, credentials, and multi-account access-control testing | | `api-security-testing` | Test a REST/GraphQL API against the OWASP API Security Top 10 β€” schema-driven enumeration, BOLA/IDOR, authz | | `owasp-top-10-testing` | Systematic OWASP Top 10 assessment with honest per-category coverage | diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md index 2d60673d..628c0c8c 100644 --- a/skills/api-security-testing/SKILL.md +++ b/skills/api-security-testing/SKILL.md @@ -9,9 +9,9 @@ metadata: # Security-test an API -APIs fail differently from web UIs: there's no rendered surface to crawl, the interesting bugs are authorization-shaped rather than injection-shaped, and the same endpoint behaves differently per token. This workflow targets those specifics with Strix's autonomous agents, using the current [OWASP API Security Top 10 (2023)](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) as the coverage checklist. For the web-app equivalent, the current edition is the OWASP Top 10:2025 β€” see **owasp-top-10-testing**. +APIs fail differently from web UIs: there is no rendered surface to crawl, the interesting bugs are authorization-shaped rather than injection-shaped, and the same endpoint behaves differently per token. This workflow targets those specifics with Strix's autonomous agents, using the current [OWASP API Security Top 10 (2023)](https://owasp.org/API-Security/editions/2023/en/0x11-t10/) as the coverage checklist. For the web-app equivalent, the current edition is the OWASP Top 10:2025 β€” see **owasp-top-10-testing**. -Install, LLM setup, full CLI flags, and the managed-cloud path are in the **penetration-testing-with-strix** skill. Read it if `strix --version` fails or the target isn't an API. +Install, LLM setup, full CLI flags, and the managed-cloud path are in the **penetration-testing-with-strix** skill. Read it if `strix --version` fails or the target is not an API. ## 1. Gather what the agents need @@ -19,27 +19,30 @@ APIs are near-impossible to test blind, so collect first: | Input | Why it matters | |---|---| -| **Schema** β€” OpenAPI/Swagger URL or file, GraphQL endpoint (introspection), or `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage. | +| **Schema** β€” OpenAPI/Swagger file, Postman collection, GraphQL endpoint (introspection), or `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage, and Strix takes a spec directly as a target. | | **Two sets of credentials/tokens**, ideally in different tenants | BOLA/IDOR β€” API1:2023, still the #1 API risk β€” can only be *proven* by accessing tenant A's objects with tenant B's token. | | **A low-privilege and a high-privilege token** | Required to prove broken function-level authorization (API5:2023 β€” a `user` calling admin-only routes). | | **Example object IDs** | Lets agents test ID tampering immediately instead of hunting for valid identifiers. | | **Out-of-scope routes** | Payments, mass notification, destructive admin endpoints. | | **Rate limits / WAF** in front of the API | Avoids agents burning budget on throttled requests; mention them so testing adapts. | -Ask the user for anything missing β€” don't fabricate tokens or scan an API they don't own. +Ask the user for anything missing β€” do not fabricate tokens or scan an API they do not own. ## 2. Run the scan +Pass the spec as a **target**, not as prose in the instruction β€” Strix parses OpenAPI/Swagger (`.json`/`.yaml`) and Postman collection exports directly, so the agents start from the real endpoint list: + ```bash -strix -n -t https://api.staging.example.com --max-budget 20 \ - --instruction "OpenAPI spec: https://api.staging.example.com/openapi.json. -Tenant A token: (org 1111, user id 11, order id 501). +strix -n -t ./openapi.yaml -t https://api.staging.example.com --max-budget 20 \ + --instruction "Tenant A token: (org 1111, user id 11, order id 501). Tenant B token: (org 2222, user id 22). Admin token: . Focus: BOLA across orgs (API1), function-level authz on /admin/* (API5), object property level authz on PATCH /users/{id} β€” both mass assignment and over-exposed fields in list responses (API3), unrestricted resource consumption (API4). Out of scope: POST /billing/*, POST /notifications/broadcast." ``` +- **Postman instead of OpenAPI:** a collection export works as a target (`-t ./collection.postman_collection.json`), or pull one live with `-t postman://` (optionally `"postman://?env="`), which needs `POSTMAN_API_KEY` in the environment. +- **Many services at once:** put one target per line in a file and pass `--target-list ./targets.txt`, repeatable and combinable with `-t`. - **Add the backend source for depth:** `-t ./services/api -t https://api.staging.example.com`. With code access the agents can reason about authorization checks and object ownership rather than inferring them from responses. - **GraphQL:** point at the GraphQL endpoint and say whether introspection is enabled; call out that you want batching/aliasing abuse, depth/complexity limits, and per-field authorization tested. - **Internal/private APIs** unreachable from your machine: use the managed platform's network connector β€” see **managed-pentesting-with-strix**. @@ -47,7 +50,7 @@ Out of scope: POST /billing/*, POST /notifications/broadcast." ## 3. Verify findings -`strix_runs//penetration_test_report.md` first, then `vulnerabilities/*.md` β€” each contains the exact request that proved the issue. Replay it (e.g. with `curl`) before reporting; for authorization findings, confirm the response really contains the other tenant's data rather than an empty 200. +`strix_runs//penetration_test_report.md` first, then `vulnerabilities/*.md` β€” each contains the exact request that proved the issue. Replay it (for example, with `curl`) before reporting; for authorization findings, confirm the response really contains the other tenant's data rather than an empty 200. `findings.sarif` uploads to GitHub code scanning; `vulnerabilities.json` is the structured index for ticketing. diff --git a/skills/application-security-testing/SKILL.md b/skills/application-security-testing/SKILL.md new file mode 100644 index 00000000..78a2f49f --- /dev/null +++ b/skills/application-security-testing/SKILL.md @@ -0,0 +1,66 @@ +--- +name: application-security-testing +description: Application security testing (AppSec) across a whole product with Strix β€” decide which asset needs which test (source code, running web app, API, CI pipeline), run it, and turn the results into a ranked remediation plan. Autonomous agents exploit and prove each issue instead of emitting static-analysis alerts, so the plan is ordered by what is actually reachable. Use when the user asks for an application security review or audit, an appsec assessment, vulnerability scanning across their stack, a security review before a launch or a customer security questionnaire, or does not yet know which kind of security test they need. +license: Apache-2.0 +metadata: + author: usestrix + homepage: https://docs.strix.ai +--- + +# Application security testing + +Entry point for "make my application secure" requests, where the target is not yet a single URL or repo. The job here is to pick the right test per asset, run it, and produce one ranked plan β€” not to run everything at maximum depth. + +Install, LLM setup, all CLI flags, and the managed-cloud path live in the **penetration-testing-with-strix** skill. Read it first if `strix --version` fails. + +Only test assets the user owns or is authorized to test. Confirm authorization before the first run, and prefer staging over production, because the agents send real exploit payloads and can change data. + +## 1. Map the assets + +Ask (or read from the repo) and write the answers down before scanning: + +- **Source** β€” one repo, a monorepo, several services? Which languages/frameworks? +- **Running environments** β€” is there a staging deployment? A public production site? A local dev server only? +- **APIs** β€” REST, GraphQL, gRPC? Is there an OpenAPI/GraphQL schema? +- **Authentication** β€” can you get two test accounts in different tenants? Most high-impact bugs need them. +- **Constraints** β€” out-of-scope paths, whether production may be touched, budget and wall-clock limits. + +If there is no staging environment and production is off limits, say so early. A code-only review is still valuable, but it cannot prove exploitability against a live app. + +## 2. Pick the right test per asset + +| Asset | Skill to use | +| --- | --- | +| Repository or working tree | **find-security-vulnerabilities-in-code** | +| Live web app or staging site | **web-app-penetration-testing** | +| REST/GraphQL/gRPC API | **api-security-testing** | +| Assessment mapped to OWASP categories | **owasp-top-10-testing** | +| Every pull request, continuously | **ci-security-scanning-with-strix** | +| No Docker, no LLM key, or a report an auditor will accept | **managed-pentesting-with-strix** | + +Those skills carry the flags, credential handling, and result-reading details. Do not duplicate their instructions here. + +Sequence for a first assessment: + +1. Review the code. It is the cheapest run and it maps the authorization model. +2. Pentest staging with credentials, and pass the repo as a second target so the agents keep source context. +3. Add CI scanning, so later regressions are caught without another manual pass. + +Run one asset at a time and read each report before starting the next. Findings from the code review make the live run sharper. + +## 3. Consolidate into one plan + +Findings arrive per run in `strix_runs//`. Merge them into a single list and rank by **proven impact**, not by scanner severity: + +1. Validated exploits reachable without authentication. +2. Validated cross-tenant or privilege-escalation issues. +3. Validated issues needing an authenticated account. +4. Unproven observations (configuration, dependency, and hardening notes) β€” flag as such, and never present them as confirmed vulnerabilities. + +Deduplicate: the same root cause often surfaces in both the code review and the live pentest. + +## 4. Be honest about coverage + +State plainly what was *not* tested β€” assets with no staging environment, categories a black-box run cannot reach (logging and alerting, supply-chain integrity, insecure design), and any run that hit its budget or turn cap before finishing. Check `run.json` status and cost against `--max-budget` for each run. An empty result set from a truncated scan is not a clean bill of health. + +Then remediate with **fix-security-vulnerabilities-with-strix**, which re-runs Strix against each fix to prove the exploit no longer works. diff --git a/skills/ci-security-scanning-with-strix/SKILL.md b/skills/ci-security-scanning-with-strix/SKILL.md index 10ed88ba..c53054bb 100644 --- a/skills/ci-security-scanning-with-strix/SKILL.md +++ b/skills/ci-security-scanning-with-strix/SKILL.md @@ -12,7 +12,7 @@ metadata: You can gate PRs two ways β€” pick based on the environment, or combine them: - **Managed platform (recommended for most teams)** β€” connect the GitHub/GitLab/Bitbucket app once and Strix reviews every PR with **no workflow file, no runner, no Docker, and no LLM key**. Results post as PR comments and land in the team dashboard. Best when you want zero CI maintenance, central tracking, or your runners lack Docker. See "Managed platform" below and the **managed-pentesting-with-strix** skill. -- **Self-hosted OSS CLI in your runner** β€” run a diff-scoped scan as a pipeline step. Fully in your infra, free (BYO LLM key), no external account. Requires Docker on the runner. Best for air-gapped/self-hosted CI or when you don't want scans leaving your environment. +- **Self-hosted OSS CLI in your runner** β€” run a diff-scoped scan as a pipeline step. Fully in your infra, free (BYO LLM key), no external account. Requires Docker on the runner. Best for air-gapped/self-hosted CI or when you do not want scans leaving your environment. Both fail the build on validated findings and both emit SARIF 2.1.0, so you can start with one and add the other later. @@ -63,13 +63,13 @@ jobs: fi ``` -Then tell the user to add two repository secrets: `STRIX_LLM` (model id, e.g. `openai/gpt-5.4`) and `LLM_API_KEY` (the provider key). Do not create these values yourself. +Then tell the user to add two repository secrets: `STRIX_LLM` (model id, for example `openai/gpt-5.4`) and `LLM_API_KEY` (the provider key). Do not create these values yourself. Notes: - In CI/headless runs Strix automatically scopes to the PR's changed files (`--scope-mode auto`). If diff resolution fails, keep `fetch-depth: 0` or set `--diff-base` to the PR's actual base branch β€” use `origin/${{ github.base_ref }}` in GitHub Actions rather than a hard-coded `origin/main`, since repos use different default branches. - Exit codes: `0` pass, `2` vulnerabilities found (fails the job), `1` setup error. - The runner needs Docker (default GitHub-hosted Ubuntu runners have it). -- **Size the budget so the scan completes β€” don't let it fail open.** A `0` exit means "no validated vulnerabilities in what was analyzed"; if `--max-budget` is hit before the diff is fully covered, the scan wraps up early and can still exit `0`. The "Fail unless the scan completed" step above narrows the gap: `strix_runs//run.json` is `"stopped"` when the scan was cut off at the hard budget limit without a final report. It is not a complete guard β€” the agents get graduated wrap-up warnings before that limit, and a run that wraps up on a warning still calls `finish_scan` and records `"completed"` with partial coverage. So keep that step in any pipeline that gates merges **and** give the scan real headroom (compare `run.json`'s `llm_usage.cost` against `--max-budget`; if it ran right up to the cap, raise it). For a `quick` diff-scoped PR scan `--max-budget 10` is usually ample, raise it for large diffs. +- **Size the budget so the scan completes β€” do not let it fail open.** A `0` exit means "no validated vulnerabilities in what was analyzed"; if `--max-budget` is hit before the diff is fully covered, the scan wraps up early and can still exit `0`. The "Fail unless the scan completed" step above narrows the gap: `strix_runs//run.json` is `"stopped"` when the scan was cut off at the hard budget limit without a final report. It is not a complete guard β€” the agents get graduated wrap-up warnings before that limit, and a run that wraps up on a warning still calls `finish_scan` and records `"completed"` with partial coverage. So keep that step in any pipeline that gates merges **and** give the scan real headroom (compare `run.json`'s `llm_usage.cost` against `--max-budget`; if it ran right up to the cap, raise it). For a `quick` diff-scoped PR scan `--max-budget 10` is usually ample, raise it for large diffs. ### Optional: upload findings to GitHub code scanning @@ -90,7 +90,7 @@ Any pipeline works the same way β€” install, set the two env vars, run headless: ```bash curl -sSL https://strix.ai/install | bash # Resolve the PR's base branch robustly (use your CI's base-branch variable if it -# has one, e.g. GitHub Actions: origin/${{ github.base_ref }}). Avoid piping the +# has one, for example GitHub Actions: origin/${{ github.base_ref }}). Avoid piping the # git lookup into another command β€” a failed lookup would otherwise be masked. BASE_BRANCH="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-}" # GitLab MR target if [ -z "$BASE_BRANCH" ]; then @@ -98,7 +98,7 @@ if [ -z "$BASE_BRANCH" ]; then BASE_BRANCH="${BASE_BRANCH#origin/}" fi DIFF_BASE="origin/${BASE_BRANCH:-main}" -# Fail loudly rather than silently narrowing scope (e.g. to HEAD~1, which on a +# Fail loudly rather than silently narrowing scope (for example, to HEAD~1, which on a # multi-commit branch would scan only the last commit and let earlier ones pass). if ! git rev-parse --verify --quiet "$DIFF_BASE" >/dev/null; then echo "Cannot resolve diff base '$DIFF_BASE'. Fetch the base branch (git fetch origin ) or set --diff-base explicitly." >&2 diff --git a/skills/find-security-vulnerabilities-in-code/SKILL.md b/skills/find-security-vulnerabilities-in-code/SKILL.md index da939a1e..61667c13 100644 --- a/skills/find-security-vulnerabilities-in-code/SKILL.md +++ b/skills/find-security-vulnerabilities-in-code/SKILL.md @@ -22,10 +22,15 @@ strix -n -t ./ --scan-mode standard --max-budget 15 # A GitHub repo directly strix -n -t https://github.com/org/app --max-budget 15 -# Large monorepo: bind-mount instead of copying in -strix -n --mount ./huge-monorepo --max-budget 20 +# Monorepo: point at the service that matters, not the whole tree +strix -n -t ./services/checkout --max-budget 20 + +# Only what a branch changed (whole-repo review is wasteful on a large repo) +strix -n -t ./ --scope-mode diff --diff-base origin/main --max-budget 10 ``` +A local path is mounted into the sandbox **writable**, so the agents can modify it. Run against a clean checkout. + Two things sharply improve results: 1. **Add a running instance of the app.** `-t ./ -t http://host.docker.internal:3000` lets the agents confirm exploitability against live behavior instead of reasoning about it statically β€” this is the difference between "this looks unsafe" and a validated finding. If nothing is running, static-only findings should be described as unconfirmed. @@ -34,7 +39,7 @@ Two things sharply improve results: strix -n -t ./services/api --max-budget 15 \ --instruction "Focus on the authorization layer in src/auth and every route under src/routes/admin. Multi-tenant app: tenant id comes from the JWT. Flag any query that filters by object id without also filtering by tenant." ``` - Tenancy model, trust boundaries, and which inputs are attacker-controlled are things the agents can't infer reliably β€” tell them. + Tenancy model, trust boundaries, and which inputs are attacker-controlled are things the agents cannot infer reliably β€” tell them. ## Reviewing a pull request instead of the whole repo @@ -50,7 +55,7 @@ Exit `0` means nothing exploitable was proven in what was analyzed β€” not that ## Complementary tooling -This is exploit-validated review, not an exhaustive inventory. Keep a dependency scanner (SCA) and secret scanning in place for complete coverage of known-CVE dependencies and committed credentials; use this for the logic, authorization, and injection bugs those tools structurally can't find. +This is exploit-validated review, not an exhaustive inventory. Keep a dependency scanner (SCA) and secret scanning in place for complete coverage of known-CVE dependencies and committed credentials; use this for the logic, authorization, and injection bugs those tools structurally cannot find. ## Fix and verify diff --git a/skills/fix-security-vulnerabilities-with-strix/SKILL.md b/skills/fix-security-vulnerabilities-with-strix/SKILL.md index 5e3ad0c7..770a22bd 100644 --- a/skills/fix-security-vulnerabilities-with-strix/SKILL.md +++ b/skills/fix-security-vulnerabilities-with-strix/SKILL.md @@ -27,7 +27,7 @@ Order work by severity: critical β†’ high β†’ medium β†’ low. Every Strix findin For each finding: 1. Reproduce it with the PoC from the finding file when feasible. -2. Fix the root cause, not the specific payload (e.g. parameterize all queries, don't blocklist one string; enforce authorization in the handler, don't hide the endpoint). +2. Fix the root cause, not the specific payload (parameterize every query instead of blocking one string, and enforce authorization in the handler instead of hiding the endpoint). 3. Prefer the framework's built-in defense (ORM parameterization, template auto-escaping, CSRF middleware, centralized authz) over ad-hoc sanitization. 4. Keep the diff minimal and apply the repo's existing patterns. Finding files often include `fix_before`/`fix_after` snippets β€” use them as a starting point, not verbatim. @@ -70,7 +70,7 @@ new_id=$(curl -sS "$BASE/scans/$scan_id/rerun" "${auth[@]}" -X POST | jq -r .sca Or, if the cloud scan came from a repo/PR, trigger a fresh PR review on the fix branch (`POST /pr-reviews/start`). The platform also retests a single finding directly: `POST /api/v1/vulnerabilities/{vulnerabilityId}/retest`. - Also re-run the PoC manually when it is a simple request/script β€” fastest signal. -- Run the project's own test suite to make sure the fix doesn't break behavior. +- Run the project's own test suite to make sure the fix does not break behavior. ## 4. Report diff --git a/skills/managed-pentesting-with-strix/SKILL.md b/skills/managed-pentesting-with-strix/SKILL.md index f2f01c19..08feeb36 100644 --- a/skills/managed-pentesting-with-strix/SKILL.md +++ b/skills/managed-pentesting-with-strix/SKILL.md @@ -80,7 +80,7 @@ Useful `CreateScanRequest` fields: | `domain_ids` / `repository_ids` / `internal_targets` | targets (at least one) | | `domain_paths` / `repository_branches` | narrow to specific paths / branches | | `credentials` | authenticated scanning, incl. `mfa_method` (`totp`/`email_otp`/…) + `totp_secret` | -| `headers` | extra HTTP headers (e.g. API keys) for the target | +| `headers` | extra HTTP headers (API keys, for example) for the target | | `focus` / `concerns` / `context` | steer the agents | | `upload_ids` | attach uploaded source/docs archives for white-box context | | `notify_on_completion` / `notification_emails` | email when done | @@ -89,7 +89,7 @@ Response is `{ scan_id, title, status }` with `status` = `pending`. ## 3. Poll to completion -`GET /scans/{scanId}` (`scans:read`). Status flow: `pending β†’ running β†’ completed` (or `failed` / `cancelled`). Poll on an interval β€” scans take minutes to hours; don't block. +`GET /scans/{scanId}` (`scans:read`). Status flow: `pending β†’ running β†’ completed` (or `failed` / `cancelled`). Poll on an interval β€” scans take minutes to hours. Do not block. ```bash while :; do @@ -143,10 +143,10 @@ List/inspect via `GET /pr-reviews` and `GET /pr-reviews/{id}`. Repo-level PR-rev ## 7. Continuous testing (schedules & webhooks) - **Schedules** (`schedules:write`, Pro plan): create recurring scans and trigger them on demand β€” the managed equivalent of a cron-driven CLI loop. -- **Webhooks** (`webhooks:write`): subscribe to pentest/vulnerability lifecycle events (e.g. `scan.completed`, `vulnerability.created`) to push results into Slack, ticketing, or your own pipeline instead of polling. +- **Webhooks** (`webhooks:write`): subscribe to pentest/vulnerability lifecycle events such as `scan.completed` and `vulnerability.created` to push results into Slack, ticketing, or your own pipeline instead of polling. See the schedules and webhooks sections at [docs.app.strix.ai](https://docs.app.strix.ai) for payloads. ## Safety -Only scan assets the user's organization owns or is authorized to test. External domain scans require verification (DNS/file/meta-tag) enforced by the platform β€” don't try to bypass it. +Only scan assets the user's organization owns or is authorized to test. External domain scans require verification (DNS/file/meta-tag) enforced by the platform β€” do not try to bypass it. diff --git a/skills/owasp-top-10-testing/SKILL.md b/skills/owasp-top-10-testing/SKILL.md index ae57864d..c8c121be 100644 --- a/skills/owasp-top-10-testing/SKILL.md +++ b/skills/owasp-top-10-testing/SKILL.md @@ -15,7 +15,7 @@ The OWASP Top 10 is a taxonomy of risk categories, not a test suite β€” "OWASP T Install, LLM setup, and the managed-cloud alternative: **penetration-testing-with-strix**. -## What is and isn't testable by an agent +## What is and is not testable by an agent Be straight with the user about this β€” claiming a clean sweep of all ten is misleading. @@ -55,7 +55,7 @@ Out of scope: /billing/*, outbound email." ## Report honestly -From `strix_runs//`, group `vulnerabilities/*.md` by category and state, per category: what was attempted, what was proven, and what couldn't be assessed (A09 always; A03/A04/A06/A08/A10 partially). Label the report with the edition used. Verify each PoC yourself before it goes in front of the user. +From `strix_runs//`, group `vulnerabilities/*.md` by category and state, per category: what was attempted, what was proven, and what could not be assessed (A09 always; A03/A04/A06/A08/A10 partially). Label the report with the edition used. Verify each PoC yourself before it goes in front of the user. A `0` exit code means nothing exploitable was proven **in what was analyzed** β€” check `run.json` status and cost against `--max-budget`; a budget-capped run is not a completed assessment. diff --git a/skills/penetration-testing-with-strix/SKILL.md b/skills/penetration-testing-with-strix/SKILL.md index 1745753e..c653d65d 100644 --- a/skills/penetration-testing-with-strix/SKILL.md +++ b/skills/penetration-testing-with-strix/SKILL.md @@ -14,14 +14,14 @@ Strix runs autonomous AI pentesting agents that dynamically exploit a target and - **Open-source CLI** (self-hosted) β€” runs on your machine in a Docker sandbox with your own LLM key. Free, fully local, BYO-LLM, air-gap capable. Docs: [docs.strix.ai](https://docs.strix.ai). - **Cloud API** (managed) β€” runs on Strix's infrastructure via `https://app.strix.ai/api/v1`. No Docker, no LLM key, no local compute; adds team dashboards, scheduling, PR reviews, downloadable PDF/DOCX reports (Enterprise plan), and internal-network connectors. Docs: [docs.app.strix.ai](https://docs.app.strix.ai). Full workflow in the **managed-pentesting-with-strix** skill. -## Which one? (decide, don't default) +## Which one? (decide, do not default) Choose honestly based on the situation β€” neither is "better": | Situation | Prefer | |---|---| | No Docker available, or a sandboxed/hosted agent/CI environment | **Cloud** | -| User has no LLM key / doesn't want to pay per-token or manage models | **Cloud** | +| User has no LLM key / does not want to pay per-token or manage models | **Cloud** | | Team visibility, shareable dashboard, scheduled/continuous scans, PR reviews, downloadable PDF/DOCX report (Enterprise) | **Cloud** | | Scanning internal/private infrastructure not reachable from your machine | **Cloud** (network connector) | | Source must never leave local infra (privacy/air-gap), or fully offline | **OSS CLI** | @@ -30,7 +30,7 @@ Choose honestly based on the situation β€” neither is "better": | CI: runner already has Docker and you want a self-contained gate | **OSS CLI** | | CI: no Docker, or you want results tracked centrally | **Cloud** | -**Mix them:** e.g. use the OSS CLI for the fast local dev-loop while writing/fixing code, and the Cloud for the authoritative, team-visible scan + report + tracking; or gate PRs with the OSS CLI in CI while the Cloud runs scheduled deep scans and PR reviews across the org. Both emit the same SARIF 2.1.0, so findings line up across environments. +**Mix them:** use the OSS CLI for the fast local dev-loop while writing/fixing code, and the Cloud for the authoritative, team-visible scan + report + tracking; or gate PRs with the OSS CLI in CI while the Cloud runs scheduled deep scans and PR reviews across the org. Both emit the same SARIF 2.1.0, so findings line up across environments. If unsure and the user has (or will create) an app.strix.ai account, prefer **Cloud** β€” it avoids all local-infra friction. If they want zero signup / full local control, use the **OSS CLI**. @@ -70,21 +70,29 @@ strix -n -t https://github.com/org/app -t https://staging.example.com strix -n -t https://app.example.com \ --instruction "Use credentials user@example.com:pass123. Focus on IDOR and auth bypass." -# Large monorepo: bind-mount instead of copying -strix -n --mount ./huge-monorepo +# API spec as a first-class target (OpenAPI/Swagger or a Postman collection export) +strix -n -t ./openapi.yaml -t https://api.staging.example.com + +# Many targets from a file, one per line +strix -n --target-list ./targets.txt --max-budget 30 ``` +A local path passed with `-t` is mounted into the sandbox **writable** β€” the agents can read and modify it, so point at a clean checkout, not uncommitted work you care about. + Key flags: | Flag | Meaning | |---|---| -| `-t, --target` | URL, repo URL, local path, domain, or IP. Repeatable. | +| `-t, --target` | URL, repo URL, local path, domain, IP, OpenAPI/Postman spec, or `postman://`. Repeatable. | +| `--target-list PATH` | File of targets, one per line (`#` comments allowed). Repeatable, combines with `-t`. | | `-n, --non-interactive` | Headless, exits on completion. Required for agents. | | `-m, --scan-mode` | `quick` (minutes) / `standard` (~30 min) / `deep` (hours, default). | | `--instruction` / `--instruction-file` | Credentials, focus areas, scope rules. | | `--max-budget USD` | Hard LLM spend cap; scan wraps up cleanly at the limit. | | `--max-turns N` | Per-agent turn cap (default 500). | -| `--resume RUN_NAME` | Resume a prior run from `strix_runs/`. | +| `--resume RUN_NAME` | Resume a prior run from `strix_runs/`, with its agent history and targets. Cannot be combined with `-t`. | +| `--scope-mode` | For code targets: `auto` (diff-scope in CI/headless), `diff` (force changed files only), `full` (whole tree). | +| `--diff-base REF` | Branch or commit that `diff` scope compares against. Defaults to the repo's default branch. | Scans take minutes (`quick`) to hours (`deep`). Run them in the background and poll for completion rather than blocking. @@ -130,7 +138,7 @@ curl -sS "$BASE/scans/$scan_id" -H "Authorization: Bearer $STRIX_API_TOKEN" | jq curl -sS "$BASE/scans/$scan_id/sarif" -H "Authorization: Bearer $STRIX_API_TOKEN" -o findings.sarif ``` -Ask the user to create the token (and register the target as a domain/repository asset) if they haven't. If Docker/local prerequisites aren't already satisfied, use this path instead of trying to install infra. +Ask the user to create the token (and register the target as a domain/repository asset) if they have not. If Docker/local prerequisites are not already satisfied, use this path instead of trying to install infra. --- diff --git a/skills/web-app-penetration-testing/SKILL.md b/skills/web-app-penetration-testing/SKILL.md index b792166d..9694a3de 100644 --- a/skills/web-app-penetration-testing/SKILL.md +++ b/skills/web-app-penetration-testing/SKILL.md @@ -11,13 +11,13 @@ metadata: Black-box (and optionally source-assisted) penetration testing of a running web app with Strix's autonomous agents. Every reported finding is validated with a working exploit, so there are no signature-based false positives to triage. -Install, LLM setup, all CLI flags, and the managed-cloud alternative are covered in the **penetration-testing-with-strix** skill β€” read it if the target isn't a running web app, or if `strix --version` fails. This skill is the web-app-specific workflow. +Install, LLM setup, all CLI flags, and the managed-cloud alternative are covered in the **penetration-testing-with-strix** skill β€” read it if the target is not a running web app, or if `strix --version` fails. This skill is the web-app-specific workflow. ## 1. Confirm authorization and scope Before running anything, establish: -- **The target is the user's** (or they're explicitly authorized to test it). Never pentest a third-party site on a hunch. +- **The target is the user's** (or they are explicitly authorized to test it). Never pentest a third-party site on a hunch. - **Which environment.** Prefer staging over production; agents send real exploit payloads and will create/modify data. - **Out-of-scope paths** β€” payment flows, mass-email endpoints, admin destructive actions, third-party SSO providers. - **Credentials.** Most real vulnerabilities live behind login. Without a test account, the agents only ever see the marketing surface. From d6a3ca7e58ac2bec3bf0d4a4950683fed18aeea4 Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Thu, 20 Aug 2026 20:33:32 +0000 Subject: [PATCH 09/13] docs(skills): document --workspace-file for supporting files --- skills/api-security-testing/SKILL.md | 1 + skills/penetration-testing-with-strix/SKILL.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md index 628c0c8c..94d3cf84 100644 --- a/skills/api-security-testing/SKILL.md +++ b/skills/api-security-testing/SKILL.md @@ -47,6 +47,7 @@ Out of scope: POST /billing/*, POST /notifications/broadcast." - **GraphQL:** point at the GraphQL endpoint and say whether introspection is enabled; call out that you want batching/aliasing abuse, depth/complexity limits, and per-field authorization tested. - **Internal/private APIs** unreachable from your machine: use the managed platform's network connector β€” see **managed-pentesting-with-strix**. - Use `--instruction-file` when the credential/context block gets long, and keep tokens out of shell history and out of committed files. +- **Supporting files** the agents should read but not test, such as an endpoint wordlist or handwritten notes about the tenancy model: pass `--workspace-file ./notes.md`. The file lands read-only in `/workspace`. Add `:DEST` to choose the path, for example `--workspace-file ./wordlist.txt:lists/wordlist.txt`. ## 3. Verify findings diff --git a/skills/penetration-testing-with-strix/SKILL.md b/skills/penetration-testing-with-strix/SKILL.md index c653d65d..1364ad8d 100644 --- a/skills/penetration-testing-with-strix/SKILL.md +++ b/skills/penetration-testing-with-strix/SKILL.md @@ -75,6 +75,9 @@ strix -n -t ./openapi.yaml -t https://api.staging.example.com # Many targets from a file, one per line strix -n --target-list ./targets.txt --max-budget 30 + +# Give the agents a file to work with (wordlist, spec, notes) without making it a target +strix -n -t https://staging.example.com --workspace-file ./wordlist.txt --max-budget 20 ``` A local path passed with `-t` is mounted into the sandbox **writable** β€” the agents can read and modify it, so point at a clean checkout, not uncommitted work you care about. @@ -88,6 +91,7 @@ Key flags: | `-n, --non-interactive` | Headless, exits on completion. Required for agents. | | `-m, --scan-mode` | `quick` (minutes) / `standard` (~30 min) / `deep` (hours, default). | | `--instruction` / `--instruction-file` | Credentials, focus areas, scope rules. | +| `--workspace-file PATH[:DEST]` | Place a file from this machine into `/workspace` read-only before the scan, for a wordlist, a spec, or notes. Repeatable. | | `--max-budget USD` | Hard LLM spend cap; scan wraps up cleanly at the limit. | | `--max-turns N` | Per-agent turn cap (default 500). | | `--resume RUN_NAME` | Resume a prior run from `strix_runs/`, with its agent history and targets. Cannot be combined with `-t`. | From 2cc816781438f2993bcbb5c8cf3f693c25380142 Mon Sep 17 00:00:00 2001 From: Alex Schapiro Date: Thu, 20 Aug 2026 20:40:46 +0000 Subject: [PATCH 10/13] docs(skills): correct gRPC guidance, a .proto is not a spec target --- skills/api-security-testing/SKILL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skills/api-security-testing/SKILL.md b/skills/api-security-testing/SKILL.md index 94d3cf84..e47d427d 100644 --- a/skills/api-security-testing/SKILL.md +++ b/skills/api-security-testing/SKILL.md @@ -19,7 +19,7 @@ APIs are near-impossible to test blind, so collect first: | Input | Why it matters | |---|---| -| **Schema** β€” OpenAPI/Swagger file, Postman collection, GraphQL endpoint (introspection), or `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage, and Strix takes a spec directly as a target. | +| **Schema** β€” OpenAPI/Swagger file, Postman collection, GraphQL endpoint (introspection), or a gRPC `.proto` | Turns guesswork into full endpoint enumeration. Biggest single win in coverage. An OpenAPI/Swagger or Postman spec (`.json`/`.yaml`/`.yml`) is a target Strix takes directly; a `.proto` is not, so pass it with `--workspace-file`. | | **Two sets of credentials/tokens**, ideally in different tenants | BOLA/IDOR β€” API1:2023, still the #1 API risk β€” can only be *proven* by accessing tenant A's objects with tenant B's token. | | **A low-privilege and a high-privilege token** | Required to prove broken function-level authorization (API5:2023 β€” a `user` calling admin-only routes). | | **Example object IDs** | Lets agents test ID tampering immediately instead of hunting for valid identifiers. | @@ -44,6 +44,7 @@ Out of scope: POST /billing/*, POST /notifications/broadcast." - **Postman instead of OpenAPI:** a collection export works as a target (`-t ./collection.postman_collection.json`), or pull one live with `-t postman://` (optionally `"postman://?env="`), which needs `POSTMAN_API_KEY` in the environment. - **Many services at once:** put one target per line in a file and pass `--target-list ./targets.txt`, repeatable and combinable with `-t`. - **Add the backend source for depth:** `-t ./services/api -t https://api.staging.example.com`. With code access the agents can reason about authorization checks and object ownership rather than inferring them from responses. +- **gRPC:** target the endpoint and pass the definition as a workspace file, `-t https://grpc.staging.example.com --workspace-file ./service.proto`. Only `.json`, `.yaml`, and `.yml` specs are recognized as targets, so `-t ./service.proto` fails with "Path exists but is not a directory". - **GraphQL:** point at the GraphQL endpoint and say whether introspection is enabled; call out that you want batching/aliasing abuse, depth/complexity limits, and per-field authorization tested. - **Internal/private APIs** unreachable from your machine: use the managed platform's network connector β€” see **managed-pentesting-with-strix**. - Use `--instruction-file` when the credential/context block gets long, and keep tokens out of shell history and out of committed files. From 1ce43d1b94240a3fd4b9f45cd3c0376b4feb36c9 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 20:24:08 -0700 Subject: [PATCH 11/13] perf: take heavy imports off the startup path and pre-warm them in the background (#1141) Co-authored-by: Ahmed Allam --- pyproject.toml | 11 +++++++ strix/core/execution.py | 20 ++++++++++-- strix/interface/main.py | 4 +++ strix/interface/utils.py | 7 ++-- strix/llm/compaction.py | 19 +++++++++-- strix/llm/context_budget.py | 6 ++-- strix/llm/warmup.py | 55 ++++++++++++++++++++++++++++++++ strix/runtime/caido_bootstrap.py | 10 ++++-- strix/tools/proxy/caido_api.py | 26 +++++++++------ tests/test_context_budget.py | 6 ++-- 10 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 strix/llm/warmup.py diff --git a/pyproject.toml b/pyproject.toml index 77be738f..195a9646 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -270,6 +270,10 @@ ignore = [ "strix/tools/thinking/tool.py" = ["TC002"] "strix/tools/web_search/tool.py" = ["TC002"] "strix/tools/proxy/tools.py" = ["TC002", "PLR0911"] +# The generated Caido GraphQL schema is slow to import, so the SDK is imported +# on first proxy call instead of at module scope (keeps it off the launch path). +"strix/tools/proxy/caido_api.py" = ["PLC0415"] +"strix/runtime/caido_bootstrap.py" = ["PLC0415"] "strix/tools/agents_graph/tools.py" = ["TC002"] "strix/agents/factory.py" = ["TC002"] # Entry point: ``Path`` is used at runtime by the typing of the @@ -280,6 +284,13 @@ ignore = [ # a runtime ``Callable`` annotation on ``vulnerability_found_callback``. "strix/report/state.py" = ["TC003", "PLR0912", "PLR0915", "E501", "PERF401", "PLC0415"] "strix/report/usage.py" = ["PLC0415"] +# LiteLLM and the Docker SDK are imported on first use, not at module scope: +# both cost seconds to import and neither is needed until a model call is made +# (or, for Docker, unless the Docker runtime backend is in use). +"strix/core/execution.py" = ["PLC0415"] +"strix/report/pricing.py" = ["PLC0415"] +"strix/llm/compaction.py" = ["PLC0415"] +"strix/llm/context_budget.py" = ["PLC0415"] # Lazy import of strix.config.models avoids a circular dependency between the # report pipeline and the config layer. "strix/report/dedupe.py" = ["PLC0415"] diff --git a/strix/core/execution.py b/strix/core/execution.py index bd99e7c3..9f2674d2 100644 --- a/strix/core/execution.py +++ b/strix/core/execution.py @@ -7,13 +7,12 @@ import contextlib import logging import uuid from collections.abc import Callable +from functools import cache from typing import TYPE_CHECKING, Any, cast -import litellm from agents import RunConfig, Runner from agents.exceptions import AgentsException, MaxTurnsExceeded, UserError from agents.sandbox.errors import ExecTransportError -from docker import errors as docker_errors # type: ignore[import-untyped, unused-ignore] from openai import ( APIConnectionError, APIError, @@ -56,6 +55,19 @@ _INPUT_REJECTION_CODES = frozenset({400, 404, 422}) _MAX_COMPACTIONS_PER_CYCLE = 2 +@cache +def _teardown_sandbox_errors() -> tuple[type[BaseException], ...]: + """Sandbox-gone errors, tolerated during shutdown. + + The Docker SDK is imported here rather than at module scope: it is only + reachable with the Docker runtime backend, and importing it eagerly puts it + on every launch's critical path. + """ + from docker import errors as docker_errors # type: ignore[import-untyped, unused-ignore] + + return (ExecTransportError, docker_errors.NotFound) + + class ProviderRefusalError(AgentsException): """Raised when a provider returns a structured refusal instead of an exception.""" @@ -126,6 +138,8 @@ def _is_transient_model_error(exc: BaseException) -> bool: return True code = _model_error_status_code(exc) if code is not None: + import litellm + return bool(litellm._should_retry(code)) return isinstance(exc, APIError) @@ -692,7 +706,7 @@ async def _run_cycle( # noqa: PLR0912, PLR0915 "Ignoring LiteLLM end-of-stream shutdown race for %s", agent_id, ) - except (ExecTransportError, docker_errors.NotFound): + except _teardown_sandbox_errors(): if not coordinator.is_shutting_down: raise logger.warning( diff --git a/strix/interface/main.py b/strix/interface/main.py index 06966f4c..45e114b5 100644 --- a/strix/interface/main.py +++ b/strix/interface/main.py @@ -431,6 +431,10 @@ def main() -> None: sys.exit(run_auth(sys.argv[2:])) + from strix.llm.warmup import start_import_warmup + + start_import_warmup() + args = parse_arguments() start_background_check() diff --git a/strix/interface/utils.py b/strix/interface/utils.py index 6789abe0..faab1772 100644 --- a/strix/interface/utils.py +++ b/strix/interface/utils.py @@ -13,9 +13,7 @@ from pathlib import Path from typing import Any from urllib.parse import parse_qs, urlparse -import docker import requests -from docker.errors import DockerException, ImageNotFound from rich.console import Console from rich.panel import Panel from rich.text import Text @@ -1599,6 +1597,9 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None) def check_docker_connection() -> Any: + import docker + from docker.errors import DockerException + try: return docker.from_env() except DockerException: @@ -1624,6 +1625,8 @@ def check_docker_connection() -> Any: def image_exists(client: Any, image_name: str) -> bool: + from docker.errors import ImageNotFound + try: client.images.get(image_name) except ImageNotFound: diff --git a/strix/llm/compaction.py b/strix/llm/compaction.py index e40caf6a..ecdb9a83 100644 --- a/strix/llm/compaction.py +++ b/strix/llm/compaction.py @@ -10,11 +10,11 @@ pairing so the trimmed history is still valid provider input. from __future__ import annotations import logging +from functools import cache from typing import TYPE_CHECKING, Any from agents.model_settings import ModelSettings from agents.models.interface import ModelTracing -from litellm.exceptions import BadRequestError, ContextWindowExceededError from openai.types.responses import ResponseOutputMessage, ResponseOutputText from strix.config import load_settings @@ -63,6 +63,18 @@ _OVERFLOW_MARKERS = ( ) +@cache +def _overflow_error_types() -> tuple[type[BaseException], type[BaseException]]: + """``(ContextWindowExceededError, BadRequestError)``, imported on first use. + + LiteLLM costs seconds to import, and nothing needs it until a model call is + actually made, so it stays off the launch path. + """ + from litellm.exceptions import BadRequestError, ContextWindowExceededError + + return ContextWindowExceededError, BadRequestError + + def is_context_overflow(exc: BaseException) -> bool: """Whether ``exc`` is a model context-window-overflow error. @@ -70,9 +82,10 @@ def is_context_overflow(exc: BaseException) -> bool: OpenRouter branch raises a plain BadRequestError, so for that we fall back to matching the provider message. """ - if isinstance(exc, ContextWindowExceededError): + context_window_exceeded, bad_request = _overflow_error_types() + if isinstance(exc, context_window_exceeded): return True - if isinstance(exc, BadRequestError): + if isinstance(exc, bad_request): msg = str(exc).lower() if any(x in msg for x in _OVERFLOW_EXCLUSIONS): return False diff --git a/strix/llm/context_budget.py b/strix/llm/context_budget.py index b7589a9e..baa02c4b 100644 --- a/strix/llm/context_budget.py +++ b/strix/llm/context_budget.py @@ -8,8 +8,6 @@ import logging from functools import lru_cache from typing import Any -import litellm - from strix.config import load_settings @@ -38,6 +36,8 @@ def _lookup_key(model: str) -> str: def _safe_get_model_info(model: str) -> dict[str, Any] | None: try: + import litellm + return dict(litellm.get_model_info(model)) except Exception: # noqa: BLE001 - unmapped models raise; caller falls back. return None @@ -82,6 +82,8 @@ def count_tokens(model: str, text: str) -> int: if not text: return 0 try: + import litellm + return int(litellm.token_counter(model=_lookup_key(model), text=text)) except Exception: # noqa: BLE001 - tokenizer may be unavailable for some models. return len(text.encode("utf-8")) diff --git a/strix/llm/warmup.py b/strix/llm/warmup.py new file mode 100644 index 00000000..98da959d --- /dev/null +++ b/strix/llm/warmup.py @@ -0,0 +1,55 @@ +"""Background pre-import of the heavy scan dependencies. + +The scan engine's import graph (the agents SDK, OpenAI client, LiteLLM, the +Caido SDK, the Docker SDK) costs seconds to import cold, but none of it is +needed until a scan actually starts. Importing it on a daemon thread at CLI +entry overlaps that cost with the I/O-bound startup work that always precedes +a scan (argument parsing, Docker checks, image pull, TUI setup), so by the +time the scan begins the modules are already in ``sys.modules``. Any thread +that needs one of them before the warm-up finishes just blocks on the normal +import lock, so behaviour is unchanged either way. +""" + +from __future__ import annotations + +import importlib +import logging +import threading + + +logger = logging.getLogger(__name__) + +WARMUP_MODULES = ( + "strix.core.runner", + "litellm", + "caido_sdk_client", + "docker", +) + +_lock = threading.Lock() +_thread: threading.Thread | None = None + + +def _warm(modules: tuple[str, ...]) -> None: + for name in modules: + try: + importlib.import_module(name) + except Exception: # noqa: BLE001 - a failed warm-up must never fail the run. + logger.debug("Import warm-up for %r failed", name, exc_info=True) + + +def start_import_warmup(modules: tuple[str, ...] = WARMUP_MODULES) -> threading.Thread: + """Start importing the heavy scan dependencies in the background, once. + + ``modules`` lets embedders that never touch some backends (e.g. a cloud + runtime that has no local Docker) warm a narrower set. + """ + global _thread # noqa: PLW0603 + with _lock: + if _thread is not None: + return _thread + _thread = threading.Thread( + target=_warm, args=(modules,), name="strix-import-warmup", daemon=True + ) + _thread.start() + return _thread diff --git a/strix/runtime/caido_bootstrap.py b/strix/runtime/caido_bootstrap.py index 0b9ad5b1..8398350b 100644 --- a/strix/runtime/caido_bootstrap.py +++ b/strix/runtime/caido_bootstrap.py @@ -15,12 +15,10 @@ import json import logging from typing import TYPE_CHECKING -from caido_sdk_client import Client, TokenAuthOptions -from caido_sdk_client.types import CreateProjectOptions - if TYPE_CHECKING: from agents.sandbox.session import BaseSandboxSession + from caido_sdk_client import Client logger = logging.getLogger(__name__) @@ -87,6 +85,12 @@ async def bootstrap_caido( container_url: str, ) -> Client: """Connect to the in-container Caido sidecar and select a fresh project.""" + # The Caido SDK (and its generated GraphQL schema) is slow to import and is + # only needed once a sandbox is actually being bootstrapped, so it is + # imported here rather than at module scope. + from caido_sdk_client import Client, TokenAuthOptions + from caido_sdk_client.types import CreateProjectOptions + logger.info("Bootstrapping Caido client (host=%s, container=%s)", host_url, container_url) access_token = await _login_as_guest(session, container_url=container_url) diff --git a/strix/tools/proxy/caido_api.py b/strix/tools/proxy/caido_api.py index 6cfee56c..af81b500 100644 --- a/strix/tools/proxy/caido_api.py +++ b/strix/tools/proxy/caido_api.py @@ -10,20 +10,16 @@ import urllib.request from typing import TYPE_CHECKING, Any, Literal from urllib.parse import parse_qs, urlencode, urlparse, urlunparse -from caido_sdk_client import Client, TokenAuthOptions -from caido_sdk_client.types import ( - ConnectionInfoInput, - CreateScopeOptions, - ReplaySendOptions, - RequestGetOptions, - UpdateScopeOptions, -) - +# The generated Caido GraphQL schema module is slow to import and is only needed +# once a proxy tool actually runs, so the SDK is imported on first use rather +# than at module scope, which would put it on every launch's critical path. if TYPE_CHECKING: from collections.abc import Awaitable, Callable + from caido_sdk_client import Client from caido_sdk_client import Client as CaidoClient + from caido_sdk_client.types import ConnectionInfoInput RequestPart = Literal["request", "response"] @@ -85,6 +81,8 @@ def _login_as_guest() -> str: async def _new_client() -> Client: + from caido_sdk_client import Client, TokenAuthOptions + token = await asyncio.to_thread(_login_as_guest) client = Client(caido_url(), auth=TokenAuthOptions(token=token)) await client.connect() @@ -163,6 +161,8 @@ async def get_request_with_client( # Passing False for either causes pydantic validation to fail with # "Field required" on the missing raw field. Always request both β€” # the caller picks which one to surface via ``part``. + from caido_sdk_client.types import RequestGetOptions + opts = RequestGetOptions(request_raw=True, response_raw=True) return await client.request.get(request_id, opts) @@ -206,6 +206,8 @@ def build_raw_request( if body: final_headers["Content-Length"] = str(len(body.encode("utf-8"))) + from caido_sdk_client.types import ConnectionInfoInput + lines = [f"{method.upper()} {path} HTTP/1.1"] lines.extend(f"{k}: {v}" for k, v in final_headers.items()) raw = ("\r\n".join(lines) + "\r\n\r\n" + body).encode("utf-8") @@ -334,6 +336,8 @@ async def replay_send_raw( raw: bytes, connection: ConnectionInfoInput, ) -> dict[str, Any]: + from caido_sdk_client.types import ReplaySendOptions + started = time.time() # Create an empty replay session, then dispatch via ``send()``. # Passing ``CreateReplaySessionFromRaw`` here would also seed a stored @@ -391,6 +395,8 @@ async def scope_create( allowlist: list[str] | None = None, denylist: list[str] | None = None, ) -> Any: + from caido_sdk_client.types import CreateScopeOptions + return await client.scope.create( CreateScopeOptions( name=name, @@ -408,6 +414,8 @@ async def scope_update( allowlist: list[str] | None = None, denylist: list[str] | None = None, ) -> Any: + from caido_sdk_client.types import UpdateScopeOptions + return await client.scope.update( scope_id, UpdateScopeOptions( diff --git a/tests/test_context_budget.py b/tests/test_context_budget.py index a9a48e0c..8c06fa49 100644 --- a/tests/test_context_budget.py +++ b/tests/test_context_budget.py @@ -31,7 +31,7 @@ def test_context_window_chatgpt_prefix_skips_provider_auth( calls.append(model) return {"max_input_tokens": 1_050_000, "max_output_tokens": 128_000} - monkeypatch.setattr("strix.llm.context_budget.litellm.get_model_info", _model_info) + monkeypatch.setattr("litellm.get_model_info", _model_info) try: assert context_budget.context_window("chatgpt/gpt-5.6-luna") == 1_050_000 assert calls == ["gpt-5.6-luna"] @@ -45,7 +45,7 @@ def test_context_window_unmapped_uses_fallback(monkeypatch: pytest.MonkeyPatch) def _raise(_model: str) -> dict[str, int]: raise ValueError("This model isn't mapped yet.") - monkeypatch.setattr("strix.llm.context_budget.litellm.get_model_info", _raise) + monkeypatch.setattr("litellm.get_model_info", _raise) expected = load_settings().context.fallback_context_tokens assert context_budget.context_window("totally-made-up-model") == expected context_budget._model_info.cache_clear() @@ -55,7 +55,7 @@ def test_count_tokens_fallback_on_error(monkeypatch: pytest.MonkeyPatch) -> None def _raise(**_kwargs: object) -> int: raise RuntimeError("no tokenizer") - monkeypatch.setattr("strix.llm.context_budget.litellm.token_counter", _raise) + monkeypatch.setattr("litellm.token_counter", _raise) # Falls back to UTF-8 byte length (upper bound on tokens). assert context_budget.count_tokens("weird-model", "x" * 400) == 400 assert context_budget.count_tokens("weird-model", "πŸ˜€" * 10) == 40 From 1c499c5b2d788c553f0d276b389b2b424e483304 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2026 12:09:59 -0700 Subject: [PATCH 12/13] perf: bootstrap Caido concurrently with the scan start (#1143) Co-authored-by: Ahmed Allam --- strix/runtime/caido_bootstrap.py | 8 ++- strix/runtime/caido_handle.py | 60 ++++++++++++++++++ strix/runtime/session_manager.py | 19 ++++-- strix/tools/proxy/tools.py | 26 +++++--- tests/test_caido_bootstrap.py | 81 ++++++++++++++++++++++++ tests/test_caido_handle.py | 103 +++++++++++++++++++++++++++++++ tests/test_proxy_client.py | 30 +++++++-- 7 files changed, 306 insertions(+), 21 deletions(-) create mode 100644 strix/runtime/caido_handle.py create mode 100644 tests/test_caido_bootstrap.py create mode 100644 tests/test_caido_handle.py diff --git a/strix/runtime/caido_bootstrap.py b/strix/runtime/caido_bootstrap.py index 8398350b..a9c7c82a 100644 --- a/strix/runtime/caido_bootstrap.py +++ b/strix/runtime/caido_bootstrap.py @@ -96,15 +96,17 @@ async def bootstrap_caido( access_token = await _login_as_guest(session, container_url=container_url) client = Client(host_url, auth=TokenAuthOptions(token=access_token)) - await client.connect() - try: + # connect() is inside the guard as well: a cancellation there (scan + # teardown while the bootstrap is still in flight) would otherwise + # leave the half-connected transport behind. + await client.connect() project = await client.project.create( CreateProjectOptions(name="sandbox", temporary=True), ) await client.project.select(project.id) except BaseException: - # The connected client never reaches the session bundle if project + # The client never reaches the session bundle if connect or project # setup fails, so close it here to avoid leaking the transport. with contextlib.suppress(Exception): await client.aclose() diff --git a/strix/runtime/caido_handle.py b/strix/runtime/caido_handle.py new file mode 100644 index 00000000..5b1d1c74 --- /dev/null +++ b/strix/runtime/caido_handle.py @@ -0,0 +1,60 @@ +"""Handle for a Caido bootstrap running concurrently with the scan start. + +The Caido sidecar login + project setup costs a couple of seconds of +guest-side polling, and nothing needs the client until the first proxy +tool call (or the first traffic poll). :class:`CaidoBootstrapHandle` +wraps the in-flight bootstrap task so session bring-up can return as +soon as the container is up; consumers resolve the client at first use. +""" + +from __future__ import annotations + +import asyncio +import contextlib +import logging +from typing import TYPE_CHECKING + + +if TYPE_CHECKING: + from caido_sdk_client import Client + + +logger = logging.getLogger(__name__) + + +class CaidoBootstrapHandle: + """Resolves to the connected Caido client once the bootstrap finishes. + + A failed bootstrap is surfaced (once) to every ``get()`` caller as the + original exception; proxy tools degrade to their "client unavailable" + result instead of the failure killing the scan at bring-up. + """ + + def __init__(self, task: asyncio.Task[Client]) -> None: + self._task = task + + async def get(self) -> Client: + """Wait for the bootstrap and return the client. + + Shielded so one caller's cancellation (e.g. a tool timeout) does not + cancel the shared bootstrap for everyone else. + """ + return await asyncio.shield(self._task) + + def peek(self) -> Client | None: + """Return the client if the bootstrap already finished cleanly.""" + if self._task.done() and not self._task.cancelled() and self._task.exception() is None: + return self._task.result() + return None + + async def aclose(self) -> None: + """Cancel an in-flight bootstrap or close the finished client.""" + if not self._task.done(): + self._task.cancel() + with contextlib.suppress(asyncio.CancelledError, Exception): + await self._task + return + client = self.peek() + if client is not None: + with contextlib.suppress(Exception): + await client.aclose() diff --git a/strix/runtime/session_manager.py b/strix/runtime/session_manager.py index 62204385..e8b3a279 100644 --- a/strix/runtime/session_manager.py +++ b/strix/runtime/session_manager.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio import logging import os import sys @@ -15,6 +16,7 @@ from strix.config import load_settings from strix.core.paths import run_dir_for, runtime_state_dir from strix.runtime.backends import backend_supports_bind_mounts, get_backend from strix.runtime.caido_bootstrap import bootstrap_caido +from strix.runtime.caido_handle import CaidoBootstrapHandle if TYPE_CHECKING: @@ -333,10 +335,19 @@ async def create_or_reuse( host_caido_url = f"{scheme}://{caido_endpoint.host}:{caido_endpoint.port}" logger.debug("Caido host endpoint resolved: %s", host_caido_url) - caido_client = await bootstrap_caido( - session, - host_url=host_caido_url, - container_url=container_caido_url, + # The Caido login + project setup polls the guest for a couple of seconds + # and nothing needs the client before the first proxy tool call, so it + # runs concurrently with the rest of scan start; consumers resolve the + # handle at first use (see CaidoBootstrapHandle). + caido_client = CaidoBootstrapHandle( + asyncio.create_task( + bootstrap_caido( + session, + host_url=host_caido_url, + container_url=container_caido_url, + ), + name=f"caido-bootstrap-{scan_id}", + ) ) bundle = { diff --git a/strix/tools/proxy/tools.py b/strix/tools/proxy/tools.py index 091c489f..fabcc7ff 100644 --- a/strix/tools/proxy/tools.py +++ b/strix/tools/proxy/tools.py @@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Any, Literal from agents import RunContextWrapper, function_tool +from strix.runtime.caido_handle import CaidoBootstrapHandle from strix.tools.proxy import caido_api @@ -47,9 +48,16 @@ ScopeAction = Literal["get", "list", "create", "update", "delete"] _CAIDO_CALL_LOCK = asyncio.Lock() -def _ctx_client(ctx: RunContextWrapper) -> Client | None: - inner = ctx.context if isinstance(ctx.context, dict) else {} - return inner.get("caido_client") +async def _ctx_client(ctx: RunContextWrapper) -> Client | None: + inner: dict[str, Any] = ctx.context if isinstance(ctx.context, dict) else {} + client: Client | CaidoBootstrapHandle | None = inner.get("caido_client") + if isinstance(client, CaidoBootstrapHandle): + try: + return await client.get() + except Exception: # noqa: BLE001 + logger.warning("Caido bootstrap failed; proxy tools unavailable", exc_info=True) + return None + return client async def _call[T](client: Client, fn: Callable[[Client], Awaitable[T]]) -> T: @@ -155,7 +163,7 @@ async def list_requests( sort_order: ``asc`` or ``desc``. scope_id: Restrict to a Caido scope (managed via ``scope_rules``). """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() @@ -261,7 +269,7 @@ async def view_request( page: 1-indexed page number (only when no ``search_pattern``). page_size: Lines per page. """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() @@ -379,7 +387,7 @@ async def repeat_request( - ``body`` β€” replace the body string entirely. - ``cookies`` β€” dict of cookies to add/update. """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() mods = modifications or {} @@ -461,7 +469,7 @@ async def list_sitemap( (recursive subtree). Only meaningful with ``parent_id``. page: 1-indexed page (30 entries per page). """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() try: @@ -495,7 +503,7 @@ async def view_sitemap_entry( Args: entry_id: ID from ``list_sitemap`` (or any nested entry). """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() try: @@ -554,7 +562,7 @@ async def scope_rules( scope_id: Required for ``get`` / ``update`` / ``delete``. scope_name: Required for ``create`` / ``update``. """ - client = _ctx_client(ctx) + client = await _ctx_client(ctx) if client is None: return _no_client() diff --git a/tests/test_caido_bootstrap.py b/tests/test_caido_bootstrap.py new file mode 100644 index 00000000..98e42a94 --- /dev/null +++ b/tests/test_caido_bootstrap.py @@ -0,0 +1,81 @@ +"""A bootstrap that dies mid-setup must not leave its transport behind. + +The bootstrap now runs concurrently with the scan start, so teardown can +cancel it at any await β€” including inside ``Client.connect()``, where the +client exists but no caller will ever see it to close it. +""" + +from __future__ import annotations + +import asyncio +import sys +import types +from typing import Any + +import pytest + +from strix.runtime.caido_bootstrap import bootstrap_caido + + +class _FakeExecResult: + stderr = b"" + exit_code = 0 + + def __init__(self, stdout: str) -> None: + self.stdout = stdout + + def ok(self) -> bool: + return True + + +class _FakeSession: + async def exec(self, *_args: Any, **_kwargs: Any) -> _FakeExecResult: + return _FakeExecResult('{"data":{"loginAsGuest":{"token":{"accessToken":"t"}}}}') + + +class _FakeClient: + def __init__(self, connect_error: BaseException) -> None: + self.connect_error = connect_error + self.closed = False + + async def connect(self) -> None: + raise self.connect_error + + async def aclose(self) -> None: + self.closed = True + + +async def _bootstrap_expecting( + monkeypatch: pytest.MonkeyPatch, error: BaseException +) -> _FakeClient: + """Run a bootstrap whose ``connect()`` fails with ``error``.""" + client = _FakeClient(error) + # The SDK is imported inside bootstrap_caido (it is slow to import), so the + # fakes are injected as the modules it imports. + sdk = types.ModuleType("caido_sdk_client") + sdk.Client = lambda *_a, **_k: client # type: ignore[attr-defined] + sdk.TokenAuthOptions = lambda token: token # type: ignore[attr-defined] + sdk_types = types.ModuleType("caido_sdk_client.types") + sdk_types.CreateProjectOptions = lambda **_k: None # type: ignore[attr-defined] + monkeypatch.setitem(sys.modules, "caido_sdk_client", sdk) + monkeypatch.setitem(sys.modules, "caido_sdk_client.types", sdk_types) + + with pytest.raises(type(error)): + await bootstrap_caido( + _FakeSession(), # type: ignore[arg-type] + host_url="http://host", + container_url="http://container", + ) + return client + + +async def test_cancellation_during_connect_closes_the_client( + monkeypatch: pytest.MonkeyPatch, +) -> None: + client = await _bootstrap_expecting(monkeypatch, asyncio.CancelledError()) + assert client.closed + + +async def test_failed_connect_closes_the_client(monkeypatch: pytest.MonkeyPatch) -> None: + client = await _bootstrap_expecting(monkeypatch, RuntimeError("no listener")) + assert client.closed diff --git a/tests/test_caido_handle.py b/tests/test_caido_handle.py new file mode 100644 index 00000000..84d8ce8a --- /dev/null +++ b/tests/test_caido_handle.py @@ -0,0 +1,103 @@ +"""Tests for the concurrent Caido bootstrap handle.""" + +from __future__ import annotations + +import asyncio +from typing import Any + +import pytest + +from strix.runtime.caido_handle import CaidoBootstrapHandle + + +class _FakeClient: + def __init__(self) -> None: + self.closed = False + + async def aclose(self) -> None: + self.closed = True + + +def _handle(coro: Any) -> CaidoBootstrapHandle: + return CaidoBootstrapHandle(asyncio.ensure_future(coro)) + + +async def test_get_waits_for_the_bootstrap() -> None: + client = _FakeClient() + started = asyncio.Event() + + async def _bootstrap() -> Any: + started.set() + await asyncio.sleep(0.01) + return client + + handle = _handle(_bootstrap()) + await started.wait() + assert handle.peek() is None + assert await handle.get() is client + assert handle.peek() is client + + +async def test_get_reraises_bootstrap_failure_to_every_caller() -> None: + async def _bootstrap() -> Any: + raise RuntimeError("caido never came up") + + handle = _handle(_bootstrap()) + for _ in range(2): + with pytest.raises(RuntimeError, match="caido never came up"): + await handle.get() + assert handle.peek() is None + + +async def test_caller_cancellation_does_not_cancel_the_shared_bootstrap() -> None: + client = _FakeClient() + + async def _bootstrap() -> Any: + await asyncio.sleep(0.05) + return client + + handle = _handle(_bootstrap()) + + with pytest.raises(TimeoutError): + await asyncio.wait_for(handle.get(), timeout=0.01) + + assert await handle.get() is client + + +async def test_aclose_closes_a_finished_client() -> None: + client = _FakeClient() + + async def _bootstrap() -> Any: + return client + + handle = _handle(_bootstrap()) + await handle.get() + await handle.aclose() + assert client.closed is True + + +async def test_aclose_cancels_an_in_flight_bootstrap() -> None: + cancelled = asyncio.Event() + + async def _bootstrap() -> Any: + try: + await asyncio.sleep(10) + except asyncio.CancelledError: + cancelled.set() + raise + return _FakeClient() + + handle = _handle(_bootstrap()) + await asyncio.sleep(0) + await handle.aclose() + assert cancelled.is_set() + + +async def test_aclose_swallows_a_failed_bootstrap() -> None: + async def _bootstrap() -> Any: + raise RuntimeError("boom") + + handle = _handle(_bootstrap()) + with pytest.raises(RuntimeError, match="boom"): + await handle.get() + await handle.aclose() diff --git a/tests/test_proxy_client.py b/tests/test_proxy_client.py index da54af66..1a3aa849 100644 --- a/tests/test_proxy_client.py +++ b/tests/test_proxy_client.py @@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Any, cast import pytest +from strix.runtime.caido_handle import CaidoBootstrapHandle from strix.tools.proxy import caido_api, tools @@ -198,12 +199,31 @@ class _Ctx: self.context = context -def test_ctx_client_returns_client_when_present() -> None: +async def test_ctx_client_returns_client_when_present() -> None: client = _FakeClient("host") - got = tools._ctx_client(cast("Any", _Ctx({"caido_client": client}))) + got = await tools._ctx_client(cast("Any", _Ctx({"caido_client": client}))) assert got is client -def test_ctx_client_returns_none_without_client() -> None: - assert tools._ctx_client(cast("Any", _Ctx({}))) is None - assert tools._ctx_client(cast("Any", _Ctx(None))) is None +async def test_ctx_client_returns_none_without_client() -> None: + assert await tools._ctx_client(cast("Any", _Ctx({}))) is None + assert await tools._ctx_client(cast("Any", _Ctx(None))) is None + + +async def test_ctx_client_resolves_bootstrap_handle() -> None: + client = _FakeClient("host") + + async def _bootstrap() -> Any: + return client + + handle = CaidoBootstrapHandle(asyncio.ensure_future(_bootstrap())) + got = await tools._ctx_client(cast("Any", _Ctx({"caido_client": handle}))) + assert got is client + + +async def test_ctx_client_degrades_when_bootstrap_failed() -> None: + async def _bootstrap() -> Any: + raise RuntimeError("caido never came up") + + handle = CaidoBootstrapHandle(asyncio.ensure_future(_bootstrap())) + assert await tools._ctx_client(cast("Any", _Ctx({"caido_client": handle}))) is None From 391d81bea7077b647741896dbe97745be47acacd Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 03:34:09 -0700 Subject: [PATCH 13/13] feat(agents): evidence discipline, and coverage as a first-class artifact (#961) Co-authored-by: Ahmed Allam --- strix/agents/factory.py | 16 + strix/agents/prompt.py | 22 +- strix/agents/prompts/system_prompt.jinja | 21 + strix/core/inputs.py | 17 + strix/core/runner.py | 11 + .../interface/tui/internal/render/coverage.go | 194 ++++++ .../tui/internal/render/coverage_test.go | 204 ++++++ .../interface/tui/internal/render/registry.go | 7 +- strix/interface/tui/internal/render/report.go | 30 + .../tui/internal/render/threat_model.go | 138 ++++ .../live/tool-renderers/CoverageRenderer.tsx | 184 +++++ .../tool-renderers/ThreatModelRenderer.tsx | 138 ++++ .../tool-renderers/VulnReportRenderer.tsx | 40 ++ .../components/live/tool-renderers/index.ts | 12 +- .../{index-DBJ-RJqo.js => index-Bi_X6kI3.js} | 298 ++++---- .../viewer/static/assets/index-DKbLYAbP.css | 10 - .../viewer/static/assets/index-g-_6CcwH.css | 10 + strix/interface/viewer/static/index.html | 4 +- strix/report/coverage.py | 443 ++++++++++++ strix/report/sarif.py | 134 ++++ strix/report/state.py | 48 +- strix/report/writer.py | 33 +- strix/skills/__init__.py | 2 +- strix/skills/analysis/counterevidence.md | 185 +++++ strix/skills/analysis/fix_verification.md | 129 ++++ strix/skills/analysis/severity_calibration.md | 130 ++++ .../skills/analysis/source_aware_discovery.md | 211 ++++++ strix/skills/coordination/root_agent.md | 14 + strix/skills/scan_modes/diff.md | 86 +++ strix/tools/agents_graph/tools.py | 31 +- strix/tools/coverage/__init__.py | 1 + strix/tools/coverage/tools.py | 535 ++++++++++++++ strix/tools/finish/tool.py | 67 +- strix/tools/reporting/tool.py | 258 ++++++- strix/tools/threat_model/__init__.py | 1 + strix/tools/threat_model/tools.py | 659 ++++++++++++++++++ tests/test_coverage_tool.py | 284 ++++++++ tests/test_finish_coverage_gate.py | 65 ++ tests/test_inputs.py | 30 + tests/test_report_coverage.py | 264 +++++++ tests/test_report_writer.py | 27 + tests/test_reporting_fields.py | 138 +++- tests/test_sarif.py | 129 ++++ tests/test_skill_dir_extension.py | 41 +- tests/test_state_coverage_artifact.py | 66 ++ tests/test_threat_model_tool.py | 343 +++++++++ 46 files changed, 5506 insertions(+), 204 deletions(-) create mode 100644 strix/interface/tui/internal/render/coverage.go create mode 100644 strix/interface/tui/internal/render/coverage_test.go create mode 100644 strix/interface/tui/internal/render/threat_model.go create mode 100644 strix/interface/viewer/frontend/src/components/live/tool-renderers/CoverageRenderer.tsx create mode 100644 strix/interface/viewer/frontend/src/components/live/tool-renderers/ThreatModelRenderer.tsx rename strix/interface/viewer/static/assets/{index-DBJ-RJqo.js => index-Bi_X6kI3.js} (50%) delete mode 100644 strix/interface/viewer/static/assets/index-DKbLYAbP.css create mode 100644 strix/interface/viewer/static/assets/index-g-_6CcwH.css create mode 100644 strix/report/coverage.py create mode 100644 strix/skills/analysis/counterevidence.md create mode 100644 strix/skills/analysis/fix_verification.md create mode 100644 strix/skills/analysis/severity_calibration.md create mode 100644 strix/skills/analysis/source_aware_discovery.md create mode 100644 strix/skills/scan_modes/diff.md create mode 100644 strix/tools/coverage/__init__.py create mode 100644 strix/tools/coverage/tools.py create mode 100644 strix/tools/threat_model/__init__.py create mode 100644 strix/tools/threat_model/tools.py create mode 100644 tests/test_coverage_tool.py create mode 100644 tests/test_finish_coverage_gate.py create mode 100644 tests/test_report_coverage.py create mode 100644 tests/test_state_coverage_artifact.py create mode 100644 tests/test_threat_model_tool.py diff --git a/strix/agents/factory.py b/strix/agents/factory.py index a4833539..3b56a55f 100644 --- a/strix/agents/factory.py +++ b/strix/agents/factory.py @@ -26,6 +26,7 @@ from strix.tools.agents_graph.tools import ( view_agent_graph, wait_for_agents, ) +from strix.tools.coverage.tools import list_coverage, record_coverage, update_coverage from strix.tools.finish.tool import finish_scan from strix.tools.load_skill.tool import load_skill from strix.tools.notes.tools import ( @@ -52,6 +53,11 @@ from strix.tools.reporting.tool import ( ) from strix.tools.respond.tool import respond_to_user from strix.tools.thinking.tool import think +from strix.tools.threat_model.tools import ( + amend_threat_model, + get_threat_model, + save_threat_model, +) from strix.tools.todo.tools import ( create_todo, delete_todo, @@ -528,6 +534,12 @@ _BASE_TOOLS: tuple[Tool, ...] = ( get_note, update_note, delete_note, + record_coverage, + update_coverage, + list_coverage, + get_threat_model, + save_threat_model, + amend_threat_model, web_search, create_vulnerability_report, create_dependency_report, @@ -596,6 +608,7 @@ def build_strix_agent( is_root: bool, scan_mode: str = "deep", is_whitebox: bool = False, + is_diff_scoped: bool = False, interactive: bool = False, chat_completions_tools: bool = False, strict_tool_schemas: bool = True, @@ -623,6 +636,7 @@ def build_strix_agent( scan_mode=scan_mode, is_whitebox=is_whitebox, is_root=is_root, + is_diff_scoped=is_diff_scoped, interactive=interactive, system_prompt_context=system_prompt_context, ) @@ -680,6 +694,7 @@ def make_child_factory( *, scan_mode: str = "deep", is_whitebox: bool = False, + is_diff_scoped: bool = False, interactive: bool = False, chat_completions_tools: bool = False, strict_tool_schemas: bool = True, @@ -699,6 +714,7 @@ def make_child_factory( is_root=False, scan_mode=scan_mode, is_whitebox=is_whitebox, + is_diff_scoped=is_diff_scoped, interactive=interactive, chat_completions_tools=chat_completions_tools, strict_tool_schemas=strict_tool_schemas, diff --git a/strix/agents/prompt.py b/strix/agents/prompt.py index 20f10d0f..09e4733b 100644 --- a/strix/agents/prompt.py +++ b/strix/agents/prompt.py @@ -23,30 +23,44 @@ def _resolve_skills( scan_mode: str = "deep", is_whitebox: bool = False, is_root: bool = False, + is_diff_scoped: bool = False, ) -> list[str]: """Build the deduped, ordered skills list for the prompt render. Order: 1. Whatever the caller asked for, in order. - 2. ``scan_modes/`` (always). + 2. ``scan_modes/`` (always), plus ``scan_modes/diff`` when the + run is scoped to a change set β€” diff scope overlays the depth + mode rather than replacing it. 3. ``tooling/agent_browser`` (always β€” every agent has shell + the agent-browser CLI). 4. ``tooling/python`` (always β€” Python runs through ``exec_command``; sandbox scripts can import ``caido_api`` for Caido automation). - 5. ``coordination/root_agent`` for the root agent only β€” orchestration + 5. ``analysis/counterevidence`` and ``analysis/severity_calibration`` + (always β€” closure discipline and severity rubric apply to every + agent that can open or close a candidate, or file a report). + 6. ``coordination/root_agent`` for the root agent only β€” orchestration guidance for delegating to specialist subagents. - 6. Whitebox-specific skills if applicable. + 7. Whitebox-specific skills if applicable, including + ``analysis/fix_verification`` (only whitebox agents can attach an + applyable ``fix_after``) and ``analysis/source_aware_discovery``. """ ordered: list[str] = list(requested or []) ordered.append(f"scan_modes/{scan_mode}") + if is_diff_scoped: + ordered.append("scan_modes/diff") ordered.append("tooling/agent_browser") ordered.append("tooling/python") + ordered.append("analysis/counterevidence") + ordered.append("analysis/severity_calibration") if is_root: ordered.append("coordination/root_agent") if is_whitebox: ordered.append("coordination/source_aware_whitebox") ordered.append("custom/source_aware_sast") + ordered.append("analysis/source_aware_discovery") + ordered.append("analysis/fix_verification") deduped: list[str] = [] seen: set[str] = set() @@ -63,6 +77,7 @@ def render_system_prompt( scan_mode: str = "deep", is_whitebox: bool = False, is_root: bool = False, + is_diff_scoped: bool = False, interactive: bool = False, system_prompt_context: dict[str, Any] | None = None, ) -> str: @@ -83,6 +98,7 @@ def render_system_prompt( scan_mode=scan_mode, is_whitebox=is_whitebox, is_root=is_root, + is_diff_scoped=is_diff_scoped, ) skill_content = load_skills(skills_to_load) env.globals["get_skill"] = lambda name: skill_content.get(name, "") diff --git a/strix/agents/prompts/system_prompt.jinja b/strix/agents/prompts/system_prompt.jinja index 23493d2d..95590394 100644 --- a/strix/agents/prompts/system_prompt.jinja +++ b/strix/agents/prompts/system_prompt.jinja @@ -216,10 +216,31 @@ VALIDATION REQUIREMENTS: - Independent verification through subagent - Document complete attack chain - Keep going until you find something that matters +- CLOSURE DISCIPLINE: every candidate you open ends in exactly one explicit state β€” `confirmed` (working PoC, or a complete sourceβ†’controlβ†’sinkβ†’impact trace that is reachable), `ruled_out` (you can name the SPECIFIC control, at a location, that runs on every attacker-reachable path before the sink), or `open_proof_gap` (plausible, unconfirmed, and you could NOT name such a control). "I moved on" is not a closure state. Silently dropping an uncertain candidate is mislabelling an `open_proof_gap` as `ruled_out` and is how real bugs get missed. +- Missing information is NOT proof of safety: no caller found, can't tell if deployed/exposed, couldn't stand up the service, build failed β€” each is an `open_proof_gap`, never a reason to mark a candidate clean. Difficulty is a reason to defer, not to suppress. +- COVERAGE: record every surface you assess with `record_coverage` (surface + risk area + outcome + evidence), including the ones that came back clean β€” a report that only lists findings cannot say what was reviewed and cleared. Use the `needs_follow_up` outcome for anything left in an `open_proof_gap` state, and carry the same items up in `agent_finish(open_items=[...])`. The ledger is shared and mutable: when you resolve a surface another agent left open β€” or find that a closed one is not β€” move that entry with `update_coverage` instead of recording a second one for the same surface. The root agent reconciles all of it via `list_coverage` before `finish_scan`. +- THREAT MODEL: before you start testing, call `get_threat_model` on the target you were pointed at β€” it is the scan's shared answer to who the attacker is, where the trust boundaries sit, and what counts as critical here, and it is cached per target rather than per scan. Read it instead of re-deriving trust boundaries yourself; where your testing disproves it β€” a boundary it calls trusted turns out to be attacker-reachable, a role it did not know about, a host or endpoint it never listed β€” record that with `amend_threat_model` so the agents after you inherit the correction. Amending is not optional politeness: a model nobody corrects turns the first agent's guesses into everyone's assumptions. +- Before filing any report, run the counterevidence pass: argue the strongest case AGAINST the finding, record what you found in the `counterevidence` field, set `confidence` honestly (a static-only trace you couldn't execute is at best `medium`), and state what evidence would change the severity. See the counterevidence and severity-calibration knowledge above. - A vulnerability is ONLY considered reported when a reporting agent uses create_vulnerability_report (or create_dependency_report for known-CVE dependency/supply-chain findings) with full details. Mentions in agent_finish, finish_scan, or generic messages are NOT sufficient - Reporting and fixing are ONE step, not two: when source is available, the reporting agent derives the concrete fix and files it INLINE via create_vulnerability_report (`code_locations` with `fix_before`/`fix_after` + `fix_pr_body`) β€” the report is not complete without it. Do NOT report first and then spawn a separate downstream agent to re-derive and re-apply the same patch; that just re-does the analysis and wastes tokens. (Do not silently patch a finding WITHOUT filing a report β€” the report, with its embedded fix, is the deliverable.) - DEDUPLICATION: The create_vulnerability_report tool uses LLM-based deduplication. If it rejects your report as a duplicate, DO NOT attempt to re-submit the same vulnerability. Accept the rejection and move on to testing other areas. The vulnerability has already been reported by another agent - REVIEWING FILED FINDINGS (orchestrator/root agent): use list_reports to see every vulnerability filed so far in this scan (by any agent, root or child) β€” metadata-first with per-severity counts β€” and get_report to read one finding in full by its id. These are read-only orchestration tools: the root agent uses them to track coverage, avoid dispatching work on already-covered ground, assemble the finish_scan executive summary, and reason about attack-chaining across confirmed findings. Leaf/specialist agents should NOT call them β€” just do your assigned testing and file findings. Each entry shows which agent filed it (agent_name), and your own entries are flagged by_you. list_notes/get_note do the same for notes. + +STATE & COORDINATION TOOLS (when and how): +Every one of these tools writes to state the rest of the scan reads. Reaching for the tool is not optional bookkeeping β€” the agent after you sees your state, not your reasoning, so state you never wrote is context the scan permanently loses. +- PLAN β€” `think`: use before any non-trivial or multi-step move to reason through approach, uncertainty, or what to do next. NOT for acknowledgements, summaries, or as filler before a final answer. +- SKILLS β€” `load_skill`: the skills matching your task are already inlined below under ``; `` lists the rest by name. When you are about to test a vuln class, protocol, tool, or framework whose skill is not already inlined, `load_skill` it FIRST and follow it, rather than guessing payloads or tool syntax from memory. +- TODOS β€” `create_todo` / `list_todos` / `update_todo` / `mark_todo_done` / `mark_todo_pending` / `delete_todo`: your own working checklist for a multi-step task. Create todos when your task has several distinct steps so nothing is dropped across a long run; mark them done as you finish. This is private working memory β€” use `notes` for anything another agent needs. +- NOTES β€” `create_note` / `list_notes` / `get_note` / `update_note` / `delete_note`: the scan's shared scratchpad, visible to every agent. Write a note for a durable cross-agent fact that is not a finding and not coverage β€” a working credential set, a discovered endpoint inventory, an enumerated tenant list, a rate-limit quirk the next agent needs. `update_note` to keep a living inventory current; `delete_note` only for something now wrong or superseded. Check `list_notes`/`get_note` before recon work so you build on what is already mapped instead of redoing it. +- THREAT MODEL β€” `get_threat_model` / `amend_threat_model` / `save_threat_model`: covered above. `save_threat_model` REPLACES the whole document and clears amendments, so it is for establishing the baseline or folding amendments in (normally root) β€” to correct part of an existing model, `amend_threat_model` instead. +- COVERAGE β€” `record_coverage` / `update_coverage` / `list_coverage`: covered above. One row per surface+risk; correct an existing row with `update_coverage`, never a second `record_coverage`. +- RESEARCH β€” `web_search`: pull fresh, target-specific external knowledge β€” latest bypasses, WAF evasions, DB-/framework-specific syntax, CVE and advisory detail β€” before falling back to memorized payloads, and refresh payload corpora mid-spray. +- SPAWN WORK β€” `create_agent`: delegate a focused subtask to a specialist child (see the multi-agent rules below for when to spawn and how to scope it). Give it the target to model against and what is already known. +- TRACK CHILDREN β€” `view_agent_graph`: your live map of every agent and its status. Call it before spawning (to confirm no existing agent already covers the scope) and before finishing (to confirm no child is still running). +- STEER CHILDREN β€” `send_message_to_agent`: send a running child new information, a course correction, or a request to wrap up, without killing it. Use it to answer a child's question or narrow its scope mid-run. +- BLOCK ON CHILDREN β€” `wait_for_agents`: block until named children report back when your next move genuinely depends on their results. If you can keep making progress in parallel, keep working instead of waiting. +- CANCEL CHILDREN β€” `stop_agent`: gracefully cancel a child whose work is redundant, misdirected, or no longer needed. Prefer `send_message_to_agent` to redirect a child that is merely off-track; reserve `stop_agent` for work that should not continue at all. +- FINISH β€” subagents call `agent_finish` (with `open_items=[...]` for anything left unresolved); the root agent calls `finish_scan` exactly once, only after every child is wrapped up and coverage is reconciled. `agent_finish`/`finish_scan` are handoffs, not reporting channels β€” a vulnerability is reported only via `create_vulnerability_report`/`create_dependency_report`. diff --git a/strix/core/inputs.py b/strix/core/inputs.py index ea72abb7..f383261e 100644 --- a/strix/core/inputs.py +++ b/strix/core/inputs.py @@ -226,6 +226,23 @@ def build_scope_context(scan_config: dict[str, Any]) -> dict[str, Any]: } +def build_scan_targets(scan_config: dict[str, Any]) -> list[str]: + """One canonical string per authorized target. + + Agents refer to the target in whatever words they were handed, so anything + keyed on a target the model types drifts apart across a run. This is the + scan's own spelling, which target-keyed tools resolve against. A checkout is + named by its workspace path rather than its remote URL, so the local tree β€” + and its revision β€” is what gets inspected. + """ + targets: list[str] = [] + for target in build_scope_context(scan_config)["authorized_targets"]: + value = target["workspace_path"] or target["value"] + if value and value not in targets: + targets.append(value) + return targets + + def make_model_settings( reasoning_effort: ReasoningEffort | None, *, diff --git a/strix/core/runner.py b/strix/core/runner.py index 0dfe75d0..94e90389 100644 --- a/strix/core/runner.py +++ b/strix/core/runner.py @@ -37,6 +37,7 @@ from strix.core.execution import ( from strix.core.hooks import BudgetExceededError, ReportUsageHooks, recomputed_budget_flags from strix.core.inputs import ( build_root_task, + build_scan_targets, build_scope_context, make_model_settings, ) @@ -84,6 +85,7 @@ def _compose_root_instructions_override( skills: list[str], scan_mode: str, is_whitebox: bool, + is_diff_scoped: bool, interactive: bool, system_prompt_context: dict[str, Any], ) -> str | None: @@ -95,6 +97,7 @@ def _compose_root_instructions_override( scan_mode=scan_mode, is_whitebox=is_whitebox, is_root=True, + is_diff_scoped=is_diff_scoped, interactive=interactive, system_prompt_context=system_prompt_context, ) @@ -184,11 +187,13 @@ async def run_strix_scan( coordinator = AgentCoordinator() coordinator.set_snapshot_path(agents_path) + from strix.tools.coverage.tools import hydrate_coverage_from_disk from strix.tools.notes.tools import hydrate_notes_from_disk from strix.tools.todo.tools import hydrate_todos_from_disk hydrate_todos_from_disk(state_dir) hydrate_notes_from_disk(state_dir) + hydrate_coverage_from_disk(state_dir) root_id: str | None = None if is_resume: @@ -262,6 +267,8 @@ async def run_strix_scan( targets = scan_config.get("targets") or [] scan_mode = str(scan_config.get("scan_mode") or "deep") is_whitebox = any(t.get("type") == "local_code" for t in targets) + diff_scope = scan_config.get("diff_scope") + is_diff_scoped = bool(isinstance(diff_scope, dict) and diff_scope.get("active")) skills = list(scan_config.get("skills") or []) root_task = build_root_task(scan_config) model_settings = make_model_settings( @@ -298,6 +305,7 @@ async def run_strix_scan( skills=skills, scan_mode=scan_mode, is_whitebox=is_whitebox, + is_diff_scoped=is_diff_scoped, interactive=interactive, system_prompt_context=root_context, ) @@ -308,6 +316,7 @@ async def run_strix_scan( is_root=True, scan_mode=scan_mode, is_whitebox=is_whitebox, + is_diff_scoped=is_diff_scoped, interactive=interactive, chat_completions_tools=chat_completions_tools, strict_tool_schemas=strict_tool_schemas, @@ -327,6 +336,7 @@ async def run_strix_scan( child_agent_builder = make_child_factory( scan_mode=scan_mode, is_whitebox=is_whitebox, + is_diff_scoped=is_diff_scoped, interactive=interactive, chat_completions_tools=chat_completions_tools, strict_tool_schemas=strict_tool_schemas, @@ -355,6 +365,7 @@ async def run_strix_scan( "parent_id": None, "interactive": interactive, "spawn_child_agent": spawn_child_agent, + "scan_targets": build_scan_targets(scan_config), "max_context_images": settings.runtime.max_context_images, } diff --git a/strix/interface/tui/internal/render/coverage.go b/strix/interface/tui/internal/render/coverage.go new file mode 100644 index 00000000..3f6c161e --- /dev/null +++ b/strix/interface/tui/internal/render/coverage.go @@ -0,0 +1,194 @@ +package render + +import ( + "strconv" + "strings" + + "github.com/charmbracelet/lipgloss" +) + +// --------------------------------------------------------------------------- +// Coverage ledger (record_coverage / update_coverage / list_coverage) +// --------------------------------------------------------------------------- + +// coverageOutcomes maps a ledger outcome to its marker and color. A cleared +// surface and an unresolved one must not look alike at a glance: the whole +// point of the ledger is that a reader can see which surfaces are still open. +var coverageOutcomes = map[string]struct { + marker string + label string + color lipgloss.Color +}{ + "reported": {"!", "reported", SevHigh}, + "no_issue_found": {"βœ“", "no issue found", Green}, + "ruled_out": {"βœ“", "ruled out", Mint}, + "not_applicable": {"–", "not applicable", Slate}, + "needs_follow_up": {"?", "needs follow-up", AmberY}, +} + +func coverageOutcome(outcome string) (string, string, lipgloss.Color) { + if meta, ok := coverageOutcomes[strings.TrimSpace(strings.ToLower(outcome))]; ok { + return meta.marker, meta.label, meta.color + } + if outcome == "" { + return "Β·", "", Gray + } + return "Β·", strings.ReplaceAll(outcome, "_", " "), Gray +} + +var coverageTitles = map[string]struct { + title string + loading string + errMsg string +}{ + "record_coverage": {"Coverage Recorded", "Recording...", "Failed to record coverage"}, + "update_coverage": {"Coverage Updated", "Updating...", "Failed to update coverage"}, + "list_coverage": {"Coverage", "Loading...", "Unable to list coverage"}, +} + +func renderCoverage(name string, args map[string]any, result any) string { + meta := coverageTitles[name] + var b strings.Builder + b.WriteString("β–£ " + Bold(Cyan).Render(meta.title)) + + if s, ok := result.(string); ok && strings.TrimSpace(s) != "" { + b.WriteString("\n " + Dim().Render(strings.TrimSpace(s))) + return b.String() + } + m, ok := result.(map[string]any) + if !ok { + coverageArgsPreview(&b, name, args) + b.WriteString("\n " + Dim().Render(meta.loading)) + return b.String() + } + if !truthy(m["success"]) { + coverageArgsPreview(&b, name, args) + errMsg := StringValue(m["error"]) + if errMsg == "" { + errMsg = meta.errMsg + } + b.WriteString("\n " + Col(Red).Render(errMsg)) + return b.String() + } + + switch name { + case "list_coverage": + coverageListBody(&b, m) + case "update_coverage": + marker, label, color := coverageOutcome(StringValue(m["outcome"])) + _, previous, previousColor := coverageOutcome(StringValue(m["previous_outcome"])) + b.WriteString("\n " + Col(color).Render(marker) + " " + coverageSubject(args, m)) + if previous != "" { + b.WriteString("\n " + Col(previousColor).Render(previous) + + Dim().Render(" β†’ ") + Col(color).Render(label)) + } else { + b.WriteString("\n " + Col(color).Render(label)) + } + coverageEvidence(&b, StringValue(args["evidence"])) + default: + marker, label, color := coverageOutcome(StringValue(m["outcome"])) + b.WriteString("\n " + Col(color).Render(marker) + " " + coverageSubject(args, m)) + b.WriteString("\n " + Col(color).Render(label)) + coverageEvidence(&b, StringValue(args["evidence"])) + } + return b.String() +} + +// coverageSubject names the surface being recorded, falling back to the entry +// id when only the id is known (an update carries no surface in its args). +func coverageSubject(args map[string]any, result map[string]any) string { + surface := strings.TrimSpace(StringValue(args["surface"])) + risk := strings.TrimSpace(StringValue(args["risk_area"])) + switch { + case surface != "" && risk != "": + return surface + Dim().Render(" Β· "+risk) + case surface != "": + return surface + case risk != "": + return risk + } + if id := StringValue(result["entry_id"]); id != "" { + return Dim().Render("entry " + id) + } + return Dim().Render("(unnamed surface)") +} + +func coverageEvidence(b *strings.Builder, evidence string) { + if strings.TrimSpace(evidence) != "" { + b.WriteString("\n " + Dim().Render(psanitize(strings.TrimSpace(evidence), 160))) + } +} + +func coverageArgsPreview(b *strings.Builder, name string, args map[string]any) { + if name == "list_coverage" { + return + } + if subject := coverageSubject(args, map[string]any{}); subject != "" { + b.WriteString("\n " + subject) + } +} + +func coverageListBody(b *strings.Builder, result map[string]any) { + entries, _ := result["entries"].([]any) + total, _ := NumericValue(result["total_count"]) + if len(entries) == 0 { + if int(total) == 0 { + b.WriteString("\n " + Dim().Render("No surfaces recorded yet")) + } else { + b.WriteString("\n " + Dim().Render("No surfaces match this filter")) + } + return + } + + if counts, ok := result["outcome_counts"].(map[string]any); ok && len(counts) > 0 { + var parts []string + for _, outcome := range []string{ + "reported", "no_issue_found", "ruled_out", "not_applicable", "needs_follow_up", + } { + count, ok := NumericValue(counts[outcome]) + if !ok || count == 0 { + continue + } + _, label, color := coverageOutcome(outcome) + parts = append(parts, Col(color).Render(label+": "+strconv.Itoa(int(count)))) + } + if len(parts) > 0 { + b.WriteString("\n " + strings.Join(parts, Dim().Render(" "))) + } + } + + for _, e := range entries { + entry, _ := e.(map[string]any) + marker, label, color := coverageOutcome(StringValue(entry["outcome"])) + surface := strings.TrimSpace(StringValue(entry["surface"])) + if surface == "" { + surface = "(unnamed surface)" + } + b.WriteString("\n " + Col(color).Render(marker) + " " + surface) + if risk := strings.TrimSpace(StringValue(entry["risk_area"])); risk != "" { + b.WriteString(Dim().Render(" Β· " + risk)) + } + b.WriteString("\n " + Col(color).Render(label)) + // A row that moved states carries its own history; showing it keeps a + // closed surface from reading as one that was never in question. + if previous, ok := entry["previous_outcomes"].([]any); ok && len(previous) > 0 { + var was []string + for _, p := range previous { + if _, label, _ := coverageOutcome(StringValue(p)); label != "" { + was = append(was, label) + } + } + if len(was) > 0 { + b.WriteString(Dim().Render(" (was " + strings.Join(was, " β†’ ") + ")")) + } + } + // Whose row this is matters for reconciliation: an agent needs to see + // at a glance which surfaces it owns and which came from a sibling. + if truthy(entry["by_you"]) { + b.WriteString(Dim().Render(" Β· you")) + } else if who := strings.TrimSpace(StringValue(entry["agent_name"])); who != "" { + b.WriteString(Dim().Render(" Β· " + who)) + } + coverageEvidence(b, StringValue(entry["evidence"])) + } +} diff --git a/strix/interface/tui/internal/render/coverage_test.go b/strix/interface/tui/internal/render/coverage_test.go new file mode 100644 index 00000000..f4a38ee2 --- /dev/null +++ b/strix/interface/tui/internal/render/coverage_test.go @@ -0,0 +1,204 @@ +package render + +import ( + "strings" + "testing" + + "github.com/charmbracelet/x/ansi" +) + +func TestRecordCoverageRendersSurfaceAndOutcome(t *testing.T) { + out := ansi.Strip(Tool(tool("record_coverage", + map[string]any{ + "surface": "POST /api/v1/invoices", + "risk_area": "object-level authorization", + "evidence": "tenant B token returns 403 on tenant A invoice ids", + }, + map[string]any{"success": true, "entry_id": "a1b2c3", "outcome": "ruled_out"}, + "completed"))) + requireContains(t, out, + "Coverage Recorded", + "POST /api/v1/invoices", + "object-level authorization", + "ruled out", + "tenant B token returns 403", + ) +} + +func TestUpdateCoverageShowsStateTransition(t *testing.T) { + out := ansi.Strip(Tool(tool("update_coverage", + map[string]any{"entry_id": "a1b2c3", "evidence": "reproduced with a second tenant"}, + map[string]any{ + "success": true, + "entry_id": "a1b2c3", + "previous_outcome": "needs_follow_up", + "outcome": "reported", + }, + "completed"))) + requireContains(t, out, "Coverage Updated", "needs follow-up", "β†’", "reported") +} + +func TestListCoverageRendersCountsHistoryAndAuthor(t *testing.T) { + out := ansi.Strip(Tool(tool("list_coverage", nil, + map[string]any{ + "success": true, + "entries": []any{ + map[string]any{ + "entry_id": "a1b2c3", + "surface": "/admin/export", + "risk_area": "IDOR", + "outcome": "no_issue_found", + "agent_name": "AuthzAgent", + "previous_outcomes": []any{"needs_follow_up"}, + "evidence": "org id is server-derived from the session", + }, + map[string]any{ + "entry_id": "d4e5f6", + "surface": "/graphql", + "risk_area": "injection", + "outcome": "needs_follow_up", + "by_you": true, + "evidence": "introspection disabled; needs an authenticated schema dump", + }, + }, + "total_count": 2, + "outcome_counts": map[string]any{"no_issue_found": 1, "needs_follow_up": 1}, + }, + "completed"))) + requireContains(t, out, + "/admin/export", "IDOR", "no issue found", + "was needs follow-up", "AuthzAgent", + "/graphql", "needs follow-up", "you", + "no issue found: 1", "needs follow-up: 1", + ) +} + +func TestListCoverageEmptyLedgerReadsAsUnrecorded(t *testing.T) { + out := ansi.Strip(Tool(tool("list_coverage", nil, + map[string]any{"success": true, "entries": []any{}, "total_count": 0}, "completed"))) + requireContains(t, out, "No surfaces recorded yet") + + filtered := ansi.Strip(Tool(tool("list_coverage", + map[string]any{"outcome": "reported"}, + map[string]any{"success": true, "entries": []any{}, "total_count": 4}, "completed"))) + requireContains(t, filtered, "No surfaces match this filter") +} + +func TestCoverageDuplicateRejectionSurfacesTheError(t *testing.T) { + out := ansi.Strip(Tool(tool("record_coverage", + map[string]any{"surface": "/login", "risk_area": "XSS"}, + map[string]any{ + "success": false, + "error": "'/login' (XSS) already has coverage entry a1b2c3", + "existing_entry_id": "a1b2c3", + }, + "completed"))) + requireContains(t, out, "/login", "already has coverage entry a1b2c3") +} + +func TestGetThreatModelRendersStalenessAndAmendments(t *testing.T) { + out := ansi.Strip(Tool(tool("get_threat_model", + map[string]any{"target": "https://app.example.com"}, + map[string]any{ + "success": true, + "found": true, + "stale": true, + "cached_revision": "0123456789abcdef", + "content": "# Overview\nMulti-tenant billing app.\n\n" + + "## Trust Boundaries and Assumptions\n\n## Attack Surface\n", + "amendments": []any{ + map[string]any{ + "agent_name": "ReconAgent", + "content": "staging host shares the production database", + }, + }, + }, + "completed"))) + requireContains(t, out, + "Threat Model", "https://app.example.com", + "stale", "01234567", + "1 amendment(s)", "ReconAgent", "staging host shares the production database", + "Multi-tenant billing app.", "Overview", "Trust Boundaries and Assumptions", + ) +} + +func TestGetThreatModelMissingModelIsExplicit(t *testing.T) { + out := ansi.Strip(Tool(tool("get_threat_model", + map[string]any{"target": "10.0.0.5"}, + map[string]any{"success": true, "found": false}, "completed"))) + requireContains(t, out, "No model cached for this target yet") +} + +func TestSaveThreatModelWarnsWhenAmendmentsAreCleared(t *testing.T) { + out := ansi.Strip(Tool(tool("save_threat_model", + map[string]any{"target": "app.example.com", "content": "# Overview\nA thing.\n"}, + map[string]any{ + "success": true, + "revision": "unversioned", + "amendments_cleared": 2, + }, + "completed"))) + requireContains(t, out, "Threat Model Saved", "saved", "cleared 2 amendment(s)") + // An unversioned target has no revision worth printing. + if strings.Contains(out, "unversioned") { + t.Fatalf("unversioned revision should not be rendered:\n%s", out) + } +} + +func TestAmendThreatModelRendersAddendum(t *testing.T) { + out := ansi.Strip(Tool(tool("amend_threat_model", + map[string]any{ + "target": "app.example.com", + "addendum": "The admin role is assignable by any org member via PATCH /members.", + }, + map[string]any{"success": true, "amendment_count": 3}, "completed"))) + requireContains(t, out, "Threat Model Amended", "amendment recorded", "(3 total)", + "admin role is assignable") +} + +func TestCoverageAndThreatModelToolsAreNotGeneric(t *testing.T) { + // The generic fallback dumps raw arg keys; these tools must not reach it. + for _, name := range []string{ + "record_coverage", "update_coverage", "list_coverage", + "get_threat_model", "save_threat_model", "amend_threat_model", + } { + out := ansi.Strip(Tool(tool(name, map[string]any{"target": "x", "surface": "y"}, nil, "running"))) + if strings.Contains(out, "Using tool") { + t.Fatalf("%s fell through to the generic renderer:\n%s", name, out) + } + } +} + +func TestOutputHeavyCoverageToolsCollapse(t *testing.T) { + for _, name := range []string{"list_coverage", "get_threat_model"} { + if ToolPreviewLines(name) == 0 { + t.Fatalf("%s should collapse; its output is unbounded", name) + } + } + for _, name := range []string{"record_coverage", "amend_threat_model"} { + if ToolPreviewLines(name) != 0 { + t.Fatalf("%s should not collapse", name) + } + } +} + +func TestVulnerabilityReportRendersCalibrationFields(t *testing.T) { + out := ansi.Strip(Tool(tool("create_vulnerability_report", + map[string]any{ + "title": "IDOR in invoice export", + "confidence": "medium", + "confidence_rationale": "traced statically; no authenticated instance to replay against", + "counterevidence": "the gateway may strip the id parameter before it reaches the handler", + "severity_change_conditions": "critical if the export includes other tenants' bank details", + "fix_verification": "unit tests executed; bypass review reasoned only", + "description": "The handler trusts a client-supplied invoice id.", + }, + map[string]any{"success": true, "severity": "high", "cvss_score": 7.5}, + "completed"))) + requireContains(t, out, + "Confidence", "MEDIUM", "no authenticated instance to replay against", + "Counterevidence", "gateway may strip the id parameter", + "Severity Would Change If", "other tenants' bank details", + "Fix Verification", "bypass review reasoned only", + ) +} diff --git a/strix/interface/tui/internal/render/registry.go b/strix/interface/tui/internal/render/registry.go index 3c235b0a..ef8c9a41 100644 --- a/strix/interface/tui/internal/render/registry.go +++ b/strix/interface/tui/internal/render/registry.go @@ -82,6 +82,10 @@ func Tool(data map[string]any) string { return renderNote(name, args, result) case "create_todo", "list_todos", "update_todo", "mark_todo_done", "mark_todo_pending", "delete_todo": return renderTodo(name, result) + case "record_coverage", "update_coverage", "list_coverage": + return renderCoverage(name, args, result) + case "get_threat_model", "save_threat_model", "amend_threat_model": + return renderThreatModel(name, args, result) case "view_agent_graph", "create_agent", "send_message_to_agent", "agent_finish", "wait_for_agents", "stop_agent": return renderAgentGraphTool(name, args, result) case "list_requests", "view_request", "repeat_request", "list_sitemap", "view_sitemap_entry", "scope_rules": @@ -103,7 +107,8 @@ const outputPreviewLines = 10 func ToolPreviewLines(name string) int { switch name { case "exec_command", "write_stdin", "apply_patch", - "view_request", "repeat_request", "view_sitemap_entry": + "view_request", "repeat_request", "view_sitemap_entry", + "list_coverage", "get_threat_model": return outputPreviewLines } return 0 diff --git a/strix/interface/tui/internal/render/report.go b/strix/interface/tui/internal/render/report.go index 0002fdb2..9fe2026a 100644 --- a/strix/interface/tui/internal/render/report.go +++ b/strix/interface/tui/internal/render/report.go @@ -50,15 +50,31 @@ func renderVulnerabilityReport(args map[string]any, result any) string { b.WriteString("\n\n" + Bold(Field).Render(label) + "\n" + value) } } + if confidence := StringValue(args["confidence"]); confidence != "" { + b.WriteString("\n\n" + Bold(Field).Render("Confidence: ") + + lipgloss.NewStyle().Bold(true).Foreground(confidenceColor(confidence)). + Render(strings.ToUpper(confidence))) + if rationale := StringValue(args["confidence_rationale"]); rationale != "" { + b.WriteString("\n" + Dim().Render(rationale)) + } + } + section("Description", StringValue(args["description"])) section("Impact", StringValue(args["impact"])) section("Technical Analysis", StringValue(args["technical_analysis"])) + // The case against the finding travels with the case for it: a reader + // triaging this needs both to judge whether to act. + section("Counterevidence", StringValue(args["counterevidence"])) + section("Severity Would Change If", StringValue(args["severity_change_conditions"])) renderCodeLocations(&b, args["code_locations"]) section("PoC Description", StringValue(args["poc_description"])) if poc := StringValue(args["poc_script_code"]); poc != "" { b.WriteString("\n\n" + Bold(Field).Render("PoC Code") + "\n" + Col(Text).Render(poc)) } section("Remediation", StringValue(args["remediation_steps"])) + // Any applyable fix above is one click from the user's codebase, so how it + // was verified belongs next to it rather than in the artifact alone. + section("Fix Verification", StringValue(args["fix_verification"])) if title == "" { b.WriteString("\n " + Dim().Render("Creating report...")) @@ -66,6 +82,20 @@ func renderVulnerabilityReport(args map[string]any, result any) string { return "\n\n" + b.String() + "\n\n" } +// confidenceColor grades how firm the agent's own call is. Anything below +// high is a claim the reader has to check, and should not read as settled. +func confidenceColor(confidence string) lipgloss.Color { + switch strings.ToLower(strings.TrimSpace(confidence)) { + case "high": + return Green + case "medium": + return SevMed + case "low": + return SevHigh + } + return Gray +} + var cvssKeys = [][2]string{ {"attack_vector", "AV"}, {"attack_complexity", "AC"}, {"privileges_required", "PR"}, {"user_interaction", "UI"}, {"scope", "S"}, {"confidentiality", "C"}, diff --git a/strix/interface/tui/internal/render/threat_model.go b/strix/interface/tui/internal/render/threat_model.go new file mode 100644 index 00000000..411e5ede --- /dev/null +++ b/strix/interface/tui/internal/render/threat_model.go @@ -0,0 +1,138 @@ +package render + +import ( + "strconv" + "strings" +) + +// --------------------------------------------------------------------------- +// Threat model (get_threat_model / save_threat_model / amend_threat_model) +// --------------------------------------------------------------------------- + +var threatModelTitles = map[string]struct { + title string + loading string + errMsg string +}{ + "get_threat_model": {"Threat Model", "Loading...", "Unable to read threat model"}, + "save_threat_model": {"Threat Model Saved", "Saving...", "Failed to save threat model"}, + "amend_threat_model": {"Threat Model Amended", "Amending...", "Failed to amend threat model"}, +} + +func renderThreatModel(name string, args map[string]any, result any) string { + meta := threatModelTitles[name] + var b strings.Builder + b.WriteString("βŒ– " + Bold(InfoBlue).Render(meta.title)) + if target := strings.TrimSpace(StringValue(args["target"])); target != "" { + b.WriteString(Dim().Render(" " + target)) + } + + if s, ok := result.(string); ok && strings.TrimSpace(s) != "" { + b.WriteString("\n " + Dim().Render(strings.TrimSpace(s))) + return b.String() + } + m, ok := result.(map[string]any) + if !ok { + b.WriteString("\n " + Dim().Render(meta.loading)) + return b.String() + } + if !truthy(m["success"]) { + errMsg := StringValue(m["error"]) + if errMsg == "" { + errMsg = meta.errMsg + } + b.WriteString("\n " + Col(Red).Render(errMsg)) + return b.String() + } + + switch name { + case "get_threat_model": + threatModelReadBody(&b, m) + case "amend_threat_model": + b.WriteString("\n " + Col(Green).Render("βœ“ amendment recorded")) + if count, ok := NumericValue(m["amendment_count"]); ok { + b.WriteString(Dim().Render(" (" + strconv.Itoa(int(count)) + " total)")) + } + threatModelBody(&b, StringValue(args["addendum"])) + default: + b.WriteString("\n " + Col(Green).Render("βœ“ saved")) + if revision := shortRevision(StringValue(m["revision"])); revision != "" { + b.WriteString(Dim().Render(" at " + revision)) + } + // Saving folds amendments away, so the count that vanished is worth + // stating: it is the one destructive thing this tool does. + if cleared, ok := NumericValue(m["amendments_cleared"]); ok && cleared > 0 { + b.WriteString("\n " + Col(AmberY).Render("⚠ cleared "+ + strconv.Itoa(int(cleared))+" amendment(s)")) + } + threatModelBody(&b, StringValue(args["content"])) + } + return b.String() +} + +func threatModelReadBody(b *strings.Builder, result map[string]any) { + if !truthy(result["found"]) { + b.WriteString("\n " + Dim().Render("No model cached for this target yet")) + return + } + if truthy(result["stale"]) { + b.WriteString("\n " + Col(AmberY).Render("⚠ stale")) + if cached := shortRevision(StringValue(result["cached_revision"])); cached != "" { + b.WriteString(Dim().Render(" (written at " + cached + ")")) + } + } + if amendments, ok := result["amendments"].([]any); ok && len(amendments) > 0 { + b.WriteString("\n " + Col(Gold).Render("+ "+strconv.Itoa(len(amendments))+ + " amendment(s)") + Dim().Render(" β€” later statements win")) + for _, a := range amendments { + amendment, _ := a.(map[string]any) + who := strings.TrimSpace(StringValue(amendment["agent_name"])) + if who == "" { + who = "unknown agent" + } + b.WriteString("\n - " + Dim().Render(who+": ") + + psanitize(strings.TrimSpace(StringValue(amendment["content"])), 120)) + } + } + threatModelBody(b, StringValue(result["content"])) +} + +// threatModelBody previews the document. The full text is a page or more, so +// only its section headings and opening line are shown here; the trace can be +// expanded for the rest. +func threatModelBody(b *strings.Builder, content string) { + content = strings.TrimSpace(content) + if content == "" { + return + } + var headings []string + summary := "" + for _, line := range strings.Split(content, "\n") { + line = strings.TrimSpace(line) + switch { + case strings.HasPrefix(line, "#"): + headings = append(headings, strings.TrimSpace(strings.TrimLeft(line, "# "))) + case summary == "" && line != "": + summary = line + } + } + if summary != "" { + b.WriteString("\n " + Dim().Render(psanitize(summary, 160))) + } + if len(headings) > 0 { + if len(headings) > 8 { + headings = headings[:8] + } + b.WriteString("\n " + Dim().Render(strings.Join(headings, " Β· "))) + } +} + +// shortRevision abbreviates a git sha; "unversioned" targets have no revision +// worth showing. +func shortRevision(revision string) string { + revision = strings.TrimSpace(revision) + if revision == "" || revision == "unversioned" { + return "" + } + return firstN(revision, 8) +} diff --git a/strix/interface/viewer/frontend/src/components/live/tool-renderers/CoverageRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/CoverageRenderer.tsx new file mode 100644 index 00000000..57e579ce --- /dev/null +++ b/strix/interface/viewer/frontend/src/components/live/tool-renderers/CoverageRenderer.tsx @@ -0,0 +1,184 @@ +"use client"; + +import type { ToolRendererProps } from "@/types/events"; +import { CheckCircle2, CircleSlash, HelpCircle, AlertTriangle, Circle, ClipboardList } from "lucide-react"; + +interface CoverageEntry { + entry_id?: string; + surface?: string; + risk_area?: string; + outcome?: string; + evidence?: string; + agent_name?: string; + by_you?: boolean; + previous_outcomes?: string[]; +} + +/** + * A cleared surface and an unresolved one must never read alike β€” the ledger + * exists so that the negative space of a scan is legible, so each outcome gets + * its own icon and color rather than a shared neutral row. + */ +const OUTCOMES: Record = { + reported: { label: "reported", color: "text-orange-400", Icon: AlertTriangle }, + no_issue_found: { label: "no issue found", color: "text-emerald-400", Icon: CheckCircle2 }, + ruled_out: { label: "ruled out", color: "text-emerald-400/70", Icon: CheckCircle2 }, + not_applicable: { label: "not applicable", color: "text-[#777]", Icon: CircleSlash }, + needs_follow_up: { label: "needs follow-up", color: "text-yellow-400", Icon: HelpCircle }, +}; + +const OUTCOME_ORDER = [ + "reported", "needs_follow_up", "no_issue_found", "ruled_out", "not_applicable", +] as const; + +function outcomeMeta(outcome: string | undefined) { + const key = (outcome ?? "").trim().toLowerCase(); + return OUTCOMES[key] ?? { + label: key ? key.replace(/_/g, " ") : "unrecorded", + color: "text-[#777]", + Icon: Circle, + }; +} + +const ACTION_LABELS: Record = { + record_coverage: "Coverage recorded", + update_coverage: "Coverage updated", + list_coverage: "Coverage", +}; + +function Header({ toolName }: { toolName: string }) { + return ( +
+ + + {ACTION_LABELS[toolName] ?? "Coverage"} + +
+ ); +} + +function Row({ entry }: { entry: CoverageEntry }) { + const { label, color, Icon } = outcomeMeta(entry.outcome); + const previous = (entry.previous_outcomes ?? []) + .map((o) => outcomeMeta(o).label) + .filter(Boolean); + return ( +
+ +
+
+ {entry.surface ?? "(unnamed surface)"} + {entry.risk_area && Β· {entry.risk_area}} +
+
+ {label} + {previous.length > 0 && ( + (was {previous.join(" β†’ ")}) + )} + {(entry.by_you || entry.agent_name) && ( + Β· {entry.by_you ? "you" : entry.agent_name} + )} +
+ {entry.evidence && ( +
{entry.evidence}
+ )} +
+
+ ); +} + +export default function CoverageRenderer({ toolName, args, result }: ToolRendererProps) { + const res = result as Record | string | null; + + if (typeof res === "string" && res.trim()) { + return ( +
+
+
{res.trim()}
+
+ ); + } + + const structured = res && typeof res === "object" ? res : null; + const surface = (args.surface as string) ?? ""; + const riskArea = (args.risk_area as string) ?? ""; + const evidence = (args.evidence as string) ?? ""; + + if (structured && !structured.success) { + return ( +
+
+ {(surface || riskArea) && ( +
+ {surface} + {riskArea && Β· {riskArea}} +
+ )} +
+ {(structured.error as string) ?? "Coverage call failed"} +
+
+ ); + } + + if (toolName === "list_coverage") { + const rawEntries = structured?.entries; + const entries: CoverageEntry[] = Array.isArray(rawEntries) ? (rawEntries as CoverageEntry[]) : []; + const counts = (structured?.outcome_counts as Record | undefined) ?? {}; + const total = (structured?.total_count as number) ?? 0; + return ( +
+
+ {Object.keys(counts).length > 0 && ( +
+ {OUTCOME_ORDER.filter((o) => counts[o]).map((o) => { + const { label, color } = outcomeMeta(o); + return ( + + {label}: {counts[o]} + + ); + })} +
+ )} + {entries.length > 0 ? ( +
+ {entries.map((entry, i) => )} +
+ ) : ( +
+ {total === 0 ? "No surfaces recorded yet" : "No surfaces match this filter"} +
+ )} +
+ ); + } + + const outcome = (structured?.outcome as string) ?? ""; + const previousOutcome = (structured?.previous_outcome as string) ?? ""; + const { label, color, Icon } = outcomeMeta(outcome); + + return ( +
+
+
+ +
+
+ {surface || (structured?.entry_id ? `entry ${structured.entry_id as string}` : "(unnamed surface)")} + {riskArea && Β· {riskArea}} +
+
+ {previousOutcome && ( + {outcomeMeta(previousOutcome).label} β†’ + )} + {label} +
+ {evidence && ( +
{evidence}
+ )} +
+
+
+ ); +} diff --git a/strix/interface/viewer/frontend/src/components/live/tool-renderers/ThreatModelRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ThreatModelRenderer.tsx new file mode 100644 index 00000000..fa7e687d --- /dev/null +++ b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ThreatModelRenderer.tsx @@ -0,0 +1,138 @@ +"use client"; + +import type { ToolRendererProps } from "@/types/events"; +import { Crosshair, AlertTriangle, Plus, Save } from "lucide-react"; +import { TruncatedText } from "./ToolCard"; + +interface Amendment { + agent_name?: string; + content?: string; + recorded_at?: string; +} + +const ACTION_LABELS: Record = { + get_threat_model: { label: "Threat model", Icon: Crosshair }, + save_threat_model: { label: "Threat model saved", Icon: Save }, + amend_threat_model: { label: "Threat model amended", Icon: Plus }, +}; + +/** A git sha is noise past its first bytes, and "unversioned" is not a revision. */ +function shortRevision(revision: unknown): string { + const value = typeof revision === "string" ? revision.trim() : ""; + if (!value || value === "unversioned") return ""; + return value.slice(0, 8); +} + +export default function ThreatModelRenderer({ toolName, args, result }: ToolRendererProps) { + const action = ACTION_LABELS[toolName] ?? { label: "Threat model", Icon: Crosshair }; + const ActionIcon = action.Icon; + const target = (args.target as string) ?? ""; + const res = result as Record | string | null; + + const header = ( +
+ + {action.label} + {target && {target}} +
+ ); + + if (typeof res === "string" && res.trim()) { + return
{header}
{res.trim()}
; + } + + const structured = res && typeof res === "object" ? res : null; + + if (structured && !structured.success) { + return ( +
+ {header} +
+ {(structured.error as string) ?? "Threat model call failed"} +
+
+ ); + } + + if (toolName === "get_threat_model") { + if (structured && !structured.found) { + return ( +
+ {header} +
No model cached for this target yet
+
+ ); + } + const rawAmendments = structured?.amendments; + const amendments: Amendment[] = Array.isArray(rawAmendments) ? (rawAmendments as Amendment[]) : []; + const cachedRevision = shortRevision(structured?.cached_revision); + return ( +
+ {header} + {structured?.stale === true && ( +
+ + stale{cachedRevision ? ` β€” written at ${cachedRevision}` : ""} +
+ )} + {amendments.length > 0 && ( +
+ + {amendments.length} amendment{amendments.length === 1 ? "" : "s"} + + β€” later statements win +
+ {/* On a public share link the amendment body is stripped, so the + author line has to stand on its own. */} + {amendments.map((amendment, i) => ( +
+ {amendment.agent_name ?? "unknown agent"} + {amendment.content && ( + : {amendment.content} + )} +
+ ))} +
+
+ )} + {typeof structured?.content === "string" && structured.content.trim() && ( +
+ +
+ )} +
+ ); + } + + if (toolName === "amend_threat_model") { + const addendum = (args.addendum as string) ?? ""; + const count = structured?.amendment_count as number | undefined; + return ( +
+ {header} + {count != null && ( +
{count} amendment{count === 1 ? "" : "s"} on this model
+ )} + {addendum &&
} +
+ ); + } + + const cleared = (structured?.amendments_cleared as number | undefined) ?? 0; + const revision = shortRevision(structured?.revision); + const content = (args.content as string) ?? ""; + return ( +
+ {header} + {revision &&
at {revision}
} + {/* Saving folds amendments away β€” the one destructive thing this tool does. */} + {cleared > 0 && ( +
+ + cleared {cleared} amendment{cleared === 1 ? "" : "s"} +
+ )} + {content &&
} +
+ ); +} diff --git a/strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx index fa8a08ee..c556e1c7 100644 --- a/strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx +++ b/strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx @@ -11,6 +11,11 @@ const SEVERITY_COLORS: Record = { low: "text-blue-400", info: "text-cyan-400", }; +/** Anything below high is a claim the reader still has to check. */ +const CONFIDENCE_COLORS: Record = { + high: "text-emerald-400", medium: "text-yellow-400", low: "text-orange-400", +}; + export default function VulnReportRenderer({ args, result }: ToolRendererProps) { const title = (args.title as string) ?? ""; const description = (args.description as string) ?? ""; @@ -24,6 +29,11 @@ export default function VulnReportRenderer({ args, result }: ToolRendererProps) const remediation = (args.remediation_steps as string) ?? ""; const cve = (args.cve as string) ?? ""; const cwe = (args.cwe as string) ?? ""; + const counterevidence = (args.counterevidence as string) ?? ""; + const confidence = ((args.confidence as string) ?? "").toLowerCase(); + const confidenceRationale = (args.confidence_rationale as string) ?? ""; + const severityChangeConditions = (args.severity_change_conditions as string) ?? ""; + const fixVerification = (args.fix_verification as string) ?? ""; const res = result as Record | null; const rawSev = (res && typeof res === "object" ? res.severity : null) ?? args.severity ?? "medium"; @@ -38,6 +48,11 @@ export default function VulnReportRenderer({ args, result }: ToolRendererProps) {cvss != null && CVSS {cvss}} {cve && {cve}} {cwe && {cwe}} + {confidence && ( + + {confidence} confidence + + )} {title &&
{title}
} {(target || endpoint) && ( @@ -56,6 +71,23 @@ export default function VulnReportRenderer({ args, result }: ToolRendererProps)
)} + {confidenceRationale && ( +
{confidenceRationale}
+ )} + {/* The case against the finding sits beside the case for it: whoever + triages this needs both to decide whether to act. */} + {counterevidence && ( +
+ Counterevidence +
+
+ )} + {severityChangeConditions && ( +
+ Severity would change if +
+
+ )} {(pocDescription || pocCode) && (
Proof of Concept @@ -69,6 +101,14 @@ export default function VulnReportRenderer({ args, result }: ToolRendererProps)
)} + {/* An applyable fix is one click from the user's codebase, so how it was + verified belongs next to it. */} + {fixVerification && ( +
+ Fix verification +
+
+ )} ); } diff --git a/strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts b/strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts index 67f275fc..e2658aeb 100644 --- a/strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts +++ b/strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts @@ -3,7 +3,7 @@ import type { ToolRendererProps } from "@/types/events"; import { Terminal, Globe, FileText, ShieldAlert, ArrowUpRight, Brain, Bot, MessageCircle, Flag, Eye, Search, Code, StickyNote, - ListTodo, Crosshair, Wrench, Ban, Image, + ListTodo, Crosshair, Wrench, Ban, Image, ClipboardList, } from "lucide-react"; import TerminalRenderer from "./TerminalRenderer"; @@ -25,6 +25,8 @@ import TodoRenderer from "./TodoRenderer"; import FallbackRenderer from "./FallbackRenderer"; import LoadSkillRenderer from "./LoadSkillRenderer"; import RespondRenderer from "./RespondRenderer"; +import CoverageRenderer from "./CoverageRenderer"; +import ThreatModelRenderer from "./ThreatModelRenderer"; /** * Tool-renderer mapping β€” data-driven, keyed by the engine's tool *family*. @@ -53,6 +55,8 @@ export type ToolCategory = | "notes" | "skills" | "todos" + | "coverage" + | "threatModel" | "telemetry"; export interface ToolIconMeta { @@ -83,6 +87,8 @@ const CATEGORY_META: Record = { notes: { renderer: NotesRenderer, icon: StickyNote, color: "text-amber-400", match: /note/ }, skills: { renderer: LoadSkillRenderer, icon: Wrench, color: "text-emerald-400" }, todos: { renderer: TodoRenderer, icon: ListTodo, color: "text-purple-400", match: /todo/ }, + coverage: { renderer: CoverageRenderer, icon: ClipboardList, color: "text-cyan-400", match: /coverage/ }, + threatModel: { renderer: ThreatModelRenderer, icon: Crosshair, color: "text-blue-400", match: /threat_model/ }, telemetry: { renderer: FallbackRenderer, icon: Wrench, color: "text-[#555]" }, }; @@ -112,6 +118,10 @@ const CATEGORY_TOOLS: Record = { notes: ["create_note", "delete_note", "update_note", "list_notes", "get_note"], skills: ["load_skill"], todos: ["create_todo", "list_todos", "update_todo", "mark_todo_done", "mark_todo_pending", "delete_todo"], + // Shared coverage ledger β€” one row per surface Γ— risk area for the whole run + coverage: ["record_coverage", "update_coverage", "list_coverage"], + // Per-target threat model, shared across the agent tree + threatModel: ["get_threat_model", "save_threat_model", "amend_threat_model"], telemetry: ["sandbox_error_details", "llm_error_details"], }; diff --git a/strix/interface/viewer/static/assets/index-DBJ-RJqo.js b/strix/interface/viewer/static/assets/index-Bi_X6kI3.js similarity index 50% rename from strix/interface/viewer/static/assets/index-DBJ-RJqo.js rename to strix/interface/viewer/static/assets/index-Bi_X6kI3.js index ecdc0fcf..ae7a105f 100644 --- a/strix/interface/viewer/static/assets/index-DBJ-RJqo.js +++ b/strix/interface/viewer/static/assets/index-Bi_X6kI3.js @@ -1,4 +1,4 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))a(s);new MutationObserver(s=>{for(const o of s)if(o.type==="childList")for(const c of o.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&a(c)}).observe(document,{childList:!0,subtree:!0});function r(s){const o={};return s.integrity&&(o.integrity=s.integrity),s.referrerPolicy&&(o.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?o.credentials="include":s.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function a(s){if(s.ep)return;s.ep=!0;const o=r(s);fetch(s.href,o)}})();function Co(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var oh={exports:{}},Yl={};/** +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))a(s);new MutationObserver(s=>{for(const o of s)if(o.type==="childList")for(const c of o.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&a(c)}).observe(document,{childList:!0,subtree:!0});function r(s){const o={};return s.integrity&&(o.integrity=s.integrity),s.referrerPolicy&&(o.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?o.credentials="include":s.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function a(s){if(s.ep)return;s.ep=!0;const o=r(s);fetch(s.href,o)}})();function To(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var hh={exports:{}},Yl={};/** * @license React * react-jsx-runtime.production.js * @@ -6,7 +6,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var V0;function yk(){if(V0)return Yl;V0=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function r(a,s,o){var c=null;if(o!==void 0&&(c=""+o),s.key!==void 0&&(c=""+s.key),"key"in s){o={};for(var d in s)d!=="key"&&(o[d]=s[d])}else o=s;return s=o.ref,{$$typeof:e,type:a,key:c,ref:s!==void 0?s:null,props:o}}return Yl.Fragment=t,Yl.jsx=r,Yl.jsxs=r,Yl}var Y0;function vk(){return Y0||(Y0=1,oh.exports=yk()),oh.exports}var g=vk(),ch={exports:{}},Ve={};/** + */var Q0;function Ck(){if(Q0)return Yl;Q0=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function r(a,s,o){var c=null;if(o!==void 0&&(c=""+o),s.key!==void 0&&(c=""+s.key),"key"in s){o={};for(var d in s)d!=="key"&&(o[d]=s[d])}else o=s;return s=o.ref,{$$typeof:e,type:a,key:c,ref:s!==void 0?s:null,props:o}}return Yl.Fragment=t,Yl.jsx=r,Yl.jsxs=r,Yl}var W0;function Tk(){return W0||(W0=1,hh.exports=Ck()),hh.exports}var m=Tk(),mh={exports:{}},Ve={};/** * @license React * react.production.js * @@ -14,7 +14,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var X0;function _k(){if(X0)return Ve;X0=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),s=Symbol.for("react.profiler"),o=Symbol.for("react.consumer"),c=Symbol.for("react.context"),d=Symbol.for("react.forward_ref"),h=Symbol.for("react.suspense"),f=Symbol.for("react.memo"),m=Symbol.for("react.lazy"),p=Symbol.for("react.activity"),y=Symbol.iterator;function x(D){return D===null||typeof D!="object"?null:(D=y&&D[y]||D["@@iterator"],typeof D=="function"?D:null)}var _={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},N=Object.assign,S={};function w(D,Y,L){this.props=D,this.context=Y,this.refs=S,this.updater=L||_}w.prototype.isReactComponent={},w.prototype.setState=function(D,Y){if(typeof D!="object"&&typeof D!="function"&&D!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,D,Y,"setState")},w.prototype.forceUpdate=function(D){this.updater.enqueueForceUpdate(this,D,"forceUpdate")};function k(){}k.prototype=w.prototype;function E(D,Y,L){this.props=D,this.context=Y,this.refs=S,this.updater=L||_}var M=E.prototype=new k;M.constructor=E,N(M,w.prototype),M.isPureReactComponent=!0;var I=Array.isArray;function R(){}var U={H:null,A:null,T:null,S:null},B=Object.prototype.hasOwnProperty;function Z(D,Y,L){var G=L.ref;return{$$typeof:e,type:D,key:Y,ref:G!==void 0?G:null,props:L}}function j(D,Y){return Z(D.type,Y,D.props)}function z(D){return typeof D=="object"&&D!==null&&D.$$typeof===e}function V(D){var Y={"=":"=0",":":"=2"};return"$"+D.replace(/[=:]/g,function(L){return Y[L]})}var P=/\/+/g;function T(D,Y){return typeof D=="object"&&D!==null&&D.key!=null?V(""+D.key):Y.toString(36)}function $(D){switch(D.status){case"fulfilled":return D.value;case"rejected":throw D.reason;default:switch(typeof D.status=="string"?D.then(R,R):(D.status="pending",D.then(function(Y){D.status==="pending"&&(D.status="fulfilled",D.value=Y)},function(Y){D.status==="pending"&&(D.status="rejected",D.reason=Y)})),D.status){case"fulfilled":return D.value;case"rejected":throw D.reason}}throw D}function O(D,Y,L,G,q){var Q=typeof D;(Q==="undefined"||Q==="boolean")&&(D=null);var J=!1;if(D===null)J=!0;else switch(Q){case"bigint":case"string":case"number":J=!0;break;case"object":switch(D.$$typeof){case e:case t:J=!0;break;case m:return J=D._init,O(J(D._payload),Y,L,G,q)}}if(J)return q=q(D),J=G===""?"."+T(D,0):G,I(q)?(L="",J!=null&&(L=J.replace(P,"$&/")+"/"),O(q,Y,L,"",function(ce){return ce})):q!=null&&(z(q)&&(q=j(q,L+(q.key==null||D&&D.key===q.key?"":(""+q.key).replace(P,"$&/")+"/")+J)),Y.push(q)),1;J=0;var W=G===""?".":G+":";if(I(D))for(var te=0;te>>1,C=O[K];if(0>>1;Ks(L,X))Gs(q,L)?(O[K]=q,O[G]=X,K=G):(O[K]=L,O[Y]=X,K=Y);else if(Gs(q,X))O[K]=q,O[G]=X,K=G;else break e}}return H}function s(O,H){var X=O.sortIndex-H.sortIndex;return X!==0?X:O.id-H.id}if(e.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var c=Date,d=c.now();e.unstable_now=function(){return c.now()-d}}var h=[],f=[],m=1,p=null,y=3,x=!1,_=!1,N=!1,S=!1,w=typeof setTimeout=="function"?setTimeout:null,k=typeof clearTimeout=="function"?clearTimeout:null,E=typeof setImmediate<"u"?setImmediate:null;function M(O){for(var H=r(f);H!==null;){if(H.callback===null)a(f);else if(H.startTime<=O)a(f),H.sortIndex=H.expirationTime,t(h,H);else break;H=r(f)}}function I(O){if(N=!1,M(O),!_)if(r(h)!==null)_=!0,R||(R=!0,V());else{var H=r(f);H!==null&&$(I,H.startTime-O)}}var R=!1,U=-1,B=5,Z=-1;function j(){return S?!0:!(e.unstable_now()-ZO&&j());){var K=p.callback;if(typeof K=="function"){p.callback=null,y=p.priorityLevel;var C=K(p.expirationTime<=O);if(O=e.unstable_now(),typeof C=="function"){p.callback=C,M(O),H=!0;break t}p===r(h)&&a(h),M(O)}else a(h);p=r(h)}if(p!==null)H=!0;else{var D=r(f);D!==null&&$(I,D.startTime-O),H=!1}}break e}finally{p=null,y=X,x=!1}H=void 0}}finally{H?V():R=!1}}}var V;if(typeof E=="function")V=function(){E(z)};else if(typeof MessageChannel<"u"){var P=new MessageChannel,T=P.port2;P.port1.onmessage=z,V=function(){T.postMessage(null)}}else V=function(){w(z,0)};function $(O,H){U=w(function(){O(e.unstable_now())},H)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(O){O.callback=null},e.unstable_forceFrameRate=function(O){0>O||125K?(O.sortIndex=X,t(f,O),r(h)===null&&O===r(f)&&(N?(k(U),U=-1):N=!0,$(I,X-K))):(O.sortIndex=C,t(h,O),_||x||(_=!0,R||(R=!0,V()))),O},e.unstable_shouldYield=j,e.unstable_wrapCallback=function(O){var H=y;return function(){var X=y;y=H;try{return O.apply(this,arguments)}finally{y=X}}}})(fh)),fh}var Q0;function Ek(){return Q0||(Q0=1,dh.exports=wk()),dh.exports}var hh={exports:{}},Cn={};/** + */var ty;function Mk(){return ty||(ty=1,(function(e){function t(O,H){var X=O.length;O.push(H);e:for(;0>>1,C=O[K];if(0>>1;Ks(L,X))Gs(q,L)?(O[K]=q,O[G]=X,K=G):(O[K]=L,O[Y]=X,K=Y);else if(Gs(q,X))O[K]=q,O[G]=X,K=G;else break e}}return H}function s(O,H){var X=O.sortIndex-H.sortIndex;return X!==0?X:O.id-H.id}if(e.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var c=Date,d=c.now();e.unstable_now=function(){return c.now()-d}}var f=[],h=[],p=1,g=null,y=3,b=!1,_=!1,N=!1,S=!1,w=typeof setTimeout=="function"?setTimeout:null,k=typeof clearTimeout=="function"?clearTimeout:null,E=typeof setImmediate<"u"?setImmediate:null;function M(O){for(var H=r(h);H!==null;){if(H.callback===null)a(h);else if(H.startTime<=O)a(h),H.sortIndex=H.expirationTime,t(f,H);else break;H=r(h)}}function I(O){if(N=!1,M(O),!_)if(r(f)!==null)_=!0,R||(R=!0,V());else{var H=r(h);H!==null&&$(I,H.startTime-O)}}var R=!1,U=-1,B=5,Z=-1;function j(){return S?!0:!(e.unstable_now()-ZO&&j());){var K=g.callback;if(typeof K=="function"){g.callback=null,y=g.priorityLevel;var C=K(g.expirationTime<=O);if(O=e.unstable_now(),typeof C=="function"){g.callback=C,M(O),H=!0;break t}g===r(f)&&a(f),M(O)}else a(f);g=r(f)}if(g!==null)H=!0;else{var D=r(h);D!==null&&$(I,D.startTime-O),H=!1}}break e}finally{g=null,y=X,b=!1}H=void 0}}finally{H?V():R=!1}}}var V;if(typeof E=="function")V=function(){E(z)};else if(typeof MessageChannel<"u"){var P=new MessageChannel,T=P.port2;P.port1.onmessage=z,V=function(){T.postMessage(null)}}else V=function(){w(z,0)};function $(O,H){U=w(function(){O(e.unstable_now())},H)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(O){O.callback=null},e.unstable_forceFrameRate=function(O){0>O||125K?(O.sortIndex=X,t(h,O),r(f)===null&&O===r(h)&&(N?(k(U),U=-1):N=!0,$(I,X-K))):(O.sortIndex=C,t(f,O),_||b||(_=!0,R||(R=!0,V()))),O},e.unstable_shouldYield=j,e.unstable_wrapCallback=function(O){var H=y;return function(){var X=y;y=H;try{return O.apply(this,arguments)}finally{y=X}}}})(xh)),xh}var ny;function Ok(){return ny||(ny=1,gh.exports=Mk()),gh.exports}var bh={exports:{}},Tn={};/** * @license React * react-dom.production.js * @@ -30,7 +30,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var W0;function Nk(){if(W0)return Cn;W0=1;var e=To();function t(h){var f="https://react.dev/errors/"+h;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),hh.exports=Nk(),hh.exports}/** + */var ry;function Rk(){if(ry)return Tn;ry=1;var e=Ao();function t(f){var h="https://react.dev/errors/"+f;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),bh.exports=Rk(),bh.exports}/** * @license React * react-dom-client.production.js * @@ -38,407 +38,427 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var ey;function Sk(){if(ey)return Xl;ey=1;var e=Ek(),t=To(),r=k_();function a(n){var i="https://react.dev/errors/"+n;if(1C||(n.current=K[C],K[C]=null,C--)}function L(n,i){C++,K[C]=n.current,n.current=i}var G=D(null),q=D(null),Q=D(null),J=D(null);function W(n,i){switch(L(Q,i),L(q,n),L(G,null),i.nodeType){case 9:case 11:n=(n=i.documentElement)&&(n=n.namespaceURI)?p0(n):0;break;default:if(n=i.tagName,i=i.namespaceURI)i=p0(i),n=g0(i,n);else switch(n){case"svg":n=1;break;case"math":n=2;break;default:n=0}}Y(G),L(G,n)}function te(){Y(G),Y(q),Y(Q)}function ce(n){n.memoizedState!==null&&L(J,n);var i=G.current,l=g0(i,n.type);i!==l&&(L(q,n),L(G,l))}function fe(n){q.current===n&&(Y(G),Y(q)),J.current===n&&(Y(J),Pl._currentValue=X)}var be,we;function Ne(n){if(be===void 0)try{throw Error()}catch(l){var i=l.stack.trim().match(/\n( *(at )?)/);be=i&&i[1]||"",we=-1C||(n.current=K[C],K[C]=null,C--)}function L(n,i){C++,K[C]=n.current,n.current=i}var G=D(null),q=D(null),Q=D(null),J=D(null);function W(n,i){switch(L(Q,i),L(q,n),L(G,null),i.nodeType){case 9:case 11:n=(n=i.documentElement)&&(n=n.namespaceURI)?v0(n):0;break;default:if(n=i.tagName,i=i.namespaceURI)i=v0(i),n=_0(i,n);else switch(n){case"svg":n=1;break;case"math":n=2;break;default:n=0}}Y(G),L(G,n)}function te(){Y(G),Y(q),Y(Q)}function ce(n){n.memoizedState!==null&&L(J,n);var i=G.current,l=_0(i,n.type);i!==l&&(L(q,n),L(G,l))}function fe(n){q.current===n&&(Y(G),Y(q)),J.current===n&&(Y(J),Pl._currentValue=X)}var xe,we;function Ne(n){if(xe===void 0)try{throw Error()}catch(l){var i=l.stack.trim().match(/\n( *(at )?)/);xe=i&&i[1]||"",we=-1)":-1b||ne[u]!==le[b]){var he=` -`+ne[u].replace(" at new "," at ");return n.displayName&&he.includes("")&&(he=he.replace("",n.displayName)),he}while(1<=u&&0<=b);break}}}finally{De=!1,Error.prepareStackTrace=l}return(l=n?n.displayName||n.name:"")?Ne(l):""}function st(n,i){switch(n.tag){case 26:case 27:case 5:return Ne(n.type);case 16:return Ne("Lazy");case 13:return n.child!==i&&i!==null?Ne("Suspense Fallback"):Ne("Suspense");case 19:return Ne("SuspenseList");case 0:case 15:return $e(n.type,!1);case 11:return $e(n.type.render,!1);case 1:return $e(n.type,!0);case 31:return Ne("Activity");default:return""}}function Rt(n){try{var i="",l=null;do i+=st(n,l),l=n,n=n.return;while(n);return i}catch(u){return` +`);for(x=u=0;ux||ne[u]!==le[x]){var he=` +`+ne[u].replace(" at new "," at ");return n.displayName&&he.includes("")&&(he=he.replace("",n.displayName)),he}while(1<=u&&0<=x);break}}}finally{De=!1,Error.prepareStackTrace=l}return(l=n?n.displayName||n.name:"")?Ne(l):""}function st(n,i){switch(n.tag){case 26:case 27:case 5:return Ne(n.type);case 16:return Ne("Lazy");case 13:return n.child!==i&&i!==null?Ne("Suspense Fallback"):Ne("Suspense");case 19:return Ne("SuspenseList");case 0:case 15:return $e(n.type,!1);case 11:return $e(n.type.render,!1);case 1:return $e(n.type,!0);case 31:return Ne("Activity");default:return""}}function Rt(n){try{var i="",l=null;do i+=st(n,l),l=n,n=n.return;while(n);return i}catch(u){return` Error generating stack: `+u.message+` -`+u.stack}}var Yt=Object.prototype.hasOwnProperty,Pt=e.unstable_scheduleCallback,Xt=e.unstable_cancelCallback,Yn=e.unstable_shouldYield,En=e.unstable_requestPaint,ct=e.unstable_now,It=e.unstable_getCurrentPriorityLevel,ue=e.unstable_ImmediatePriority,xe=e.unstable_UserBlockingPriority,Oe=e.unstable_NormalPriority,Fe=e.unstable_LowPriority,Ze=e.unstable_IdlePriority,on=e.log,Nn=e.unstable_setDisableYieldValue,Kt=null,At=null;function Wt(n){if(typeof on=="function"&&Nn(n),At&&typeof At.setStrictMode=="function")try{At.setStrictMode(Kt,n)}catch{}}var ut=Math.clz32?Math.clz32:Ni,In=Math.log,cn=Math.LN2;function Ni(n){return n>>>=0,n===0?32:31-(In(n)/cn|0)|0}var nt=256,Xn=262144,On=4194304;function hn(n){var i=n&42;if(i!==0)return i;switch(n&-n){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return n&261888;case 262144:case 524288:case 1048576:case 2097152:return n&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return n&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return n}}function re(n,i,l){var u=n.pendingLanes;if(u===0)return 0;var b=0,v=n.suspendedLanes,A=n.pingedLanes;n=n.warmLanes;var F=u&134217727;return F!==0?(u=F&~v,u!==0?b=hn(u):(A&=F,A!==0?b=hn(A):l||(l=F&~n,l!==0&&(b=hn(l))))):(F=u&~v,F!==0?b=hn(F):A!==0?b=hn(A):l||(l=u&~n,l!==0&&(b=hn(l)))),b===0?0:i!==0&&i!==b&&(i&v)===0&&(v=b&-b,l=i&-i,v>=l||v===32&&(l&4194048)!==0)?i:b}function me(n,i){return(n.pendingLanes&~(n.suspendedLanes&~n.pingedLanes)&i)===0}function Ee(n,i){switch(n){case 1:case 2:case 4:case 8:case 64:return i+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return i+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Pe(){var n=On;return On<<=1,(On&62914560)===0&&(On=4194304),n}function St(n){for(var i=[],l=0;31>l;l++)i.push(n);return i}function gt(n,i){n.pendingLanes|=i,i!==268435456&&(n.suspendedLanes=0,n.pingedLanes=0,n.warmLanes=0)}function Ae(n,i,l,u,b,v){var A=n.pendingLanes;n.pendingLanes=l,n.suspendedLanes=0,n.pingedLanes=0,n.warmLanes=0,n.expiredLanes&=l,n.entangledLanes&=l,n.errorRecoveryDisabledLanes&=l,n.shellSuspendCounter=0;var F=n.entanglements,ne=n.expirationTimes,le=n.hiddenUpdates;for(l=A&~l;0"u")return null;try{return n.activeElement||n.body}catch{return n.body}}var rs=/[\n"\\]/g;function kn(n){return n.replace(rs,function(i){return"\\"+i.charCodeAt(0).toString(16)+" "})}function xa(n,i,l,u,b,v,A,F){n.name="",A!=null&&typeof A!="function"&&typeof A!="symbol"&&typeof A!="boolean"?n.type=A:n.removeAttribute("type"),i!=null?A==="number"?(i===0&&n.value===""||n.value!=i)&&(n.value=""+_t(i)):n.value!==""+_t(i)&&(n.value=""+_t(i)):A!=="submit"&&A!=="reset"||n.removeAttribute("value"),i!=null?Oi(n,A,_t(i)):l!=null?Oi(n,A,_t(l)):u!=null&&n.removeAttribute("value"),b==null&&v!=null&&(n.defaultChecked=!!v),b!=null&&(n.checked=b&&typeof b!="function"&&typeof b!="symbol"),F!=null&&typeof F!="function"&&typeof F!="symbol"&&typeof F!="boolean"?n.name=""+_t(F):n.removeAttribute("name")}function Er(n,i,l,u,b,v,A,F){if(v!=null&&typeof v!="function"&&typeof v!="symbol"&&typeof v!="boolean"&&(n.type=v),i!=null||l!=null){if(!(v!=="submit"&&v!=="reset"||i!=null)){Ai(n);return}l=l!=null?""+_t(l):"",i=i!=null?""+_t(i):l,F||i===n.value||(n.value=i),n.defaultValue=i}u=u??b,u=typeof u!="function"&&typeof u!="symbol"&&!!u,n.checked=F?n.checked:!!u,n.defaultChecked=!!u,A!=null&&typeof A!="function"&&typeof A!="symbol"&&typeof A!="boolean"&&(n.name=A),Ai(n)}function Oi(n,i,l){i==="number"&&Mi(n.ownerDocument)===n||n.defaultValue===""+l||(n.defaultValue=""+l)}function un(n,i,l,u){if(n=n.options,i){i={};for(var b=0;b"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ld=!1;if(ti)try{var ll={};Object.defineProperty(ll,"passive",{get:function(){ld=!0}}),window.addEventListener("test",ll,ll),window.removeEventListener("test",ll,ll)}catch{ld=!1}var Di=null,od=null,qo=null;function gg(){if(qo)return qo;var n,i=od,l=i.length,u,b="value"in Di?Di.value:Di.textContent,v=b.length;for(n=0;n=ul),wg=" ",Eg=!1;function Ng(n,i){switch(n){case"keyup":return $S.indexOf(i.keyCode)!==-1;case"keydown":return i.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Sg(n){return n=n.detail,typeof n=="object"&&"data"in n?n.data:null}var as=!1;function PS(n,i){switch(n){case"compositionend":return Sg(i);case"keypress":return i.which!==32?null:(Eg=!0,wg);case"textInput":return n=i.data,n===wg&&Eg?null:n;default:return null}}function FS(n,i){if(as)return n==="compositionend"||!hd&&Ng(n,i)?(n=gg(),qo=od=Di=null,as=!1,n):null;switch(n){case"paste":return null;case"keypress":if(!(i.ctrlKey||i.altKey||i.metaKey)||i.ctrlKey&&i.altKey){if(i.char&&1=i)return{node:l,offset:i-n};n=u}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=jg(l)}}function Lg(n,i){return n&&i?n===i?!0:n&&n.nodeType===3?!1:i&&i.nodeType===3?Lg(n,i.parentNode):"contains"in n?n.contains(i):n.compareDocumentPosition?!!(n.compareDocumentPosition(i)&16):!1:!1}function zg(n){n=n!=null&&n.ownerDocument!=null&&n.ownerDocument.defaultView!=null?n.ownerDocument.defaultView:window;for(var i=Mi(n.document);i instanceof n.HTMLIFrameElement;){try{var l=typeof i.contentWindow.location.href=="string"}catch{l=!1}if(l)n=i.contentWindow;else break;i=Mi(n.document)}return i}function gd(n){var i=n&&n.nodeName&&n.nodeName.toLowerCase();return i&&(i==="input"&&(n.type==="text"||n.type==="search"||n.type==="tel"||n.type==="url"||n.type==="password")||i==="textarea"||n.contentEditable==="true")}var WS=ti&&"documentMode"in document&&11>=document.documentMode,ss=null,bd=null,ml=null,xd=!1;function Ig(n,i,l){var u=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;xd||ss==null||ss!==Mi(u)||(u=ss,"selectionStart"in u&&gd(u)?u={start:u.selectionStart,end:u.selectionEnd}:(u=(u.ownerDocument&&u.ownerDocument.defaultView||window).getSelection(),u={anchorNode:u.anchorNode,anchorOffset:u.anchorOffset,focusNode:u.focusNode,focusOffset:u.focusOffset}),ml&&hl(ml,u)||(ml=u,u=Lc(bd,"onSelect"),0>=A,b-=A,Hr=1<<32-ut(i)+b|l<Ke?(at=je,je=null):at=je.sibling;var mt=oe(ae,je,se[Ke],pe);if(mt===null){je===null&&(je=at);break}n&&je&&mt.alternate===null&&i(ae,je),ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt,je=at}if(Ke===se.length)return l(ae,je),lt&&ri(ae,Ke),Ie;if(je===null){for(;KeKe?(at=je,je=null):at=je.sibling;var na=oe(ae,je,mt.value,pe);if(na===null){je===null&&(je=at);break}n&&je&&na.alternate===null&&i(ae,je),ie=v(na,ie,Ke),ht===null?Ie=na:ht.sibling=na,ht=na,je=at}if(mt.done)return l(ae,je),lt&&ri(ae,Ke),Ie;if(je===null){for(;!mt.done;Ke++,mt=se.next())mt=ge(ae,mt.value,pe),mt!==null&&(ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt);return lt&&ri(ae,Ke),Ie}for(je=u(je);!mt.done;Ke++,mt=se.next())mt=de(je,ae,Ke,mt.value,pe),mt!==null&&(n&&mt.alternate!==null&&je.delete(mt.key===null?Ke:mt.key),ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt);return n&&je.forEach(function(xk){return i(ae,xk)}),lt&&ri(ae,Ke),Ie}function Nt(ae,ie,se,pe){if(typeof se=="object"&&se!==null&&se.type===N&&se.key===null&&(se=se.props.children),typeof se=="object"&&se!==null){switch(se.$$typeof){case x:e:{for(var Ie=se.key;ie!==null;){if(ie.key===Ie){if(Ie=se.type,Ie===N){if(ie.tag===7){l(ae,ie.sibling),pe=b(ie,se.props.children),pe.return=ae,ae=pe;break e}}else if(ie.elementType===Ie||typeof Ie=="object"&&Ie!==null&&Ie.$$typeof===B&&Aa(Ie)===ie.type){l(ae,ie.sibling),pe=b(ie,se.props),vl(pe,se),pe.return=ae,ae=pe;break e}l(ae,ie);break}else i(ae,ie);ie=ie.sibling}se.type===N?(pe=Na(se.props.children,ae.mode,pe,se.key),pe.return=ae,ae=pe):(pe=Wo(se.type,se.key,se.props,null,ae.mode,pe),vl(pe,se),pe.return=ae,ae=pe)}return A(ae);case _:e:{for(Ie=se.key;ie!==null;){if(ie.key===Ie)if(ie.tag===4&&ie.stateNode.containerInfo===se.containerInfo&&ie.stateNode.implementation===se.implementation){l(ae,ie.sibling),pe=b(ie,se.children||[]),pe.return=ae,ae=pe;break e}else{l(ae,ie);break}else i(ae,ie);ie=ie.sibling}pe=Sd(se,ae.mode,pe),pe.return=ae,ae=pe}return A(ae);case B:return se=Aa(se),Nt(ae,ie,se,pe)}if($(se))return Te(ae,ie,se,pe);if(V(se)){if(Ie=V(se),typeof Ie!="function")throw Error(a(150));return se=Ie.call(se),He(ae,ie,se,pe)}if(typeof se.then=="function")return Nt(ae,ie,ac(se),pe);if(se.$$typeof===E)return Nt(ae,ie,tc(ae,se),pe);sc(ae,se)}return typeof se=="string"&&se!==""||typeof se=="number"||typeof se=="bigint"?(se=""+se,ie!==null&&ie.tag===6?(l(ae,ie.sibling),pe=b(ie,se),pe.return=ae,ae=pe):(l(ae,ie),pe=Nd(se,ae.mode,pe),pe.return=ae,ae=pe),A(ae)):l(ae,ie)}return function(ae,ie,se,pe){try{yl=0;var Ie=Nt(ae,ie,se,pe);return bs=null,Ie}catch(je){if(je===gs||je===rc)throw je;var ht=Zn(29,je,null,ae.mode);return ht.lanes=pe,ht.return=ae,ht}finally{}}}var Oa=sb(!0),lb=sb(!1),Ui=!1;function Id(n){n.updateQueue={baseState:n.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Bd(n,i){n=n.updateQueue,i.updateQueue===n&&(i.updateQueue={baseState:n.baseState,firstBaseUpdate:n.firstBaseUpdate,lastBaseUpdate:n.lastBaseUpdate,shared:n.shared,callbacks:null})}function Hi(n){return{lane:n,tag:0,payload:null,callback:null,next:null}}function $i(n,i,l){var u=n.updateQueue;if(u===null)return null;if(u=u.shared,(pt&2)!==0){var b=u.pending;return b===null?i.next=i:(i.next=b.next,b.next=i),u.pending=i,i=Qo(n),Fg(n,null,l),i}return Zo(n,u,i,l),Qo(n)}function _l(n,i,l){if(i=i.updateQueue,i!==null&&(i=i.shared,(l&4194048)!==0)){var u=i.lanes;u&=n.pendingLanes,l|=u,i.lanes=l,Ue(n,l)}}function Ud(n,i){var l=n.updateQueue,u=n.alternate;if(u!==null&&(u=u.updateQueue,l===u)){var b=null,v=null;if(l=l.firstBaseUpdate,l!==null){do{var A={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};v===null?b=v=A:v=v.next=A,l=l.next}while(l!==null);v===null?b=v=i:v=v.next=i}else b=v=i;l={baseState:u.baseState,firstBaseUpdate:b,lastBaseUpdate:v,shared:u.shared,callbacks:u.callbacks},n.updateQueue=l;return}n=l.lastBaseUpdate,n===null?l.firstBaseUpdate=i:n.next=i,l.lastBaseUpdate=i}var Hd=!1;function wl(){if(Hd){var n=ps;if(n!==null)throw n}}function El(n,i,l,u){Hd=!1;var b=n.updateQueue;Ui=!1;var v=b.firstBaseUpdate,A=b.lastBaseUpdate,F=b.shared.pending;if(F!==null){b.shared.pending=null;var ne=F,le=ne.next;ne.next=null,A===null?v=le:A.next=le,A=ne;var he=n.alternate;he!==null&&(he=he.updateQueue,F=he.lastBaseUpdate,F!==A&&(F===null?he.firstBaseUpdate=le:F.next=le,he.lastBaseUpdate=ne))}if(v!==null){var ge=b.baseState;A=0,he=le=ne=null,F=v;do{var oe=F.lane&-536870913,de=oe!==F.lane;if(de?(it&oe)===oe:(u&oe)===oe){oe!==0&&oe===ms&&(Hd=!0),he!==null&&(he=he.next={lane:0,tag:F.tag,payload:F.payload,callback:null,next:null});e:{var Te=n,He=F;oe=i;var Nt=l;switch(He.tag){case 1:if(Te=He.payload,typeof Te=="function"){ge=Te.call(Nt,ge,oe);break e}ge=Te;break e;case 3:Te.flags=Te.flags&-65537|128;case 0:if(Te=He.payload,oe=typeof Te=="function"?Te.call(Nt,ge,oe):Te,oe==null)break e;ge=p({},ge,oe);break e;case 2:Ui=!0}}oe=F.callback,oe!==null&&(n.flags|=64,de&&(n.flags|=8192),de=b.callbacks,de===null?b.callbacks=[oe]:de.push(oe))}else de={lane:oe,tag:F.tag,payload:F.payload,callback:F.callback,next:null},he===null?(le=he=de,ne=ge):he=he.next=de,A|=oe;if(F=F.next,F===null){if(F=b.shared.pending,F===null)break;de=F,F=de.next,de.next=null,b.lastBaseUpdate=de,b.shared.pending=null}}while(!0);he===null&&(ne=ge),b.baseState=ne,b.firstBaseUpdate=le,b.lastBaseUpdate=he,v===null&&(b.shared.lanes=0),Vi|=A,n.lanes=A,n.memoizedState=ge}}function ob(n,i){if(typeof n!="function")throw Error(a(191,n));n.call(i)}function cb(n,i){var l=n.callbacks;if(l!==null)for(n.callbacks=null,n=0;nv?v:8;var A=O.T,F={};O.T=F,sf(n,!1,i,l);try{var ne=b(),le=O.S;if(le!==null&&le(F,ne),ne!==null&&typeof ne=="object"&&typeof ne.then=="function"){var he=l2(ne,u);kl(n,i,he,tr(n))}else kl(n,i,u,tr(n))}catch(ge){kl(n,i,{then:function(){},status:"rejected",reason:ge},tr())}finally{H.p=v,A!==null&&F.types!==null&&(A.types=F.types),O.T=A}}function h2(){}function rf(n,i,l,u){if(n.tag!==5)throw Error(a(476));var b=$b(n).queue;Hb(n,b,i,X,l===null?h2:function(){return qb(n),l(u)})}function $b(n){var i=n.memoizedState;if(i!==null)return i;i={memoizedState:X,baseState:X,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:li,lastRenderedState:X},next:null};var l={};return i.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:li,lastRenderedState:l},next:null},n.memoizedState=i,n=n.alternate,n!==null&&(n.memoizedState=i),i}function qb(n){var i=$b(n);i.next===null&&(i=n.alternate.memoizedState),kl(n,i.next.queue,{},tr())}function af(){return yn(Pl)}function Pb(){return Qt().memoizedState}function Fb(){return Qt().memoizedState}function m2(n){for(var i=n.return;i!==null;){switch(i.tag){case 24:case 3:var l=tr();n=Hi(l);var u=$i(i,n,l);u!==null&&(Pn(u,i,l),_l(u,i,l)),i={cache:jd()},n.payload=i;return}i=i.return}}function p2(n,i,l){var u=tr();l={lane:u,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},gc(n)?Vb(i,l):(l=wd(n,i,l,u),l!==null&&(Pn(l,n,u),Yb(l,i,u)))}function Gb(n,i,l){var u=tr();kl(n,i,l,u)}function kl(n,i,l,u){var b={lane:u,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(gc(n))Vb(i,b);else{var v=n.alternate;if(n.lanes===0&&(v===null||v.lanes===0)&&(v=i.lastRenderedReducer,v!==null))try{var A=i.lastRenderedState,F=v(A,l);if(b.hasEagerState=!0,b.eagerState=F,Kn(F,A))return Zo(n,i,b,0),kt===null&&Ko(),!1}catch{}finally{}if(l=wd(n,i,b,u),l!==null)return Pn(l,n,u),Yb(l,i,u),!0}return!1}function sf(n,i,l,u){if(u={lane:2,revertLane:Bf(),gesture:null,action:u,hasEagerState:!1,eagerState:null,next:null},gc(n)){if(i)throw Error(a(479))}else i=wd(n,l,u,2),i!==null&&Pn(i,n,2)}function gc(n){var i=n.alternate;return n===Xe||i!==null&&i===Xe}function Vb(n,i){ys=cc=!0;var l=n.pending;l===null?i.next=i:(i.next=l.next,l.next=i),n.pending=i}function Yb(n,i,l){if((l&4194048)!==0){var u=i.lanes;u&=n.pendingLanes,l|=u,i.lanes=l,Ue(n,l)}}var Cl={readContext:yn,use:fc,useCallback:Gt,useContext:Gt,useEffect:Gt,useImperativeHandle:Gt,useLayoutEffect:Gt,useInsertionEffect:Gt,useMemo:Gt,useReducer:Gt,useRef:Gt,useState:Gt,useDebugValue:Gt,useDeferredValue:Gt,useTransition:Gt,useSyncExternalStore:Gt,useId:Gt,useHostTransitionStatus:Gt,useFormState:Gt,useActionState:Gt,useOptimistic:Gt,useMemoCache:Gt,useCacheRefresh:Gt};Cl.useEffectEvent=Gt;var Xb={readContext:yn,use:fc,useCallback:function(n,i){return Dn().memoizedState=[n,i===void 0?null:i],n},useContext:yn,useEffect:Ob,useImperativeHandle:function(n,i,l){l=l!=null?l.concat([n]):null,mc(4194308,4,Lb.bind(null,i,n),l)},useLayoutEffect:function(n,i){return mc(4194308,4,n,i)},useInsertionEffect:function(n,i){mc(4,2,n,i)},useMemo:function(n,i){var l=Dn();i=i===void 0?null:i;var u=n();if(Ra){Wt(!0);try{n()}finally{Wt(!1)}}return l.memoizedState=[u,i],u},useReducer:function(n,i,l){var u=Dn();if(l!==void 0){var b=l(i);if(Ra){Wt(!0);try{l(i)}finally{Wt(!1)}}}else b=i;return u.memoizedState=u.baseState=b,n={pending:null,lanes:0,dispatch:null,lastRenderedReducer:n,lastRenderedState:b},u.queue=n,n=n.dispatch=p2.bind(null,Xe,n),[u.memoizedState,n]},useRef:function(n){var i=Dn();return n={current:n},i.memoizedState=n},useState:function(n){n=Wd(n);var i=n.queue,l=Gb.bind(null,Xe,i);return i.dispatch=l,[n.memoizedState,l]},useDebugValue:tf,useDeferredValue:function(n,i){var l=Dn();return nf(l,n,i)},useTransition:function(){var n=Wd(!1);return n=Hb.bind(null,Xe,n.queue,!0,!1),Dn().memoizedState=n,[!1,n]},useSyncExternalStore:function(n,i,l){var u=Xe,b=Dn();if(lt){if(l===void 0)throw Error(a(407));l=l()}else{if(l=i(),kt===null)throw Error(a(349));(it&127)!==0||pb(u,i,l)}b.memoizedState=l;var v={value:l,getSnapshot:i};return b.queue=v,Ob(bb.bind(null,u,v,n),[n]),u.flags|=2048,_s(9,{destroy:void 0},gb.bind(null,u,v,l,i),null),l},useId:function(){var n=Dn(),i=kt.identifierPrefix;if(lt){var l=$r,u=Hr;l=(u&~(1<<32-ut(u)-1)).toString(32)+l,i="_"+i+"R_"+l,l=uc++,0<\/script>",v=v.removeChild(v.firstChild);break;case"select":v=typeof u.is=="string"?A.createElement("select",{is:u.is}):A.createElement("select"),u.multiple?v.multiple=!0:u.size&&(v.size=u.size);break;default:v=typeof u.is=="string"?A.createElement(b,{is:u.is}):A.createElement(b)}}v[Ut]=i,v[mn]=u;e:for(A=i.child;A!==null;){if(A.tag===5||A.tag===6)v.appendChild(A.stateNode);else if(A.tag!==4&&A.tag!==27&&A.child!==null){A.child.return=A,A=A.child;continue}if(A===i)break e;for(;A.sibling===null;){if(A.return===null||A.return===i)break e;A=A.return}A.sibling.return=A.return,A=A.sibling}i.stateNode=v;e:switch(_n(v,b,u),b){case"button":case"input":case"select":case"textarea":u=!!u.autoFocus;break e;case"img":u=!0;break e;default:u=!1}u&&ci(i)}}return Dt(i),vf(i,i.type,n===null?null:n.memoizedProps,i.pendingProps,l),null;case 6:if(n&&i.stateNode!=null)n.memoizedProps!==u&&ci(i);else{if(typeof u!="string"&&i.stateNode===null)throw Error(a(166));if(n=Q.current,fs(i)){if(n=i.stateNode,l=i.memoizedProps,u=null,b=xn,b!==null)switch(b.tag){case 27:case 5:u=b.memoizedProps}n[Ut]=i,n=!!(n.nodeValue===l||u!==null&&u.suppressHydrationWarning===!0||h0(n.nodeValue,l)),n||Ii(i,!0)}else n=zc(n).createTextNode(u),n[Ut]=i,i.stateNode=n}return Dt(i),null;case 31:if(l=i.memoizedState,n===null||n.memoizedState!==null){if(u=fs(i),l!==null){if(n===null){if(!u)throw Error(a(318));if(n=i.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(a(557));n[Ut]=i}else Sa(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Dt(i),n=!1}else l=Ad(),n!==null&&n.memoizedState!==null&&(n.memoizedState.hydrationErrors=l),n=!0;if(!n)return i.flags&256?(Wn(i),i):(Wn(i),null);if((i.flags&128)!==0)throw Error(a(558))}return Dt(i),null;case 13:if(u=i.memoizedState,n===null||n.memoizedState!==null&&n.memoizedState.dehydrated!==null){if(b=fs(i),u!==null&&u.dehydrated!==null){if(n===null){if(!b)throw Error(a(318));if(b=i.memoizedState,b=b!==null?b.dehydrated:null,!b)throw Error(a(317));b[Ut]=i}else Sa(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Dt(i),b=!1}else b=Ad(),n!==null&&n.memoizedState!==null&&(n.memoizedState.hydrationErrors=b),b=!0;if(!b)return i.flags&256?(Wn(i),i):(Wn(i),null)}return Wn(i),(i.flags&128)!==0?(i.lanes=l,i):(l=u!==null,n=n!==null&&n.memoizedState!==null,l&&(u=i.child,b=null,u.alternate!==null&&u.alternate.memoizedState!==null&&u.alternate.memoizedState.cachePool!==null&&(b=u.alternate.memoizedState.cachePool.pool),v=null,u.memoizedState!==null&&u.memoizedState.cachePool!==null&&(v=u.memoizedState.cachePool.pool),v!==b&&(u.flags|=2048)),l!==n&&l&&(i.child.flags|=8192),_c(i,i.updateQueue),Dt(i),null);case 4:return te(),n===null&&qf(i.stateNode.containerInfo),Dt(i),null;case 10:return ai(i.type),Dt(i),null;case 19:if(Y(Zt),u=i.memoizedState,u===null)return Dt(i),null;if(b=(i.flags&128)!==0,v=u.rendering,v===null)if(b)Al(u,!1);else{if(Vt!==0||n!==null&&(n.flags&128)!==0)for(n=i.child;n!==null;){if(v=oc(n),v!==null){for(i.flags|=128,Al(u,!1),n=v.updateQueue,i.updateQueue=n,_c(i,n),i.subtreeFlags=0,n=l,l=i.child;l!==null;)Gg(l,n),l=l.sibling;return L(Zt,Zt.current&1|2),lt&&ri(i,u.treeForkCount),i.child}n=n.sibling}u.tail!==null&&ct()>kc&&(i.flags|=128,b=!0,Al(u,!1),i.lanes=4194304)}else{if(!b)if(n=oc(v),n!==null){if(i.flags|=128,b=!0,n=n.updateQueue,i.updateQueue=n,_c(i,n),Al(u,!0),u.tail===null&&u.tailMode==="hidden"&&!v.alternate&&!lt)return Dt(i),null}else 2*ct()-u.renderingStartTime>kc&&l!==536870912&&(i.flags|=128,b=!0,Al(u,!1),i.lanes=4194304);u.isBackwards?(v.sibling=i.child,i.child=v):(n=u.last,n!==null?n.sibling=v:i.child=v,u.last=v)}return u.tail!==null?(n=u.tail,u.rendering=n,u.tail=n.sibling,u.renderingStartTime=ct(),n.sibling=null,l=Zt.current,L(Zt,b?l&1|2:l&1),lt&&ri(i,u.treeForkCount),n):(Dt(i),null);case 22:case 23:return Wn(i),qd(),u=i.memoizedState!==null,n!==null?n.memoizedState!==null!==u&&(i.flags|=8192):u&&(i.flags|=8192),u?(l&536870912)!==0&&(i.flags&128)===0&&(Dt(i),i.subtreeFlags&6&&(i.flags|=8192)):Dt(i),l=i.updateQueue,l!==null&&_c(i,l.retryQueue),l=null,n!==null&&n.memoizedState!==null&&n.memoizedState.cachePool!==null&&(l=n.memoizedState.cachePool.pool),u=null,i.memoizedState!==null&&i.memoizedState.cachePool!==null&&(u=i.memoizedState.cachePool.pool),u!==l&&(i.flags|=2048),n!==null&&Y(Ta),null;case 24:return l=null,n!==null&&(l=n.memoizedState.cache),i.memoizedState.cache!==l&&(i.flags|=2048),ai(en),Dt(i),null;case 25:return null;case 30:return null}throw Error(a(156,i.tag))}function v2(n,i){switch(Cd(i),i.tag){case 1:return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 3:return ai(en),te(),n=i.flags,(n&65536)!==0&&(n&128)===0?(i.flags=n&-65537|128,i):null;case 26:case 27:case 5:return fe(i),null;case 31:if(i.memoizedState!==null){if(Wn(i),i.alternate===null)throw Error(a(340));Sa()}return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 13:if(Wn(i),n=i.memoizedState,n!==null&&n.dehydrated!==null){if(i.alternate===null)throw Error(a(340));Sa()}return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 19:return Y(Zt),null;case 4:return te(),null;case 10:return ai(i.type),null;case 22:case 23:return Wn(i),qd(),n!==null&&Y(Ta),n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 24:return ai(en),null;case 25:return null;default:return null}}function xx(n,i){switch(Cd(i),i.tag){case 3:ai(en),te();break;case 26:case 27:case 5:fe(i);break;case 4:te();break;case 31:i.memoizedState!==null&&Wn(i);break;case 13:Wn(i);break;case 19:Y(Zt);break;case 10:ai(i.type);break;case 22:case 23:Wn(i),qd(),n!==null&&Y(Ta);break;case 24:ai(en)}}function Ml(n,i){try{var l=i.updateQueue,u=l!==null?l.lastEffect:null;if(u!==null){var b=u.next;l=b;do{if((l.tag&n)===n){u=void 0;var v=l.create,A=l.inst;u=v(),A.destroy=u}l=l.next}while(l!==b)}}catch(F){yt(i,i.return,F)}}function Fi(n,i,l){try{var u=i.updateQueue,b=u!==null?u.lastEffect:null;if(b!==null){var v=b.next;u=v;do{if((u.tag&n)===n){var A=u.inst,F=A.destroy;if(F!==void 0){A.destroy=void 0,b=i;var ne=l,le=F;try{le()}catch(he){yt(b,ne,he)}}}u=u.next}while(u!==v)}}catch(he){yt(i,i.return,he)}}function yx(n){var i=n.updateQueue;if(i!==null){var l=n.stateNode;try{cb(i,l)}catch(u){yt(n,n.return,u)}}}function vx(n,i,l){l.props=ja(n.type,n.memoizedProps),l.state=n.memoizedState;try{l.componentWillUnmount()}catch(u){yt(n,i,u)}}function Ol(n,i){try{var l=n.ref;if(l!==null){switch(n.tag){case 26:case 27:case 5:var u=n.stateNode;break;case 30:u=n.stateNode;break;default:u=n.stateNode}typeof l=="function"?n.refCleanup=l(u):l.current=u}}catch(b){yt(n,i,b)}}function qr(n,i){var l=n.ref,u=n.refCleanup;if(l!==null)if(typeof u=="function")try{u()}catch(b){yt(n,i,b)}finally{n.refCleanup=null,n=n.alternate,n!=null&&(n.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(b){yt(n,i,b)}else l.current=null}function _x(n){var i=n.type,l=n.memoizedProps,u=n.stateNode;try{e:switch(i){case"button":case"input":case"select":case"textarea":l.autoFocus&&u.focus();break e;case"img":l.src?u.src=l.src:l.srcSet&&(u.srcset=l.srcSet)}}catch(b){yt(n,n.return,b)}}function _f(n,i,l){try{var u=n.stateNode;q2(u,n.type,l,i),u[mn]=i}catch(b){yt(n,n.return,b)}}function wx(n){return n.tag===5||n.tag===3||n.tag===26||n.tag===27&&Qi(n.type)||n.tag===4}function wf(n){e:for(;;){for(;n.sibling===null;){if(n.return===null||wx(n.return))return null;n=n.return}for(n.sibling.return=n.return,n=n.sibling;n.tag!==5&&n.tag!==6&&n.tag!==18;){if(n.tag===27&&Qi(n.type)||n.flags&2||n.child===null||n.tag===4)continue e;n.child.return=n,n=n.child}if(!(n.flags&2))return n.stateNode}}function Ef(n,i,l){var u=n.tag;if(u===5||u===6)n=n.stateNode,i?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(n,i):(i=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,i.appendChild(n),l=l._reactRootContainer,l!=null||i.onclick!==null||(i.onclick=_e));else if(u!==4&&(u===27&&Qi(n.type)&&(l=n.stateNode,i=null),n=n.child,n!==null))for(Ef(n,i,l),n=n.sibling;n!==null;)Ef(n,i,l),n=n.sibling}function wc(n,i,l){var u=n.tag;if(u===5||u===6)n=n.stateNode,i?l.insertBefore(n,i):l.appendChild(n);else if(u!==4&&(u===27&&Qi(n.type)&&(l=n.stateNode),n=n.child,n!==null))for(wc(n,i,l),n=n.sibling;n!==null;)wc(n,i,l),n=n.sibling}function Ex(n){var i=n.stateNode,l=n.memoizedProps;try{for(var u=n.type,b=i.attributes;b.length;)i.removeAttributeNode(b[0]);_n(i,u,l),i[Ut]=n,i[mn]=l}catch(v){yt(n,n.return,v)}}var ui=!1,rn=!1,Nf=!1,Nx=typeof WeakSet=="function"?WeakSet:Set,gn=null;function _2(n,i){if(n=n.containerInfo,Gf=Pc,n=zg(n),gd(n)){if("selectionStart"in n)var l={start:n.selectionStart,end:n.selectionEnd};else e:{l=(l=n.ownerDocument)&&l.defaultView||window;var u=l.getSelection&&l.getSelection();if(u&&u.rangeCount!==0){l=u.anchorNode;var b=u.anchorOffset,v=u.focusNode;u=u.focusOffset;try{l.nodeType,v.nodeType}catch{l=null;break e}var A=0,F=-1,ne=-1,le=0,he=0,ge=n,oe=null;t:for(;;){for(var de;ge!==l||b!==0&&ge.nodeType!==3||(F=A+b),ge!==v||u!==0&&ge.nodeType!==3||(ne=A+u),ge.nodeType===3&&(A+=ge.nodeValue.length),(de=ge.firstChild)!==null;)oe=ge,ge=de;for(;;){if(ge===n)break t;if(oe===l&&++le===b&&(F=A),oe===v&&++he===u&&(ne=A),(de=ge.nextSibling)!==null)break;ge=oe,oe=ge.parentNode}ge=de}l=F===-1||ne===-1?null:{start:F,end:ne}}else l=null}l=l||{start:0,end:0}}else l=null;for(Vf={focusedElem:n,selectionRange:l},Pc=!1,gn=i;gn!==null;)if(i=gn,n=i.child,(i.subtreeFlags&1028)!==0&&n!==null)n.return=i,gn=n;else for(;gn!==null;){switch(i=gn,v=i.alternate,n=i.flags,i.tag){case 0:if((n&4)!==0&&(n=i.updateQueue,n=n!==null?n.events:null,n!==null))for(l=0;l title"))),_n(v,u,l),v[Ut]=n,Ft(v),u=v;break e;case"link":var A=M0("link","href",b).get(u+(l.href||""));if(A){for(var F=0;FNt&&(A=Nt,Nt=He,He=A);var ae=Dg(F,He),ie=Dg(F,Nt);if(ae&&ie&&(de.rangeCount!==1||de.anchorNode!==ae.node||de.anchorOffset!==ae.offset||de.focusNode!==ie.node||de.focusOffset!==ie.offset)){var se=ge.createRange();se.setStart(ae.node,ae.offset),de.removeAllRanges(),He>Nt?(de.addRange(se),de.extend(ie.node,ie.offset)):(se.setEnd(ie.node,ie.offset),de.addRange(se))}}}}for(ge=[],de=F;de=de.parentNode;)de.nodeType===1&&ge.push({element:de,left:de.scrollLeft,top:de.scrollTop});for(typeof F.focus=="function"&&F.focus(),F=0;Fl?32:l,O.T=null,l=Of,Of=null;var v=Xi,A=pi;if(dn=0,ks=Xi=null,pi=0,(pt&6)!==0)throw Error(a(331));var F=pt;if(pt|=4,Lx(v.current),Rx(v,v.current,A,l),pt=F,Il(0,!1),At&&typeof At.onPostCommitFiberRoot=="function")try{At.onPostCommitFiberRoot(Kt,v)}catch{}return!0}finally{H.p=b,O.T=u,Jx(n,i)}}function t0(n,i,l){i=ur(l,i),i=uf(n.stateNode,i,2),n=$i(n,i,2),n!==null&&(gt(n,2),Pr(n))}function yt(n,i,l){if(n.tag===3)t0(n,n,l);else for(;i!==null;){if(i.tag===3){t0(i,n,l);break}else if(i.tag===1){var u=i.stateNode;if(typeof i.type.getDerivedStateFromError=="function"||typeof u.componentDidCatch=="function"&&(Yi===null||!Yi.has(u))){n=ur(l,n),l=nx(2),u=$i(i,l,2),u!==null&&(rx(l,u,i,n),gt(u,2),Pr(u));break}}i=i.return}}function Lf(n,i,l){var u=n.pingCache;if(u===null){u=n.pingCache=new N2;var b=new Set;u.set(i,b)}else b=u.get(i),b===void 0&&(b=new Set,u.set(i,b));b.has(l)||(Cf=!0,b.add(l),n=A2.bind(null,n,i,l),i.then(n,n))}function A2(n,i,l){var u=n.pingCache;u!==null&&u.delete(i),n.pingedLanes|=n.suspendedLanes&l,n.warmLanes&=~l,kt===n&&(it&l)===l&&(Vt===4||Vt===3&&(it&62914560)===it&&300>ct()-Sc?(pt&2)===0&&Cs(n,0):Tf|=l,Ss===it&&(Ss=0)),Pr(n)}function n0(n,i){i===0&&(i=Pe()),n=Ea(n,i),n!==null&&(gt(n,i),Pr(n))}function M2(n){var i=n.memoizedState,l=0;i!==null&&(l=i.retryLane),n0(n,l)}function O2(n,i){var l=0;switch(n.tag){case 31:case 13:var u=n.stateNode,b=n.memoizedState;b!==null&&(l=b.retryLane);break;case 19:u=n.stateNode;break;case 22:u=n.stateNode._retryCache;break;default:throw Error(a(314))}u!==null&&u.delete(i),n0(n,l)}function R2(n,i){return Pt(n,i)}var Rc=null,As=null,zf=!1,jc=!1,If=!1,Zi=0;function Pr(n){n!==As&&n.next===null&&(As===null?Rc=As=n:As=As.next=n),jc=!0,zf||(zf=!0,D2())}function Il(n,i){if(!If&&jc){If=!0;do for(var l=!1,u=Rc;u!==null;){if(n!==0){var b=u.pendingLanes;if(b===0)var v=0;else{var A=u.suspendedLanes,F=u.pingedLanes;v=(1<<31-ut(42|n)+1)-1,v&=b&~(A&~F),v=v&201326741?v&201326741|1:v?v|2:0}v!==0&&(l=!0,s0(u,v))}else v=it,v=re(u,u===kt?v:0,u.cancelPendingCommit!==null||u.timeoutHandle!==-1),(v&3)===0||me(u,v)||(l=!0,s0(u,v));u=u.next}while(l);If=!1}}function j2(){r0()}function r0(){jc=zf=!1;var n=0;Zi!==0&&F2()&&(n=Zi);for(var i=ct(),l=null,u=Rc;u!==null;){var b=u.next,v=i0(u,i);v===0?(u.next=null,l===null?Rc=b:l.next=b,b===null&&(As=l)):(l=u,(n!==0||(v&3)!==0)&&(jc=!0)),u=b}dn!==0&&dn!==5||Il(n),Zi!==0&&(Zi=0)}function i0(n,i){for(var l=n.suspendedLanes,u=n.pingedLanes,b=n.expirationTimes,v=n.pendingLanes&-62914561;0F)break;var he=ne.transferSize,ge=ne.initiatorType;he&&m0(ge)&&(ne=ne.responseEnd,A+=he*(ne"u"?null:document;function k0(n,i,l){var u=Ms;if(u&&typeof i=="string"&&i){var b=kn(i);b='link[rel="'+n+'"][href="'+b+'"]',typeof l=="string"&&(b+='[crossorigin="'+l+'"]'),S0.has(b)||(S0.add(b),n={rel:n,crossOrigin:l,href:i},u.querySelector(b)===null&&(i=u.createElement("link"),_n(i,"link",n),Ft(i),u.head.appendChild(i)))}}function J2(n){gi.D(n),k0("dns-prefetch",n,null)}function ek(n,i){gi.C(n,i),k0("preconnect",n,i)}function tk(n,i,l){gi.L(n,i,l);var u=Ms;if(u&&n&&i){var b='link[rel="preload"][as="'+kn(i)+'"]';i==="image"&&l&&l.imageSrcSet?(b+='[imagesrcset="'+kn(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(b+='[imagesizes="'+kn(l.imageSizes)+'"]')):b+='[href="'+kn(n)+'"]';var v=b;switch(i){case"style":v=Os(n);break;case"script":v=Rs(n)}gr.has(v)||(n=p({rel:"preload",href:i==="image"&&l&&l.imageSrcSet?void 0:n,as:i},l),gr.set(v,n),u.querySelector(b)!==null||i==="style"&&u.querySelector($l(v))||i==="script"&&u.querySelector(ql(v))||(i=u.createElement("link"),_n(i,"link",n),Ft(i),u.head.appendChild(i)))}}function nk(n,i){gi.m(n,i);var l=Ms;if(l&&n){var u=i&&typeof i.as=="string"?i.as:"script",b='link[rel="modulepreload"][as="'+kn(u)+'"][href="'+kn(n)+'"]',v=b;switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":v=Rs(n)}if(!gr.has(v)&&(n=p({rel:"modulepreload",href:n},i),gr.set(v,n),l.querySelector(b)===null)){switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ql(v)))return}u=l.createElement("link"),_n(u,"link",n),Ft(u),l.head.appendChild(u)}}}function rk(n,i,l){gi.S(n,i,l);var u=Ms;if(u&&n){var b=Br(u).hoistableStyles,v=Os(n);i=i||"default";var A=b.get(v);if(!A){var F={loading:0,preload:null};if(A=u.querySelector($l(v)))F.loading=5;else{n=p({rel:"stylesheet",href:n,"data-precedence":i},l),(l=gr.get(v))&&Jf(n,l);var ne=A=u.createElement("link");Ft(ne),_n(ne,"link",n),ne._p=new Promise(function(le,he){ne.onload=le,ne.onerror=he}),ne.addEventListener("load",function(){F.loading|=1}),ne.addEventListener("error",function(){F.loading|=2}),F.loading|=4,Bc(A,i,u)}A={type:"stylesheet",instance:A,count:1,state:F},b.set(v,A)}}}function ik(n,i){gi.X(n,i);var l=Ms;if(l&&n){var u=Br(l).hoistableScripts,b=Rs(n),v=u.get(b);v||(v=l.querySelector(ql(b)),v||(n=p({src:n,async:!0},i),(i=gr.get(b))&&eh(n,i),v=l.createElement("script"),Ft(v),_n(v,"link",n),l.head.appendChild(v)),v={type:"script",instance:v,count:1,state:null},u.set(b,v))}}function ak(n,i){gi.M(n,i);var l=Ms;if(l&&n){var u=Br(l).hoistableScripts,b=Rs(n),v=u.get(b);v||(v=l.querySelector(ql(b)),v||(n=p({src:n,async:!0,type:"module"},i),(i=gr.get(b))&&eh(n,i),v=l.createElement("script"),Ft(v),_n(v,"link",n),l.head.appendChild(v)),v={type:"script",instance:v,count:1,state:null},u.set(b,v))}}function C0(n,i,l,u){var b=(b=Q.current)?Ic(b):null;if(!b)throw Error(a(446));switch(n){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(i=Os(l.href),l=Br(b).hoistableStyles,u=l.get(i),u||(u={type:"style",instance:null,count:0,state:null},l.set(i,u)),u):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){n=Os(l.href);var v=Br(b).hoistableStyles,A=v.get(n);if(A||(b=b.ownerDocument||b,A={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},v.set(n,A),(v=b.querySelector($l(n)))&&!v._p&&(A.instance=v,A.state.loading=5),gr.has(n)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},gr.set(n,l),v||sk(b,n,l,A.state))),i&&u===null)throw Error(a(528,""));return A}if(i&&u!==null)throw Error(a(529,""));return null;case"script":return i=l.async,l=l.src,typeof l=="string"&&i&&typeof i!="function"&&typeof i!="symbol"?(i=Rs(l),l=Br(b).hoistableScripts,u=l.get(i),u||(u={type:"script",instance:null,count:0,state:null},l.set(i,u)),u):{type:"void",instance:null,count:0,state:null};default:throw Error(a(444,n))}}function Os(n){return'href="'+kn(n)+'"'}function $l(n){return'link[rel="stylesheet"]['+n+"]"}function T0(n){return p({},n,{"data-precedence":n.precedence,precedence:null})}function sk(n,i,l,u){n.querySelector('link[rel="preload"][as="style"]['+i+"]")?u.loading=1:(i=n.createElement("link"),u.preload=i,i.addEventListener("load",function(){return u.loading|=1}),i.addEventListener("error",function(){return u.loading|=2}),_n(i,"link",l),Ft(i),n.head.appendChild(i))}function Rs(n){return'[src="'+kn(n)+'"]'}function ql(n){return"script[async]"+n}function A0(n,i,l){if(i.count++,i.instance===null)switch(i.type){case"style":var u=n.querySelector('style[data-href~="'+kn(l.href)+'"]');if(u)return i.instance=u,Ft(u),u;var b=p({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return u=(n.ownerDocument||n).createElement("style"),Ft(u),_n(u,"style",b),Bc(u,l.precedence,n),i.instance=u;case"stylesheet":b=Os(l.href);var v=n.querySelector($l(b));if(v)return i.state.loading|=4,i.instance=v,Ft(v),v;u=T0(l),(b=gr.get(b))&&Jf(u,b),v=(n.ownerDocument||n).createElement("link"),Ft(v);var A=v;return A._p=new Promise(function(F,ne){A.onload=F,A.onerror=ne}),_n(v,"link",u),i.state.loading|=4,Bc(v,l.precedence,n),i.instance=v;case"script":return v=Rs(l.src),(b=n.querySelector(ql(v)))?(i.instance=b,Ft(b),b):(u=l,(b=gr.get(v))&&(u=p({},l),eh(u,b)),n=n.ownerDocument||n,b=n.createElement("script"),Ft(b),_n(b,"link",u),n.head.appendChild(b),i.instance=b);case"void":return null;default:throw Error(a(443,i.type))}else i.type==="stylesheet"&&(i.state.loading&4)===0&&(u=i.instance,i.state.loading|=4,Bc(u,l.precedence,n));return i.instance}function Bc(n,i,l){for(var u=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),b=u.length?u[u.length-1]:null,v=b,A=0;A title"):null)}function lk(n,i,l){if(l===1||i.itemProp!=null)return!1;switch(n){case"meta":case"title":return!0;case"style":if(typeof i.precedence!="string"||typeof i.href!="string"||i.href==="")break;return!0;case"link":if(typeof i.rel!="string"||typeof i.href!="string"||i.href===""||i.onLoad||i.onError)break;switch(i.rel){case"stylesheet":return n=i.disabled,typeof i.precedence=="string"&&n==null;default:return!0}case"script":if(i.async&&typeof i.async!="function"&&typeof i.async!="symbol"&&!i.onLoad&&!i.onError&&i.src&&typeof i.src=="string")return!0}return!1}function R0(n){return!(n.type==="stylesheet"&&(n.state.loading&3)===0)}function ok(n,i,l,u){if(l.type==="stylesheet"&&(typeof u.media!="string"||matchMedia(u.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var b=Os(u.href),v=i.querySelector($l(b));if(v){i=v._p,i!==null&&typeof i=="object"&&typeof i.then=="function"&&(n.count++,n=Hc.bind(n),i.then(n,n)),l.state.loading|=4,l.instance=v,Ft(v);return}v=i.ownerDocument||i,u=T0(u),(b=gr.get(b))&&Jf(u,b),v=v.createElement("link"),Ft(v);var A=v;A._p=new Promise(function(F,ne){A.onload=F,A.onerror=ne}),_n(v,"link",u),l.instance=v}n.stylesheets===null&&(n.stylesheets=new Map),n.stylesheets.set(l,i),(i=l.state.preload)&&(l.state.loading&3)===0&&(n.count++,l=Hc.bind(n),i.addEventListener("load",l),i.addEventListener("error",l))}}var th=0;function ck(n,i){return n.stylesheets&&n.count===0&&qc(n,n.stylesheets),0th?50:800)+i);return n.unsuspend=l,function(){n.unsuspend=null,clearTimeout(u),clearTimeout(b)}}:null}function Hc(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)qc(this,this.stylesheets);else if(this.unsuspend){var n=this.unsuspend;this.unsuspend=null,n()}}}var $c=null;function qc(n,i){n.stylesheets=null,n.unsuspend!==null&&(n.count++,$c=new Map,i.forEach(uk,n),$c=null,Hc.call(n))}function uk(n,i){if(!(i.state.loading&4)){var l=$c.get(n);if(l)var u=l.get(null);else{l=new Map,$c.set(n,l);for(var b=n.querySelectorAll("link[data-precedence],style[data-precedence]"),v=0;v"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),uh.exports=Sk(),uh.exports}var Ck=kk();/** +`+u.stack}}var Xt=Object.prototype.hasOwnProperty,Pt=e.unstable_scheduleCallback,Kt=e.unstable_cancelCallback,Yn=e.unstable_shouldYield,Nn=e.unstable_requestPaint,ct=e.unstable_now,It=e.unstable_getCurrentPriorityLevel,ue=e.unstable_ImmediatePriority,be=e.unstable_UserBlockingPriority,Oe=e.unstable_NormalPriority,Fe=e.unstable_LowPriority,Ze=e.unstable_IdlePriority,cn=e.log,Sn=e.unstable_setDisableYieldValue,Zt=null,At=null;function Jt(n){if(typeof cn=="function"&&Sn(n),At&&typeof At.setStrictMode=="function")try{At.setStrictMode(Zt,n)}catch{}}var ut=Math.clz32?Math.clz32:Ni,In=Math.log,un=Math.LN2;function Ni(n){return n>>>=0,n===0?32:31-(In(n)/un|0)|0}var nt=256,Xn=262144,On=4194304;function mn(n){var i=n&42;if(i!==0)return i;switch(n&-n){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return n&261888;case 262144:case 524288:case 1048576:case 2097152:return n&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return n&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return n}}function re(n,i,l){var u=n.pendingLanes;if(u===0)return 0;var x=0,v=n.suspendedLanes,A=n.pingedLanes;n=n.warmLanes;var F=u&134217727;return F!==0?(u=F&~v,u!==0?x=mn(u):(A&=F,A!==0?x=mn(A):l||(l=F&~n,l!==0&&(x=mn(l))))):(F=u&~v,F!==0?x=mn(F):A!==0?x=mn(A):l||(l=u&~n,l!==0&&(x=mn(l)))),x===0?0:i!==0&&i!==x&&(i&v)===0&&(v=x&-x,l=i&-i,v>=l||v===32&&(l&4194048)!==0)?i:x}function me(n,i){return(n.pendingLanes&~(n.suspendedLanes&~n.pingedLanes)&i)===0}function Ee(n,i){switch(n){case 1:case 2:case 4:case 8:case 64:return i+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return i+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Pe(){var n=On;return On<<=1,(On&62914560)===0&&(On=4194304),n}function St(n){for(var i=[],l=0;31>l;l++)i.push(n);return i}function gt(n,i){n.pendingLanes|=i,i!==268435456&&(n.suspendedLanes=0,n.pingedLanes=0,n.warmLanes=0)}function Me(n,i,l,u,x,v){var A=n.pendingLanes;n.pendingLanes=l,n.suspendedLanes=0,n.pingedLanes=0,n.warmLanes=0,n.expiredLanes&=l,n.entangledLanes&=l,n.errorRecoveryDisabledLanes&=l,n.shellSuspendCounter=0;var F=n.entanglements,ne=n.expirationTimes,le=n.hiddenUpdates;for(l=A&~l;0"u")return null;try{return n.activeElement||n.body}catch{return n.body}}var rs=/[\n"\\]/g;function Cn(n){return n.replace(rs,function(i){return"\\"+i.charCodeAt(0).toString(16)+" "})}function ba(n,i,l,u,x,v,A,F){n.name="",A!=null&&typeof A!="function"&&typeof A!="symbol"&&typeof A!="boolean"?n.type=A:n.removeAttribute("type"),i!=null?A==="number"?(i===0&&n.value===""||n.value!=i)&&(n.value=""+_t(i)):n.value!==""+_t(i)&&(n.value=""+_t(i)):A!=="submit"&&A!=="reset"||n.removeAttribute("value"),i!=null?Oi(n,A,_t(i)):l!=null?Oi(n,A,_t(l)):u!=null&&n.removeAttribute("value"),x==null&&v!=null&&(n.defaultChecked=!!v),x!=null&&(n.checked=x&&typeof x!="function"&&typeof x!="symbol"),F!=null&&typeof F!="function"&&typeof F!="symbol"&&typeof F!="boolean"?n.name=""+_t(F):n.removeAttribute("name")}function Er(n,i,l,u,x,v,A,F){if(v!=null&&typeof v!="function"&&typeof v!="symbol"&&typeof v!="boolean"&&(n.type=v),i!=null||l!=null){if(!(v!=="submit"&&v!=="reset"||i!=null)){Ai(n);return}l=l!=null?""+_t(l):"",i=i!=null?""+_t(i):l,F||i===n.value||(n.value=i),n.defaultValue=i}u=u??x,u=typeof u!="function"&&typeof u!="symbol"&&!!u,n.checked=F?n.checked:!!u,n.defaultChecked=!!u,A!=null&&typeof A!="function"&&typeof A!="symbol"&&typeof A!="boolean"&&(n.name=A),Ai(n)}function Oi(n,i,l){i==="number"&&Mi(n.ownerDocument)===n||n.defaultValue===""+l||(n.defaultValue=""+l)}function dn(n,i,l,u){if(n=n.options,i){i={};for(var x=0;x"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),fd=!1;if(ti)try{var ll={};Object.defineProperty(ll,"passive",{get:function(){fd=!0}}),window.addEventListener("test",ll,ll),window.removeEventListener("test",ll,ll)}catch{fd=!1}var Di=null,hd=null,Po=null;function _g(){if(Po)return Po;var n,i=hd,l=i.length,u,x="value"in Di?Di.value:Di.textContent,v=x.length;for(n=0;n=ul),Cg=" ",Tg=!1;function Ag(n,i){switch(n){case"keyup":return K2.indexOf(i.keyCode)!==-1;case"keydown":return i.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Mg(n){return n=n.detail,typeof n=="object"&&"data"in n?n.data:null}var as=!1;function Q2(n,i){switch(n){case"compositionend":return Mg(i);case"keypress":return i.which!==32?null:(Tg=!0,Cg);case"textInput":return n=i.data,n===Cg&&Tg?null:n;default:return null}}function W2(n,i){if(as)return n==="compositionend"||!bd&&Ag(n,i)?(n=_g(),Po=hd=Di=null,as=!1,n):null;switch(n){case"paste":return null;case"keypress":if(!(i.ctrlKey||i.altKey||i.metaKey)||i.ctrlKey&&i.altKey){if(i.char&&1=i)return{node:l,offset:i-n};n=u}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Bg(l)}}function Hg(n,i){return n&&i?n===i?!0:n&&n.nodeType===3?!1:i&&i.nodeType===3?Hg(n,i.parentNode):"contains"in n?n.contains(i):n.compareDocumentPosition?!!(n.compareDocumentPosition(i)&16):!1:!1}function $g(n){n=n!=null&&n.ownerDocument!=null&&n.ownerDocument.defaultView!=null?n.ownerDocument.defaultView:window;for(var i=Mi(n.document);i instanceof n.HTMLIFrameElement;){try{var l=typeof i.contentWindow.location.href=="string"}catch{l=!1}if(l)n=i.contentWindow;else break;i=Mi(n.document)}return i}function _d(n){var i=n&&n.nodeName&&n.nodeName.toLowerCase();return i&&(i==="input"&&(n.type==="text"||n.type==="search"||n.type==="tel"||n.type==="url"||n.type==="password")||i==="textarea"||n.contentEditable==="true")}var sS=ti&&"documentMode"in document&&11>=document.documentMode,ss=null,wd=null,ml=null,Ed=!1;function qg(n,i,l){var u=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Ed||ss==null||ss!==Mi(u)||(u=ss,"selectionStart"in u&&_d(u)?u={start:u.selectionStart,end:u.selectionEnd}:(u=(u.ownerDocument&&u.ownerDocument.defaultView||window).getSelection(),u={anchorNode:u.anchorNode,anchorOffset:u.anchorOffset,focusNode:u.focusNode,focusOffset:u.focusOffset}),ml&&hl(ml,u)||(ml=u,u=zc(wd,"onSelect"),0>=A,x-=A,Hr=1<<32-ut(i)+x|l<Ke?(at=je,je=null):at=je.sibling;var mt=oe(ae,je,se[Ke],pe);if(mt===null){je===null&&(je=at);break}n&&je&&mt.alternate===null&&i(ae,je),ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt,je=at}if(Ke===se.length)return l(ae,je),lt&&ri(ae,Ke),Ie;if(je===null){for(;KeKe?(at=je,je=null):at=je.sibling;var na=oe(ae,je,mt.value,pe);if(na===null){je===null&&(je=at);break}n&&je&&na.alternate===null&&i(ae,je),ie=v(na,ie,Ke),ht===null?Ie=na:ht.sibling=na,ht=na,je=at}if(mt.done)return l(ae,je),lt&&ri(ae,Ke),Ie;if(je===null){for(;!mt.done;Ke++,mt=se.next())mt=ge(ae,mt.value,pe),mt!==null&&(ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt);return lt&&ri(ae,Ke),Ie}for(je=u(je);!mt.done;Ke++,mt=se.next())mt=de(je,ae,Ke,mt.value,pe),mt!==null&&(n&&mt.alternate!==null&&je.delete(mt.key===null?Ke:mt.key),ie=v(mt,ie,Ke),ht===null?Ie=mt:ht.sibling=mt,ht=mt);return n&&je.forEach(function(kk){return i(ae,kk)}),lt&&ri(ae,Ke),Ie}function Nt(ae,ie,se,pe){if(typeof se=="object"&&se!==null&&se.type===N&&se.key===null&&(se=se.props.children),typeof se=="object"&&se!==null){switch(se.$$typeof){case b:e:{for(var Ie=se.key;ie!==null;){if(ie.key===Ie){if(Ie=se.type,Ie===N){if(ie.tag===7){l(ae,ie.sibling),pe=x(ie,se.props.children),pe.return=ae,ae=pe;break e}}else if(ie.elementType===Ie||typeof Ie=="object"&&Ie!==null&&Ie.$$typeof===B&&Aa(Ie)===ie.type){l(ae,ie.sibling),pe=x(ie,se.props),vl(pe,se),pe.return=ae,ae=pe;break e}l(ae,ie);break}else i(ae,ie);ie=ie.sibling}se.type===N?(pe=Na(se.props.children,ae.mode,pe,se.key),pe.return=ae,ae=pe):(pe=Jo(se.type,se.key,se.props,null,ae.mode,pe),vl(pe,se),pe.return=ae,ae=pe)}return A(ae);case _:e:{for(Ie=se.key;ie!==null;){if(ie.key===Ie)if(ie.tag===4&&ie.stateNode.containerInfo===se.containerInfo&&ie.stateNode.implementation===se.implementation){l(ae,ie.sibling),pe=x(ie,se.children||[]),pe.return=ae,ae=pe;break e}else{l(ae,ie);break}else i(ae,ie);ie=ie.sibling}pe=Md(se,ae.mode,pe),pe.return=ae,ae=pe}return A(ae);case B:return se=Aa(se),Nt(ae,ie,se,pe)}if($(se))return Ae(ae,ie,se,pe);if(V(se)){if(Ie=V(se),typeof Ie!="function")throw Error(a(150));return se=Ie.call(se),He(ae,ie,se,pe)}if(typeof se.then=="function")return Nt(ae,ie,sc(se),pe);if(se.$$typeof===E)return Nt(ae,ie,nc(ae,se),pe);lc(ae,se)}return typeof se=="string"&&se!==""||typeof se=="number"||typeof se=="bigint"?(se=""+se,ie!==null&&ie.tag===6?(l(ae,ie.sibling),pe=x(ie,se),pe.return=ae,ae=pe):(l(ae,ie),pe=Ad(se,ae.mode,pe),pe.return=ae,ae=pe),A(ae)):l(ae,ie)}return function(ae,ie,se,pe){try{yl=0;var Ie=Nt(ae,ie,se,pe);return xs=null,Ie}catch(je){if(je===gs||je===ic)throw je;var ht=Zn(29,je,null,ae.mode);return ht.lanes=pe,ht.return=ae,ht}finally{}}}var Oa=dx(!0),fx=dx(!1),Ui=!1;function qd(n){n.updateQueue={baseState:n.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Pd(n,i){n=n.updateQueue,i.updateQueue===n&&(i.updateQueue={baseState:n.baseState,firstBaseUpdate:n.firstBaseUpdate,lastBaseUpdate:n.lastBaseUpdate,shared:n.shared,callbacks:null})}function Hi(n){return{lane:n,tag:0,payload:null,callback:null,next:null}}function $i(n,i,l){var u=n.updateQueue;if(u===null)return null;if(u=u.shared,(pt&2)!==0){var x=u.pending;return x===null?i.next=i:(i.next=x.next,x.next=i),u.pending=i,i=Wo(n),Kg(n,null,l),i}return Qo(n,u,i,l),Wo(n)}function _l(n,i,l){if(i=i.updateQueue,i!==null&&(i=i.shared,(l&4194048)!==0)){var u=i.lanes;u&=n.pendingLanes,l|=u,i.lanes=l,Ue(n,l)}}function Fd(n,i){var l=n.updateQueue,u=n.alternate;if(u!==null&&(u=u.updateQueue,l===u)){var x=null,v=null;if(l=l.firstBaseUpdate,l!==null){do{var A={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};v===null?x=v=A:v=v.next=A,l=l.next}while(l!==null);v===null?x=v=i:v=v.next=i}else x=v=i;l={baseState:u.baseState,firstBaseUpdate:x,lastBaseUpdate:v,shared:u.shared,callbacks:u.callbacks},n.updateQueue=l;return}n=l.lastBaseUpdate,n===null?l.firstBaseUpdate=i:n.next=i,l.lastBaseUpdate=i}var Gd=!1;function wl(){if(Gd){var n=ps;if(n!==null)throw n}}function El(n,i,l,u){Gd=!1;var x=n.updateQueue;Ui=!1;var v=x.firstBaseUpdate,A=x.lastBaseUpdate,F=x.shared.pending;if(F!==null){x.shared.pending=null;var ne=F,le=ne.next;ne.next=null,A===null?v=le:A.next=le,A=ne;var he=n.alternate;he!==null&&(he=he.updateQueue,F=he.lastBaseUpdate,F!==A&&(F===null?he.firstBaseUpdate=le:F.next=le,he.lastBaseUpdate=ne))}if(v!==null){var ge=x.baseState;A=0,he=le=ne=null,F=v;do{var oe=F.lane&-536870913,de=oe!==F.lane;if(de?(it&oe)===oe:(u&oe)===oe){oe!==0&&oe===ms&&(Gd=!0),he!==null&&(he=he.next={lane:0,tag:F.tag,payload:F.payload,callback:null,next:null});e:{var Ae=n,He=F;oe=i;var Nt=l;switch(He.tag){case 1:if(Ae=He.payload,typeof Ae=="function"){ge=Ae.call(Nt,ge,oe);break e}ge=Ae;break e;case 3:Ae.flags=Ae.flags&-65537|128;case 0:if(Ae=He.payload,oe=typeof Ae=="function"?Ae.call(Nt,ge,oe):Ae,oe==null)break e;ge=g({},ge,oe);break e;case 2:Ui=!0}}oe=F.callback,oe!==null&&(n.flags|=64,de&&(n.flags|=8192),de=x.callbacks,de===null?x.callbacks=[oe]:de.push(oe))}else de={lane:oe,tag:F.tag,payload:F.payload,callback:F.callback,next:null},he===null?(le=he=de,ne=ge):he=he.next=de,A|=oe;if(F=F.next,F===null){if(F=x.shared.pending,F===null)break;de=F,F=de.next,de.next=null,x.lastBaseUpdate=de,x.shared.pending=null}}while(!0);he===null&&(ne=ge),x.baseState=ne,x.firstBaseUpdate=le,x.lastBaseUpdate=he,v===null&&(x.shared.lanes=0),Vi|=A,n.lanes=A,n.memoizedState=ge}}function hx(n,i){if(typeof n!="function")throw Error(a(191,n));n.call(i)}function mx(n,i){var l=n.callbacks;if(l!==null)for(n.callbacks=null,n=0;nv?v:8;var A=O.T,F={};O.T=F,df(n,!1,i,l);try{var ne=x(),le=O.S;if(le!==null&&le(F,ne),ne!==null&&typeof ne=="object"&&typeof ne.then=="function"){var he=pS(ne,u);kl(n,i,he,tr(n))}else kl(n,i,u,tr(n))}catch(ge){kl(n,i,{then:function(){},status:"rejected",reason:ge},tr())}finally{H.p=v,A!==null&&F.types!==null&&(A.types=F.types),O.T=A}}function _S(){}function cf(n,i,l,u){if(n.tag!==5)throw Error(a(476));var x=Vx(n).queue;Gx(n,x,i,X,l===null?_S:function(){return Yx(n),l(u)})}function Vx(n){var i=n.memoizedState;if(i!==null)return i;i={memoizedState:X,baseState:X,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:li,lastRenderedState:X},next:null};var l={};return i.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:li,lastRenderedState:l},next:null},n.memoizedState=i,n=n.alternate,n!==null&&(n.memoizedState=i),i}function Yx(n){var i=Vx(n);i.next===null&&(i=n.alternate.memoizedState),kl(n,i.next.queue,{},tr())}function uf(){return vn(Pl)}function Xx(){return Wt().memoizedState}function Kx(){return Wt().memoizedState}function wS(n){for(var i=n.return;i!==null;){switch(i.tag){case 24:case 3:var l=tr();n=Hi(l);var u=$i(i,n,l);u!==null&&(Pn(u,i,l),_l(u,i,l)),i={cache:Bd()},n.payload=i;return}i=i.return}}function ES(n,i,l){var u=tr();l={lane:u,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},xc(n)?Qx(i,l):(l=Cd(n,i,l,u),l!==null&&(Pn(l,n,u),Wx(l,i,u)))}function Zx(n,i,l){var u=tr();kl(n,i,l,u)}function kl(n,i,l,u){var x={lane:u,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(xc(n))Qx(i,x);else{var v=n.alternate;if(n.lanes===0&&(v===null||v.lanes===0)&&(v=i.lastRenderedReducer,v!==null))try{var A=i.lastRenderedState,F=v(A,l);if(x.hasEagerState=!0,x.eagerState=F,Kn(F,A))return Qo(n,i,x,0),kt===null&&Zo(),!1}catch{}finally{}if(l=Cd(n,i,x,u),l!==null)return Pn(l,n,u),Wx(l,i,u),!0}return!1}function df(n,i,l,u){if(u={lane:2,revertLane:Pf(),gesture:null,action:u,hasEagerState:!1,eagerState:null,next:null},xc(n)){if(i)throw Error(a(479))}else i=Cd(n,l,u,2),i!==null&&Pn(i,n,2)}function xc(n){var i=n.alternate;return n===Xe||i!==null&&i===Xe}function Qx(n,i){ys=uc=!0;var l=n.pending;l===null?i.next=i:(i.next=l.next,l.next=i),n.pending=i}function Wx(n,i,l){if((l&4194048)!==0){var u=i.lanes;u&=n.pendingLanes,l|=u,i.lanes=l,Ue(n,l)}}var Cl={readContext:vn,use:hc,useCallback:Gt,useContext:Gt,useEffect:Gt,useImperativeHandle:Gt,useLayoutEffect:Gt,useInsertionEffect:Gt,useMemo:Gt,useReducer:Gt,useRef:Gt,useState:Gt,useDebugValue:Gt,useDeferredValue:Gt,useTransition:Gt,useSyncExternalStore:Gt,useId:Gt,useHostTransitionStatus:Gt,useFormState:Gt,useActionState:Gt,useOptimistic:Gt,useMemoCache:Gt,useCacheRefresh:Gt};Cl.useEffectEvent=Gt;var Jx={readContext:vn,use:hc,useCallback:function(n,i){return Dn().memoizedState=[n,i===void 0?null:i],n},useContext:vn,useEffect:zx,useImperativeHandle:function(n,i,l){l=l!=null?l.concat([n]):null,pc(4194308,4,Hx.bind(null,i,n),l)},useLayoutEffect:function(n,i){return pc(4194308,4,n,i)},useInsertionEffect:function(n,i){pc(4,2,n,i)},useMemo:function(n,i){var l=Dn();i=i===void 0?null:i;var u=n();if(Ra){Jt(!0);try{n()}finally{Jt(!1)}}return l.memoizedState=[u,i],u},useReducer:function(n,i,l){var u=Dn();if(l!==void 0){var x=l(i);if(Ra){Jt(!0);try{l(i)}finally{Jt(!1)}}}else x=i;return u.memoizedState=u.baseState=x,n={pending:null,lanes:0,dispatch:null,lastRenderedReducer:n,lastRenderedState:x},u.queue=n,n=n.dispatch=ES.bind(null,Xe,n),[u.memoizedState,n]},useRef:function(n){var i=Dn();return n={current:n},i.memoizedState=n},useState:function(n){n=rf(n);var i=n.queue,l=Zx.bind(null,Xe,i);return i.dispatch=l,[n.memoizedState,l]},useDebugValue:lf,useDeferredValue:function(n,i){var l=Dn();return of(l,n,i)},useTransition:function(){var n=rf(!1);return n=Gx.bind(null,Xe,n.queue,!0,!1),Dn().memoizedState=n,[!1,n]},useSyncExternalStore:function(n,i,l){var u=Xe,x=Dn();if(lt){if(l===void 0)throw Error(a(407));l=l()}else{if(l=i(),kt===null)throw Error(a(349));(it&127)!==0||vx(u,i,l)}x.memoizedState=l;var v={value:l,getSnapshot:i};return x.queue=v,zx(wx.bind(null,u,v,n),[n]),u.flags|=2048,_s(9,{destroy:void 0},_x.bind(null,u,v,l,i),null),l},useId:function(){var n=Dn(),i=kt.identifierPrefix;if(lt){var l=$r,u=Hr;l=(u&~(1<<32-ut(u)-1)).toString(32)+l,i="_"+i+"R_"+l,l=dc++,0<\/script>",v=v.removeChild(v.firstChild);break;case"select":v=typeof u.is=="string"?A.createElement("select",{is:u.is}):A.createElement("select"),u.multiple?v.multiple=!0:u.size&&(v.size=u.size);break;default:v=typeof u.is=="string"?A.createElement(x,{is:u.is}):A.createElement(x)}}v[Ut]=i,v[pn]=u;e:for(A=i.child;A!==null;){if(A.tag===5||A.tag===6)v.appendChild(A.stateNode);else if(A.tag!==4&&A.tag!==27&&A.child!==null){A.child.return=A,A=A.child;continue}if(A===i)break e;for(;A.sibling===null;){if(A.return===null||A.return===i)break e;A=A.return}A.sibling.return=A.return,A=A.sibling}i.stateNode=v;e:switch(wn(v,x,u),x){case"button":case"input":case"select":case"textarea":u=!!u.autoFocus;break e;case"img":u=!0;break e;default:u=!1}u&&ci(i)}}return Dt(i),Sf(i,i.type,n===null?null:n.memoizedProps,i.pendingProps,l),null;case 6:if(n&&i.stateNode!=null)n.memoizedProps!==u&&ci(i);else{if(typeof u!="string"&&i.stateNode===null)throw Error(a(166));if(n=Q.current,fs(i)){if(n=i.stateNode,l=i.memoizedProps,u=null,x=yn,x!==null)switch(x.tag){case 27:case 5:u=x.memoizedProps}n[Ut]=i,n=!!(n.nodeValue===l||u!==null&&u.suppressHydrationWarning===!0||b0(n.nodeValue,l)),n||Ii(i,!0)}else n=Ic(n).createTextNode(u),n[Ut]=i,i.stateNode=n}return Dt(i),null;case 31:if(l=i.memoizedState,n===null||n.memoizedState!==null){if(u=fs(i),l!==null){if(n===null){if(!u)throw Error(a(318));if(n=i.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(a(557));n[Ut]=i}else Sa(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Dt(i),n=!1}else l=Dd(),n!==null&&n.memoizedState!==null&&(n.memoizedState.hydrationErrors=l),n=!0;if(!n)return i.flags&256?(Wn(i),i):(Wn(i),null);if((i.flags&128)!==0)throw Error(a(558))}return Dt(i),null;case 13:if(u=i.memoizedState,n===null||n.memoizedState!==null&&n.memoizedState.dehydrated!==null){if(x=fs(i),u!==null&&u.dehydrated!==null){if(n===null){if(!x)throw Error(a(318));if(x=i.memoizedState,x=x!==null?x.dehydrated:null,!x)throw Error(a(317));x[Ut]=i}else Sa(),(i.flags&128)===0&&(i.memoizedState=null),i.flags|=4;Dt(i),x=!1}else x=Dd(),n!==null&&n.memoizedState!==null&&(n.memoizedState.hydrationErrors=x),x=!0;if(!x)return i.flags&256?(Wn(i),i):(Wn(i),null)}return Wn(i),(i.flags&128)!==0?(i.lanes=l,i):(l=u!==null,n=n!==null&&n.memoizedState!==null,l&&(u=i.child,x=null,u.alternate!==null&&u.alternate.memoizedState!==null&&u.alternate.memoizedState.cachePool!==null&&(x=u.alternate.memoizedState.cachePool.pool),v=null,u.memoizedState!==null&&u.memoizedState.cachePool!==null&&(v=u.memoizedState.cachePool.pool),v!==x&&(u.flags|=2048)),l!==n&&l&&(i.child.flags|=8192),wc(i,i.updateQueue),Dt(i),null);case 4:return te(),n===null&&Yf(i.stateNode.containerInfo),Dt(i),null;case 10:return ai(i.type),Dt(i),null;case 19:if(Y(Qt),u=i.memoizedState,u===null)return Dt(i),null;if(x=(i.flags&128)!==0,v=u.rendering,v===null)if(x)Al(u,!1);else{if(Vt!==0||n!==null&&(n.flags&128)!==0)for(n=i.child;n!==null;){if(v=cc(n),v!==null){for(i.flags|=128,Al(u,!1),n=v.updateQueue,i.updateQueue=n,wc(i,n),i.subtreeFlags=0,n=l,l=i.child;l!==null;)Zg(l,n),l=l.sibling;return L(Qt,Qt.current&1|2),lt&&ri(i,u.treeForkCount),i.child}n=n.sibling}u.tail!==null&&ct()>Cc&&(i.flags|=128,x=!0,Al(u,!1),i.lanes=4194304)}else{if(!x)if(n=cc(v),n!==null){if(i.flags|=128,x=!0,n=n.updateQueue,i.updateQueue=n,wc(i,n),Al(u,!0),u.tail===null&&u.tailMode==="hidden"&&!v.alternate&&!lt)return Dt(i),null}else 2*ct()-u.renderingStartTime>Cc&&l!==536870912&&(i.flags|=128,x=!0,Al(u,!1),i.lanes=4194304);u.isBackwards?(v.sibling=i.child,i.child=v):(n=u.last,n!==null?n.sibling=v:i.child=v,u.last=v)}return u.tail!==null?(n=u.tail,u.rendering=n,u.tail=n.sibling,u.renderingStartTime=ct(),n.sibling=null,l=Qt.current,L(Qt,x?l&1|2:l&1),lt&&ri(i,u.treeForkCount),n):(Dt(i),null);case 22:case 23:return Wn(i),Yd(),u=i.memoizedState!==null,n!==null?n.memoizedState!==null!==u&&(i.flags|=8192):u&&(i.flags|=8192),u?(l&536870912)!==0&&(i.flags&128)===0&&(Dt(i),i.subtreeFlags&6&&(i.flags|=8192)):Dt(i),l=i.updateQueue,l!==null&&wc(i,l.retryQueue),l=null,n!==null&&n.memoizedState!==null&&n.memoizedState.cachePool!==null&&(l=n.memoizedState.cachePool.pool),u=null,i.memoizedState!==null&&i.memoizedState.cachePool!==null&&(u=i.memoizedState.cachePool.pool),u!==l&&(i.flags|=2048),n!==null&&Y(Ta),null;case 24:return l=null,n!==null&&(l=n.memoizedState.cache),i.memoizedState.cache!==l&&(i.flags|=2048),ai(tn),Dt(i),null;case 25:return null;case 30:return null}throw Error(a(156,i.tag))}function TS(n,i){switch(Rd(i),i.tag){case 1:return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 3:return ai(tn),te(),n=i.flags,(n&65536)!==0&&(n&128)===0?(i.flags=n&-65537|128,i):null;case 26:case 27:case 5:return fe(i),null;case 31:if(i.memoizedState!==null){if(Wn(i),i.alternate===null)throw Error(a(340));Sa()}return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 13:if(Wn(i),n=i.memoizedState,n!==null&&n.dehydrated!==null){if(i.alternate===null)throw Error(a(340));Sa()}return n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 19:return Y(Qt),null;case 4:return te(),null;case 10:return ai(i.type),null;case 22:case 23:return Wn(i),Yd(),n!==null&&Y(Ta),n=i.flags,n&65536?(i.flags=n&-65537|128,i):null;case 24:return ai(tn),null;case 25:return null;default:return null}}function Eb(n,i){switch(Rd(i),i.tag){case 3:ai(tn),te();break;case 26:case 27:case 5:fe(i);break;case 4:te();break;case 31:i.memoizedState!==null&&Wn(i);break;case 13:Wn(i);break;case 19:Y(Qt);break;case 10:ai(i.type);break;case 22:case 23:Wn(i),Yd(),n!==null&&Y(Ta);break;case 24:ai(tn)}}function Ml(n,i){try{var l=i.updateQueue,u=l!==null?l.lastEffect:null;if(u!==null){var x=u.next;l=x;do{if((l.tag&n)===n){u=void 0;var v=l.create,A=l.inst;u=v(),A.destroy=u}l=l.next}while(l!==x)}}catch(F){yt(i,i.return,F)}}function Fi(n,i,l){try{var u=i.updateQueue,x=u!==null?u.lastEffect:null;if(x!==null){var v=x.next;u=v;do{if((u.tag&n)===n){var A=u.inst,F=A.destroy;if(F!==void 0){A.destroy=void 0,x=i;var ne=l,le=F;try{le()}catch(he){yt(x,ne,he)}}}u=u.next}while(u!==v)}}catch(he){yt(i,i.return,he)}}function Nb(n){var i=n.updateQueue;if(i!==null){var l=n.stateNode;try{mx(i,l)}catch(u){yt(n,n.return,u)}}}function Sb(n,i,l){l.props=ja(n.type,n.memoizedProps),l.state=n.memoizedState;try{l.componentWillUnmount()}catch(u){yt(n,i,u)}}function Ol(n,i){try{var l=n.ref;if(l!==null){switch(n.tag){case 26:case 27:case 5:var u=n.stateNode;break;case 30:u=n.stateNode;break;default:u=n.stateNode}typeof l=="function"?n.refCleanup=l(u):l.current=u}}catch(x){yt(n,i,x)}}function qr(n,i){var l=n.ref,u=n.refCleanup;if(l!==null)if(typeof u=="function")try{u()}catch(x){yt(n,i,x)}finally{n.refCleanup=null,n=n.alternate,n!=null&&(n.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(x){yt(n,i,x)}else l.current=null}function kb(n){var i=n.type,l=n.memoizedProps,u=n.stateNode;try{e:switch(i){case"button":case"input":case"select":case"textarea":l.autoFocus&&u.focus();break e;case"img":l.src?u.src=l.src:l.srcSet&&(u.srcset=l.srcSet)}}catch(x){yt(n,n.return,x)}}function kf(n,i,l){try{var u=n.stateNode;ZS(u,n.type,l,i),u[pn]=i}catch(x){yt(n,n.return,x)}}function Cb(n){return n.tag===5||n.tag===3||n.tag===26||n.tag===27&&Qi(n.type)||n.tag===4}function Cf(n){e:for(;;){for(;n.sibling===null;){if(n.return===null||Cb(n.return))return null;n=n.return}for(n.sibling.return=n.return,n=n.sibling;n.tag!==5&&n.tag!==6&&n.tag!==18;){if(n.tag===27&&Qi(n.type)||n.flags&2||n.child===null||n.tag===4)continue e;n.child.return=n,n=n.child}if(!(n.flags&2))return n.stateNode}}function Tf(n,i,l){var u=n.tag;if(u===5||u===6)n=n.stateNode,i?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(n,i):(i=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,i.appendChild(n),l=l._reactRootContainer,l!=null||i.onclick!==null||(i.onclick=_e));else if(u!==4&&(u===27&&Qi(n.type)&&(l=n.stateNode,i=null),n=n.child,n!==null))for(Tf(n,i,l),n=n.sibling;n!==null;)Tf(n,i,l),n=n.sibling}function Ec(n,i,l){var u=n.tag;if(u===5||u===6)n=n.stateNode,i?l.insertBefore(n,i):l.appendChild(n);else if(u!==4&&(u===27&&Qi(n.type)&&(l=n.stateNode),n=n.child,n!==null))for(Ec(n,i,l),n=n.sibling;n!==null;)Ec(n,i,l),n=n.sibling}function Tb(n){var i=n.stateNode,l=n.memoizedProps;try{for(var u=n.type,x=i.attributes;x.length;)i.removeAttributeNode(x[0]);wn(i,u,l),i[Ut]=n,i[pn]=l}catch(v){yt(n,n.return,v)}}var ui=!1,an=!1,Af=!1,Ab=typeof WeakSet=="function"?WeakSet:Set,xn=null;function AS(n,i){if(n=n.containerInfo,Zf=Fc,n=$g(n),_d(n)){if("selectionStart"in n)var l={start:n.selectionStart,end:n.selectionEnd};else e:{l=(l=n.ownerDocument)&&l.defaultView||window;var u=l.getSelection&&l.getSelection();if(u&&u.rangeCount!==0){l=u.anchorNode;var x=u.anchorOffset,v=u.focusNode;u=u.focusOffset;try{l.nodeType,v.nodeType}catch{l=null;break e}var A=0,F=-1,ne=-1,le=0,he=0,ge=n,oe=null;t:for(;;){for(var de;ge!==l||x!==0&&ge.nodeType!==3||(F=A+x),ge!==v||u!==0&&ge.nodeType!==3||(ne=A+u),ge.nodeType===3&&(A+=ge.nodeValue.length),(de=ge.firstChild)!==null;)oe=ge,ge=de;for(;;){if(ge===n)break t;if(oe===l&&++le===x&&(F=A),oe===v&&++he===u&&(ne=A),(de=ge.nextSibling)!==null)break;ge=oe,oe=ge.parentNode}ge=de}l=F===-1||ne===-1?null:{start:F,end:ne}}else l=null}l=l||{start:0,end:0}}else l=null;for(Qf={focusedElem:n,selectionRange:l},Fc=!1,xn=i;xn!==null;)if(i=xn,n=i.child,(i.subtreeFlags&1028)!==0&&n!==null)n.return=i,xn=n;else for(;xn!==null;){switch(i=xn,v=i.alternate,n=i.flags,i.tag){case 0:if((n&4)!==0&&(n=i.updateQueue,n=n!==null?n.events:null,n!==null))for(l=0;l title"))),wn(v,u,l),v[Ut]=n,Ft(v),u=v;break e;case"link":var A=L0("link","href",x).get(u+(l.href||""));if(A){for(var F=0;FNt&&(A=Nt,Nt=He,He=A);var ae=Ug(F,He),ie=Ug(F,Nt);if(ae&&ie&&(de.rangeCount!==1||de.anchorNode!==ae.node||de.anchorOffset!==ae.offset||de.focusNode!==ie.node||de.focusOffset!==ie.offset)){var se=ge.createRange();se.setStart(ae.node,ae.offset),de.removeAllRanges(),He>Nt?(de.addRange(se),de.extend(ie.node,ie.offset)):(se.setEnd(ie.node,ie.offset),de.addRange(se))}}}}for(ge=[],de=F;de=de.parentNode;)de.nodeType===1&&ge.push({element:de,left:de.scrollLeft,top:de.scrollTop});for(typeof F.focus=="function"&&F.focus(),F=0;Fl?32:l,O.T=null,l=zf,zf=null;var v=Xi,A=pi;if(fn=0,ks=Xi=null,pi=0,(pt&6)!==0)throw Error(a(331));var F=pt;if(pt|=4,Hb(v.current),Ib(v,v.current,A,l),pt=F,Il(0,!1),At&&typeof At.onPostCommitFiberRoot=="function")try{At.onPostCommitFiberRoot(Zt,v)}catch{}return!0}finally{H.p=x,O.T=u,i0(n,i)}}function s0(n,i,l){i=ur(l,i),i=pf(n.stateNode,i,2),n=$i(n,i,2),n!==null&&(gt(n,2),Pr(n))}function yt(n,i,l){if(n.tag===3)s0(n,n,l);else for(;i!==null;){if(i.tag===3){s0(i,n,l);break}else if(i.tag===1){var u=i.stateNode;if(typeof i.type.getDerivedStateFromError=="function"||typeof u.componentDidCatch=="function"&&(Yi===null||!Yi.has(u))){n=ur(l,n),l=lb(2),u=$i(i,l,2),u!==null&&(ob(l,u,i,n),gt(u,2),Pr(u));break}}i=i.return}}function Hf(n,i,l){var u=n.pingCache;if(u===null){u=n.pingCache=new RS;var x=new Set;u.set(i,x)}else x=u.get(i),x===void 0&&(x=new Set,u.set(i,x));x.has(l)||(Rf=!0,x.add(l),n=IS.bind(null,n,i,l),i.then(n,n))}function IS(n,i,l){var u=n.pingCache;u!==null&&u.delete(i),n.pingedLanes|=n.suspendedLanes&l,n.warmLanes&=~l,kt===n&&(it&l)===l&&(Vt===4||Vt===3&&(it&62914560)===it&&300>ct()-kc?(pt&2)===0&&Cs(n,0):jf|=l,Ss===it&&(Ss=0)),Pr(n)}function l0(n,i){i===0&&(i=Pe()),n=Ea(n,i),n!==null&&(gt(n,i),Pr(n))}function BS(n){var i=n.memoizedState,l=0;i!==null&&(l=i.retryLane),l0(n,l)}function US(n,i){var l=0;switch(n.tag){case 31:case 13:var u=n.stateNode,x=n.memoizedState;x!==null&&(l=x.retryLane);break;case 19:u=n.stateNode;break;case 22:u=n.stateNode._retryCache;break;default:throw Error(a(314))}u!==null&&u.delete(i),l0(n,l)}function HS(n,i){return Pt(n,i)}var jc=null,As=null,$f=!1,Dc=!1,qf=!1,Zi=0;function Pr(n){n!==As&&n.next===null&&(As===null?jc=As=n:As=As.next=n),Dc=!0,$f||($f=!0,qS())}function Il(n,i){if(!qf&&Dc){qf=!0;do for(var l=!1,u=jc;u!==null;){if(n!==0){var x=u.pendingLanes;if(x===0)var v=0;else{var A=u.suspendedLanes,F=u.pingedLanes;v=(1<<31-ut(42|n)+1)-1,v&=x&~(A&~F),v=v&201326741?v&201326741|1:v?v|2:0}v!==0&&(l=!0,d0(u,v))}else v=it,v=re(u,u===kt?v:0,u.cancelPendingCommit!==null||u.timeoutHandle!==-1),(v&3)===0||me(u,v)||(l=!0,d0(u,v));u=u.next}while(l);qf=!1}}function $S(){o0()}function o0(){Dc=$f=!1;var n=0;Zi!==0&&WS()&&(n=Zi);for(var i=ct(),l=null,u=jc;u!==null;){var x=u.next,v=c0(u,i);v===0?(u.next=null,l===null?jc=x:l.next=x,x===null&&(As=l)):(l=u,(n!==0||(v&3)!==0)&&(Dc=!0)),u=x}fn!==0&&fn!==5||Il(n),Zi!==0&&(Zi=0)}function c0(n,i){for(var l=n.suspendedLanes,u=n.pingedLanes,x=n.expirationTimes,v=n.pendingLanes&-62914561;0F)break;var he=ne.transferSize,ge=ne.initiatorType;he&&y0(ge)&&(ne=ne.responseEnd,A+=he*(ne"u"?null:document;function O0(n,i,l){var u=Ms;if(u&&typeof i=="string"&&i){var x=Cn(i);x='link[rel="'+n+'"][href="'+x+'"]',typeof l=="string"&&(x+='[crossorigin="'+l+'"]'),M0.has(x)||(M0.add(x),n={rel:n,crossOrigin:l,href:i},u.querySelector(x)===null&&(i=u.createElement("link"),wn(i,"link",n),Ft(i),u.head.appendChild(i)))}}function lk(n){gi.D(n),O0("dns-prefetch",n,null)}function ok(n,i){gi.C(n,i),O0("preconnect",n,i)}function ck(n,i,l){gi.L(n,i,l);var u=Ms;if(u&&n&&i){var x='link[rel="preload"][as="'+Cn(i)+'"]';i==="image"&&l&&l.imageSrcSet?(x+='[imagesrcset="'+Cn(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(x+='[imagesizes="'+Cn(l.imageSizes)+'"]')):x+='[href="'+Cn(n)+'"]';var v=x;switch(i){case"style":v=Os(n);break;case"script":v=Rs(n)}gr.has(v)||(n=g({rel:"preload",href:i==="image"&&l&&l.imageSrcSet?void 0:n,as:i},l),gr.set(v,n),u.querySelector(x)!==null||i==="style"&&u.querySelector($l(v))||i==="script"&&u.querySelector(ql(v))||(i=u.createElement("link"),wn(i,"link",n),Ft(i),u.head.appendChild(i)))}}function uk(n,i){gi.m(n,i);var l=Ms;if(l&&n){var u=i&&typeof i.as=="string"?i.as:"script",x='link[rel="modulepreload"][as="'+Cn(u)+'"][href="'+Cn(n)+'"]',v=x;switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":v=Rs(n)}if(!gr.has(v)&&(n=g({rel:"modulepreload",href:n},i),gr.set(v,n),l.querySelector(x)===null)){switch(u){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ql(v)))return}u=l.createElement("link"),wn(u,"link",n),Ft(u),l.head.appendChild(u)}}}function dk(n,i,l){gi.S(n,i,l);var u=Ms;if(u&&n){var x=Br(u).hoistableStyles,v=Os(n);i=i||"default";var A=x.get(v);if(!A){var F={loading:0,preload:null};if(A=u.querySelector($l(v)))F.loading=5;else{n=g({rel:"stylesheet",href:n,"data-precedence":i},l),(l=gr.get(v))&&ih(n,l);var ne=A=u.createElement("link");Ft(ne),wn(ne,"link",n),ne._p=new Promise(function(le,he){ne.onload=le,ne.onerror=he}),ne.addEventListener("load",function(){F.loading|=1}),ne.addEventListener("error",function(){F.loading|=2}),F.loading|=4,Uc(A,i,u)}A={type:"stylesheet",instance:A,count:1,state:F},x.set(v,A)}}}function fk(n,i){gi.X(n,i);var l=Ms;if(l&&n){var u=Br(l).hoistableScripts,x=Rs(n),v=u.get(x);v||(v=l.querySelector(ql(x)),v||(n=g({src:n,async:!0},i),(i=gr.get(x))&&ah(n,i),v=l.createElement("script"),Ft(v),wn(v,"link",n),l.head.appendChild(v)),v={type:"script",instance:v,count:1,state:null},u.set(x,v))}}function hk(n,i){gi.M(n,i);var l=Ms;if(l&&n){var u=Br(l).hoistableScripts,x=Rs(n),v=u.get(x);v||(v=l.querySelector(ql(x)),v||(n=g({src:n,async:!0,type:"module"},i),(i=gr.get(x))&&ah(n,i),v=l.createElement("script"),Ft(v),wn(v,"link",n),l.head.appendChild(v)),v={type:"script",instance:v,count:1,state:null},u.set(x,v))}}function R0(n,i,l,u){var x=(x=Q.current)?Bc(x):null;if(!x)throw Error(a(446));switch(n){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(i=Os(l.href),l=Br(x).hoistableStyles,u=l.get(i),u||(u={type:"style",instance:null,count:0,state:null},l.set(i,u)),u):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){n=Os(l.href);var v=Br(x).hoistableStyles,A=v.get(n);if(A||(x=x.ownerDocument||x,A={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},v.set(n,A),(v=x.querySelector($l(n)))&&!v._p&&(A.instance=v,A.state.loading=5),gr.has(n)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},gr.set(n,l),v||mk(x,n,l,A.state))),i&&u===null)throw Error(a(528,""));return A}if(i&&u!==null)throw Error(a(529,""));return null;case"script":return i=l.async,l=l.src,typeof l=="string"&&i&&typeof i!="function"&&typeof i!="symbol"?(i=Rs(l),l=Br(x).hoistableScripts,u=l.get(i),u||(u={type:"script",instance:null,count:0,state:null},l.set(i,u)),u):{type:"void",instance:null,count:0,state:null};default:throw Error(a(444,n))}}function Os(n){return'href="'+Cn(n)+'"'}function $l(n){return'link[rel="stylesheet"]['+n+"]"}function j0(n){return g({},n,{"data-precedence":n.precedence,precedence:null})}function mk(n,i,l,u){n.querySelector('link[rel="preload"][as="style"]['+i+"]")?u.loading=1:(i=n.createElement("link"),u.preload=i,i.addEventListener("load",function(){return u.loading|=1}),i.addEventListener("error",function(){return u.loading|=2}),wn(i,"link",l),Ft(i),n.head.appendChild(i))}function Rs(n){return'[src="'+Cn(n)+'"]'}function ql(n){return"script[async]"+n}function D0(n,i,l){if(i.count++,i.instance===null)switch(i.type){case"style":var u=n.querySelector('style[data-href~="'+Cn(l.href)+'"]');if(u)return i.instance=u,Ft(u),u;var x=g({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return u=(n.ownerDocument||n).createElement("style"),Ft(u),wn(u,"style",x),Uc(u,l.precedence,n),i.instance=u;case"stylesheet":x=Os(l.href);var v=n.querySelector($l(x));if(v)return i.state.loading|=4,i.instance=v,Ft(v),v;u=j0(l),(x=gr.get(x))&&ih(u,x),v=(n.ownerDocument||n).createElement("link"),Ft(v);var A=v;return A._p=new Promise(function(F,ne){A.onload=F,A.onerror=ne}),wn(v,"link",u),i.state.loading|=4,Uc(v,l.precedence,n),i.instance=v;case"script":return v=Rs(l.src),(x=n.querySelector(ql(v)))?(i.instance=x,Ft(x),x):(u=l,(x=gr.get(v))&&(u=g({},l),ah(u,x)),n=n.ownerDocument||n,x=n.createElement("script"),Ft(x),wn(x,"link",u),n.head.appendChild(x),i.instance=x);case"void":return null;default:throw Error(a(443,i.type))}else i.type==="stylesheet"&&(i.state.loading&4)===0&&(u=i.instance,i.state.loading|=4,Uc(u,l.precedence,n));return i.instance}function Uc(n,i,l){for(var u=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),x=u.length?u[u.length-1]:null,v=x,A=0;A title"):null)}function pk(n,i,l){if(l===1||i.itemProp!=null)return!1;switch(n){case"meta":case"title":return!0;case"style":if(typeof i.precedence!="string"||typeof i.href!="string"||i.href==="")break;return!0;case"link":if(typeof i.rel!="string"||typeof i.href!="string"||i.href===""||i.onLoad||i.onError)break;switch(i.rel){case"stylesheet":return n=i.disabled,typeof i.precedence=="string"&&n==null;default:return!0}case"script":if(i.async&&typeof i.async!="function"&&typeof i.async!="symbol"&&!i.onLoad&&!i.onError&&i.src&&typeof i.src=="string")return!0}return!1}function I0(n){return!(n.type==="stylesheet"&&(n.state.loading&3)===0)}function gk(n,i,l,u){if(l.type==="stylesheet"&&(typeof u.media!="string"||matchMedia(u.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var x=Os(u.href),v=i.querySelector($l(x));if(v){i=v._p,i!==null&&typeof i=="object"&&typeof i.then=="function"&&(n.count++,n=$c.bind(n),i.then(n,n)),l.state.loading|=4,l.instance=v,Ft(v);return}v=i.ownerDocument||i,u=j0(u),(x=gr.get(x))&&ih(u,x),v=v.createElement("link"),Ft(v);var A=v;A._p=new Promise(function(F,ne){A.onload=F,A.onerror=ne}),wn(v,"link",u),l.instance=v}n.stylesheets===null&&(n.stylesheets=new Map),n.stylesheets.set(l,i),(i=l.state.preload)&&(l.state.loading&3)===0&&(n.count++,l=$c.bind(n),i.addEventListener("load",l),i.addEventListener("error",l))}}var sh=0;function xk(n,i){return n.stylesheets&&n.count===0&&Pc(n,n.stylesheets),0sh?50:800)+i);return n.unsuspend=l,function(){n.unsuspend=null,clearTimeout(u),clearTimeout(x)}}:null}function $c(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Pc(this,this.stylesheets);else if(this.unsuspend){var n=this.unsuspend;this.unsuspend=null,n()}}}var qc=null;function Pc(n,i){n.stylesheets=null,n.unsuspend!==null&&(n.count++,qc=new Map,i.forEach(bk,n),qc=null,$c.call(n))}function bk(n,i){if(!(i.state.loading&4)){var l=qc.get(n);if(l)var u=l.get(null);else{l=new Map,qc.set(n,l);for(var x=n.querySelectorAll("link[data-precedence],style[data-precedence]"),v=0;v"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),ph.exports=jk(),ph.exports}var Lk=Dk();/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const C_=(...e)=>e.filter((t,r,a)=>!!t&&t.trim()!==""&&a.indexOf(t)===r).join(" ").trim();/** + */const j_=(...e)=>e.filter((t,r,a)=>!!t&&t.trim()!==""&&a.indexOf(t)===r).join(" ").trim();/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Tk=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();/** + */const zk=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Ak=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,r,a)=>a?a.toUpperCase():r.toLowerCase());/** + */const Ik=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,r,a)=>a?a.toUpperCase():r.toLowerCase());/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const ny=e=>{const t=Ak(e);return t.charAt(0).toUpperCase()+t.slice(1)};/** + */const ly=e=>{const t=Ik(e);return t.charAt(0).toUpperCase()+t.slice(1)};/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */var Mk={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + */var Bk={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Ok=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0;return!1};/** + */const Uk=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0;return!1};/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Rk=ee.forwardRef(({color:e="currentColor",size:t=24,strokeWidth:r=2,absoluteStrokeWidth:a,className:s="",children:o,iconNode:c,...d},h)=>ee.createElement("svg",{ref:h,...Mk,width:t,height:t,stroke:e,strokeWidth:a?Number(r)*24/Number(t):r,className:C_("lucide",s),...!o&&!Ok(d)&&{"aria-hidden":"true"},...d},[...c.map(([f,m])=>ee.createElement(f,m)),...Array.isArray(o)?o:[o]]));/** + */const Hk=ee.forwardRef(({color:e="currentColor",size:t=24,strokeWidth:r=2,absoluteStrokeWidth:a,className:s="",children:o,iconNode:c,...d},f)=>ee.createElement("svg",{ref:f,...Bk,width:t,height:t,stroke:e,strokeWidth:a?Number(r)*24/Number(t):r,className:j_("lucide",s),...!o&&!Uk(d)&&{"aria-hidden":"true"},...d},[...c.map(([h,p])=>ee.createElement(h,p)),...Array.isArray(o)?o:[o]]));/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Me=(e,t)=>{const r=ee.forwardRef(({className:a,...s},o)=>ee.createElement(Rk,{ref:o,iconNode:t,className:C_(`lucide-${Tk(ny(e))}`,`lucide-${e}`,a),...s}));return r.displayName=ny(e),r};/** + */const Te=(e,t)=>{const r=ee.forwardRef(({className:a,...s},o)=>ee.createElement(Hk,{ref:o,iconNode:t,className:j_(`lucide-${zk(ly(e))}`,`lucide-${e}`,a),...s}));return r.displayName=ly(e),r};/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const jk=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],xp=Me("arrow-left",jk);/** + */const $k=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],Ep=Te("arrow-left",$k);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Dk=[["path",{d:"M7 7h10v10",key:"1tivn9"}],["path",{d:"M7 17 17 7",key:"1vkiza"}]],T_=Me("arrow-up-right",Dk);/** + */const qk=[["path",{d:"M7 7h10v10",key:"1tivn9"}],["path",{d:"M7 17 17 7",key:"1vkiza"}]],D_=Te("arrow-up-right",qk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Lk=[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]],zk=Me("arrow-up",Lk);/** + */const Pk=[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]],Fk=Te("arrow-up",Pk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Ik=[["path",{d:"M4.929 4.929 19.07 19.071",key:"196cmz"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],A_=Me("ban",Ik);/** + */const Gk=[["path",{d:"M4.929 4.929 19.07 19.071",key:"196cmz"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],L_=Te("ban",Gk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Bk=[["path",{d:"M10.268 21a2 2 0 0 0 3.464 0",key:"vwvbt9"}],["path",{d:"M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742",key:"178tsu"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05",key:"1hqiys"}]],Uk=Me("bell-off",Bk);/** + */const Vk=[["path",{d:"M10.268 21a2 2 0 0 0 3.464 0",key:"vwvbt9"}],["path",{d:"M17 17H4a1 1 0 0 1-.74-1.673C4.59 13.956 6 12.499 6 8a6 6 0 0 1 .258-1.742",key:"178tsu"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M8.668 3.01A6 6 0 0 1 18 8c0 2.687.77 4.653 1.707 6.05",key:"1hqiys"}]],Yk=Te("bell-off",Vk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Hk=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],Ao=Me("bot",Hk);/** + */const Xk=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],Mo=Te("bot",Xk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const $k=[["path",{d:"M12 18V5",key:"adv99a"}],["path",{d:"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4",key:"1e3is1"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5",key:"1gqd8o"}],["path",{d:"M17.997 5.125a4 4 0 0 1 2.526 5.77",key:"iwvgf7"}],["path",{d:"M18 18a4 4 0 0 0 2-7.464",key:"efp6ie"}],["path",{d:"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517",key:"1gq6am"}],["path",{d:"M6 18a4 4 0 0 1-2-7.464",key:"k1g0md"}],["path",{d:"M6.003 5.125a4 4 0 0 0-2.526 5.77",key:"q97ue3"}]],M_=Me("brain",$k);/** + */const Kk=[["path",{d:"M12 18V5",key:"adv99a"}],["path",{d:"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4",key:"1e3is1"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5",key:"1gqd8o"}],["path",{d:"M17.997 5.125a4 4 0 0 1 2.526 5.77",key:"iwvgf7"}],["path",{d:"M18 18a4 4 0 0 0 2-7.464",key:"efp6ie"}],["path",{d:"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517",key:"1gq6am"}],["path",{d:"M6 18a4 4 0 0 1-2-7.464",key:"k1g0md"}],["path",{d:"M6.003 5.125a4 4 0 0 0-2.526 5.77",key:"q97ue3"}]],z_=Te("brain",Kk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const qk=[["path",{d:"M16 14v2.2l1.6 1",key:"fo4ql5"}],["path",{d:"M16 2v4",key:"4m81vk"}],["path",{d:"M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5",key:"1osxxc"}],["path",{d:"M3 10h5",key:"r794hk"}],["path",{d:"M8 2v4",key:"1cmpym"}],["circle",{cx:"16",cy:"16",r:"6",key:"qoo3c4"}]],Pk=Me("calendar-clock",qk);/** + */const Zk=[["path",{d:"M16 14v2.2l1.6 1",key:"fo4ql5"}],["path",{d:"M16 2v4",key:"4m81vk"}],["path",{d:"M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5",key:"1osxxc"}],["path",{d:"M3 10h5",key:"r794hk"}],["path",{d:"M8 2v4",key:"1cmpym"}],["circle",{cx:"16",cy:"16",r:"6",key:"qoo3c4"}]],Qk=Te("calendar-clock",Zk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Fk=[["path",{d:"M18 6 7 17l-5-5",key:"116fxf"}],["path",{d:"m22 10-7.5 7.5L13 16",key:"ke71qq"}]],Gk=Me("check-check",Fk);/** + */const Wk=[["path",{d:"M18 6 7 17l-5-5",key:"116fxf"}],["path",{d:"m22 10-7.5 7.5L13 16",key:"ke71qq"}]],Jk=Te("check-check",Wk);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Vk=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Gs=Me("check",Vk);/** + */const eC=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Gs=Te("check",eC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Yk=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],ho=Me("chevron-down",Yk);/** + */const tC=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],mo=Te("chevron-down",tC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Xk=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],Kk=Me("chevron-right",Xk);/** + */const nC=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],rC=Te("chevron-right",nC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Zk=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],O_=Me("chevron-up",Zk);/** + */const iC=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],I_=Te("chevron-up",iC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Qk=[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]],Wk=Me("chevrons-up-down",Qk);/** + */const aC=[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]],sC=Te("chevrons-up-down",aC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Jk=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],Hu=Me("circle-alert",Jk);/** + */const lC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],Fu=Te("circle-alert",lC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const eC=[["path",{d:"M21.801 10A10 10 0 1 1 17 3.335",key:"yps3ct"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]],R_=Me("circle-check-big",eC);/** + */const oC=[["path",{d:"M21.801 10A10 10 0 1 1 17 3.335",key:"yps3ct"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]],B_=Te("circle-check-big",oC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const tC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],j_=Me("circle-check",tC);/** + */const cC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],wu=Te("circle-check",cC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const nC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],rC=Me("circle-dot",nC);/** + */const uC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}]],dC=Te("circle-dot",uC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const iC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],aC=Me("circle",iC);/** + */const fC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],hC=Te("circle-question-mark",fC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const sC=[["path",{d:"M12 6v6l4 2",key:"mmk7yg"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],D_=Me("clock",sC);/** + */const mC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"9",x2:"15",y1:"15",y2:"9",key:"1dfufj"}]],pC=Te("circle-slash",mC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const lC=[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]],oC=Me("code",lC);/** + */const gC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],U_=Te("circle",gC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const cC=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],mo=Me("copy",cC);/** + */const xC=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}],["path",{d:"M12 11h4",key:"1jrz19"}],["path",{d:"M12 16h4",key:"n85exb"}],["path",{d:"M8 11h.01",key:"1dfujw"}],["path",{d:"M8 16h.01",key:"18s6g9"}]],H_=Te("clipboard-list",xC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const uC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"22",x2:"18",y1:"12",y2:"12",key:"l9bcsi"}],["line",{x1:"6",x2:"2",y1:"12",y2:"12",key:"13hhkx"}],["line",{x1:"12",x2:"12",y1:"6",y2:"2",key:"10w3f3"}],["line",{x1:"12",x2:"12",y1:"22",y2:"18",key:"15g9kq"}]],dC=Me("crosshair",uC);/** + */const bC=[["path",{d:"M12 6v6l4 2",key:"mmk7yg"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],$_=Te("clock",bC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const fC=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],ry=Me("external-link",fC);/** + */const yC=[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]],vC=Te("code",yC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const hC=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],mC=Me("eye",hC);/** + */const _C=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],po=Te("copy",_C);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const pC=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],gC=Me("file-text",pC);/** + */const wC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"22",x2:"18",y1:"12",y2:"12",key:"l9bcsi"}],["line",{x1:"6",x2:"2",y1:"12",y2:"12",key:"13hhkx"}],["line",{x1:"12",x2:"12",y1:"6",y2:"2",key:"10w3f3"}],["line",{x1:"12",x2:"12",y1:"22",y2:"18",key:"15g9kq"}]],Gu=Te("crosshair",wC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const bC=[["path",{d:"M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528",key:"1jaruq"}]],L_=Me("flag",bC);/** + */const EC=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],oy=Te("external-link",EC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const xC=[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M6 21V9a9 9 0 0 0 9 9",key:"7kw0sc"}]],yC=Me("git-merge",xC);/** + */const NC=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],SC=Te("eye",NC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const vC=[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["line",{x1:"6",x2:"6",y1:"9",y2:"21",key:"rroup"}]],_C=Me("git-pull-request",vC);/** + */const kC=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],CC=Te("file-text",kC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const wC=[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]],EC=Me("github",wC);/** + */const TC=[["path",{d:"M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528",key:"1jaruq"}]],q_=Te("flag",TC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const NC=[["path",{d:"m22 13.29-3.33-10a.42.42 0 0 0-.14-.18.38.38 0 0 0-.22-.11.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18l-2.26 6.67H8.32L6.1 3.26a.42.42 0 0 0-.1-.18.38.38 0 0 0-.26-.08.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18L2 13.29a.74.74 0 0 0 .27.83L12 21l9.69-6.88a.71.71 0 0 0 .31-.83Z",key:"148pdi"}]],SC=Me("gitlab",NC);/** + */const AC=[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M6 21V9a9 9 0 0 0 9 9",key:"7kw0sc"}]],MC=Te("git-merge",AC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const kC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],z_=Me("globe",kC);/** + */const OC=[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["line",{x1:"6",x2:"6",y1:"9",y2:"21",key:"rroup"}]],RC=Te("git-pull-request",OC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const CC=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]],Vs=Me("history",CC);/** + */const jC=[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]],DC=Te("github",jC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const TC=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],AC=Me("image",TC);/** + */const LC=[["path",{d:"m22 13.29-3.33-10a.42.42 0 0 0-.14-.18.38.38 0 0 0-.22-.11.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18l-2.26 6.67H8.32L6.1 3.26a.42.42 0 0 0-.1-.18.38.38 0 0 0-.26-.08.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18L2 13.29a.74.74 0 0 0 .27.83L12 21l9.69-6.88a.71.71 0 0 0 .31-.83Z",key:"148pdi"}]],zC=Te("gitlab",LC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const MC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],OC=Me("info",MC);/** + */const IC=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]],P_=Te("globe",IC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const RC=[["path",{d:"M13 5h8",key:"a7qcls"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 19h8",key:"c3s6r1"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["rect",{x:"3",y:"4",width:"6",height:"6",rx:"1",key:"cif1o7"}]],jC=Me("list-todo",RC);/** + */const BC=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]],Vs=Te("history",BC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const DC=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],qs=Me("loader-circle",DC);/** + */const UC=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],HC=Te("image",UC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const LC=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],zC=Me("lock",LC);/** + */const $C=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],qC=Te("info",$C);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const IC=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],BC=Me("log-out",IC);/** + */const PC=[["path",{d:"M13 5h8",key:"a7qcls"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 19h8",key:"c3s6r1"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["rect",{x:"3",y:"4",width:"6",height:"6",rx:"1",key:"cif1o7"}]],FC=Te("list-todo",PC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const UC=[["path",{d:"m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7",key:"132q7q"}],["rect",{x:"2",y:"4",width:"20",height:"16",rx:"2",key:"izxlao"}]],yp=Me("mail",UC);/** + */const GC=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],qs=Te("loader-circle",GC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const HC=[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",key:"1sd12s"}]],mh=Me("message-circle",HC);/** + */const VC=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],YC=Te("lock",VC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const $C=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],qC=Me("pencil",$C);/** + */const XC=[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]],KC=Te("log-out",XC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const PC=[["path",{d:"M12 22v-5",key:"1ega77"}],["path",{d:"M15 8V2",key:"18g5xt"}],["path",{d:"M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z",key:"1xoxul"}],["path",{d:"M9 8V2",key:"14iosj"}]],FC=Me("plug",PC);/** + */const ZC=[["path",{d:"m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7",key:"132q7q"}],["rect",{x:"2",y:"4",width:"20",height:"16",rx:"2",key:"izxlao"}]],Np=Te("mail",ZC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const GC=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],VC=Me("plus",GC);/** + */const QC=[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",key:"1sd12s"}]],yh=Te("message-circle",QC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const YC=[["path",{d:"M19.07 4.93A10 10 0 0 0 6.99 3.34",key:"z3du51"}],["path",{d:"M4 6h.01",key:"oypzma"}],["path",{d:"M2.29 9.62A10 10 0 1 0 21.31 8.35",key:"qzzz0"}],["path",{d:"M16.24 7.76A6 6 0 1 0 8.23 16.67",key:"1yjesh"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M17.99 11.66A6 6 0 0 1 15.77 16.67",key:"1u2y91"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}],["path",{d:"m13.41 10.59 5.66-5.66",key:"mhq4k0"}]],XC=Me("radar",YC);/** + */const WC=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],JC=Te("pencil",WC);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const KC=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],ZC=Me("refresh-cw",KC);/** + */const eT=[["path",{d:"M12 22v-5",key:"1ega77"}],["path",{d:"M15 8V2",key:"18g5xt"}],["path",{d:"M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z",key:"1xoxul"}],["path",{d:"M9 8V2",key:"14iosj"}]],tT=Te("plug",eT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const QC=[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]],WC=Me("rocket",QC);/** + */const nT=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],F_=Te("plus",nT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const JC=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],eT=Me("rotate-ccw",JC);/** + */const rT=[["path",{d:"M19.07 4.93A10 10 0 0 0 6.99 3.34",key:"z3du51"}],["path",{d:"M4 6h.01",key:"oypzma"}],["path",{d:"M2.29 9.62A10 10 0 1 0 21.31 8.35",key:"qzzz0"}],["path",{d:"M16.24 7.76A6 6 0 1 0 8.23 16.67",key:"1yjesh"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M17.99 11.66A6 6 0 0 1 15.77 16.67",key:"1u2y91"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}],["path",{d:"m13.41 10.59 5.66-5.66",key:"mhq4k0"}]],iT=Te("radar",rT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const tT=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],nT=Me("search",tT);/** + */const aT=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],sT=Te("refresh-cw",aT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const rT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]],iT=Me("shield-alert",rT);/** + */const lT=[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]],oT=Te("rocket",lT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const aT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],I_=Me("shield-check",aT);/** + */const cT=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],uT=Te("rotate-ccw",cT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const sT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]],lT=Me("shield",sT);/** + */const dT=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],fT=Te("save",dT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const oT=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],Um=Me("sparkles",oT);/** + */const hT=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],mT=Te("search",hT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const cT=[["path",{d:"M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",key:"1dfntj"}],["path",{d:"M15 3v5a1 1 0 0 0 1 1h5",key:"6s6qgf"}]],uT=Me("sticky-note",cT);/** + */const pT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]],gT=Te("shield-alert",pT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const dT=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],B_=Me("terminal",dT);/** + */const xT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],G_=Te("shield-check",xT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const fT=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],hT=Me("trash-2",fT);/** + */const bT=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]],yT=Te("shield",bT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const mT=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],pT=Me("triangle-alert",mT);/** + */const vT=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],Fm=Te("sparkles",vT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const gT=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],bT=Me("users",gT);/** + */const _T=[["path",{d:"M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",key:"1dfntj"}],["path",{d:"M15 3v5a1 1 0 0 0 1 1h5",key:"6s6qgf"}]],wT=Te("sticky-note",_T);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const xT=[["path",{d:"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72",key:"ul74o6"}],["path",{d:"m14 7 3 3",key:"1r5n42"}],["path",{d:"M5 6v4",key:"ilb8ba"}],["path",{d:"M19 14v4",key:"blhpug"}],["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M7 8H3",key:"zfb6yr"}],["path",{d:"M21 16h-4",key:"1cnmox"}],["path",{d:"M11 3H9",key:"1obp7u"}]],yT=Me("wand-sparkles",xT);/** + */const ET=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],V_=Te("terminal",ET);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const vT=[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",key:"1ngwbx"}]],Hm=Me("wrench",vT);/** + */const NT=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],ST=Te("trash-2",NT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const _T=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],vp=Me("x",_T);/** + */const kT=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],Eu=Te("triangle-alert",kT);/** * @license lucide-react v0.563.0 - ISC * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const wT=[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]],ET=Me("zap",wT),NT={open:{label:"Open",color:"bg-red-500/10 text-red-400 border-red-500/20",dotColor:"bg-red-500",description:"Newly discovered, awaiting triage"},in_progress:{label:"In Progress",color:"bg-blue-500/10 text-blue-400 border-blue-500/20",dotColor:"bg-blue-500",description:"Someone is working on this"},snoozed:{label:"Snoozed",color:"bg-purple-500/10 text-purple-400 border-purple-500/20",dotColor:"bg-purple-500",description:"Temporarily hidden until a follow-up date"},fixed:{label:"Fixed",color:"bg-emerald-500/10 text-emerald-400 border-emerald-500/20",dotColor:"bg-emerald-500",description:"This vulnerability has been fixed"},ignored:{label:"Ignored",color:"bg-gray-500/10 text-gray-400 border-gray-500/20",dotColor:"bg-gray-500",description:"Acknowledged but accepted"}},ST={trivial:{label:"Trivial",color:"bg-emerald-500/10 text-emerald-400 border-emerald-500/20"},low:{label:"Low",color:"bg-blue-500/10 text-blue-400 border-blue-500/20"},medium:{label:"Medium",color:"bg-yellow-500/10 text-yellow-400 border-yellow-500/20"},high:{label:"High",color:"bg-orange-500/10 text-orange-400 border-orange-500/20"}},U_={critical:"bg-red-500/20 text-red-500 border-red-500/30",high:"bg-orange-500/20 text-orange-500 border-orange-500/30",medium:"bg-yellow-500/20 text-yellow-500 border-yellow-500/30",low:"bg-blue-500/20 text-blue-500 border-blue-500/30"};function Zc(e){return e.original_severity!=null&&e.original_severity!==e.severity}const kT={js:"javascript",ts:"typescript",tsx:"typescript",jsx:"javascript",py:"python",rb:"ruby",go:"go",rs:"rust",java:"java",php:"php",cs:"csharp",cpp:"cpp",c:"c",sh:"bash",bash:"bash",sql:"sql",html:"html",css:"css",json:"json",yaml:"yaml",yml:"yaml",xml:"xml"};function CT(e){var r;if(!e)return null;const t=(r=e.split(".").pop())==null?void 0:r.toLowerCase();return t&&kT[t]||null}function _p(e){switch(e){case"critical":return"bg-red-500";case"high":return"bg-orange-500";case"medium":return"bg-yellow-500";default:return"bg-blue-500"}}async function wp(e){try{await navigator.clipboard.writeText(e)}catch{const t=document.createElement("textarea");t.value=e,t.style.position="absolute",t.style.left="-9999px",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}}const $u="https://app.strix.ai/api/auth/signup",TT="https://strix.ai/pricing",AT="ref=oss_viewer&utm_source=oss_viewer&utm_medium=local_viewer&utm_campaign=oss_viewer";function ha(e,t){const r=e.includes("?")?"&":"?";return`${e}${r}${AT}&utm_content=${encodeURIComponent(t)}`}function Tr(e,t={}){try{const r={event:e};for(const[s,o]of Object.entries(t))o!==void 0&&(r[s]=o);const a=JSON.stringify(r);typeof navigator<"u"&&navigator.sendBeacon?navigator.sendBeacon("/api/event",a):fetch("/api/event",{method:"POST",body:a,keepalive:!0})}catch{}}function jr(e,t){Tr("cta_clicked",{cta:e,surface:t})}function H_(e){var t,r,a="";if(typeof e=="string"||typeof e=="number")a+=e;else if(typeof e=="object")if(Array.isArray(e)){var s=e.length;for(t=0;t{const r=new Array(e.length+t.length);for(let a=0;a({classGroupId:e,validator:t}),$_=(e=new Map,t=null,r)=>({nextPart:e,validators:t,classGroupId:r}),vu="-",iy=[],jT="arbitrary..",DT=e=>{const t=zT(e),{conflictingClassGroups:r,conflictingClassGroupModifiers:a}=e;return{getClassGroupId:c=>{if(c.startsWith("[")&&c.endsWith("]"))return LT(c);const d=c.split(vu),h=d[0]===""&&d.length>1?1:0;return q_(d,h,t)},getConflictingClassGroupIds:(c,d)=>{if(d){const h=a[c],f=r[c];return h?f?OT(f,h):h:f||iy}return r[c]||iy}}},q_=(e,t,r)=>{if(e.length-t===0)return r.classGroupId;const s=e[t],o=r.nextPart.get(s);if(o){const f=q_(e,t+1,o);if(f)return f}const c=r.validators;if(c===null)return;const d=t===0?e.join(vu):e.slice(t).join(vu),h=c.length;for(let f=0;fe.slice(1,-1).indexOf(":")===-1?void 0:(()=>{const t=e.slice(1,-1),r=t.indexOf(":"),a=t.slice(0,r);return a?jT+a:void 0})(),zT=e=>{const{theme:t,classGroups:r}=e;return IT(r,t)},IT=(e,t)=>{const r=$_();for(const a in e){const s=e[a];Ep(s,r,a,t)}return r},Ep=(e,t,r,a)=>{const s=e.length;for(let o=0;o{if(typeof e=="string"){UT(e,t,r);return}if(typeof e=="function"){HT(e,t,r,a);return}$T(e,t,r,a)},UT=(e,t,r)=>{const a=e===""?t:P_(t,e);a.classGroupId=r},HT=(e,t,r,a)=>{if(qT(e)){Ep(e(a),t,r,a);return}t.validators===null&&(t.validators=[]),t.validators.push(RT(r,e))},$T=(e,t,r,a)=>{const s=Object.entries(e),o=s.length;for(let c=0;c{let r=e;const a=t.split(vu),s=a.length;for(let o=0;o"isThemeGetter"in e&&e.isThemeGetter===!0,PT=e=>{if(e<1)return{get:()=>{},set:()=>{}};let t=0,r=Object.create(null),a=Object.create(null);const s=(o,c)=>{r[o]=c,t++,t>e&&(t=0,a=r,r=Object.create(null))};return{get(o){let c=r[o];if(c!==void 0)return c;if((c=a[o])!==void 0)return s(o,c),c},set(o,c){o in r?r[o]=c:s(o,c)}}},$m="!",ay=":",FT=[],sy=(e,t,r,a,s)=>({modifiers:e,hasImportantModifier:t,baseClassName:r,maybePostfixModifierPosition:a,isExternal:s}),GT=e=>{const{prefix:t,experimentalParseClassName:r}=e;let a=s=>{const o=[];let c=0,d=0,h=0,f;const m=s.length;for(let N=0;Nh?f-h:void 0;return sy(o,x,y,_)};if(t){const s=t+ay,o=a;a=c=>c.startsWith(s)?o(c.slice(s.length)):sy(FT,!1,c,void 0,!0)}if(r){const s=a;a=o=>r({className:o,parseClassName:s})}return a},VT=e=>{const t=new Map;return e.orderSensitiveModifiers.forEach((r,a)=>{t.set(r,1e6+a)}),r=>{const a=[];let s=[];for(let o=0;o0&&(s.sort(),a.push(...s),s=[]),a.push(c)):s.push(c)}return s.length>0&&(s.sort(),a.push(...s)),a}},YT=e=>({cache:PT(e.cacheSize),parseClassName:GT(e),sortModifiers:VT(e),postfixLookupClassGroupIds:XT(e),...DT(e)}),XT=e=>{const t=Object.create(null),r=e.postfixLookupClassGroups;if(r)for(let a=0;a{const{parseClassName:r,getClassGroupId:a,getConflictingClassGroupIds:s,sortModifiers:o,postfixLookupClassGroupIds:c}=t,d=[],h=e.trim().split(KT);let f="";for(let m=h.length-1;m>=0;m-=1){const p=h[m],{isExternal:y,modifiers:x,hasImportantModifier:_,baseClassName:N,maybePostfixModifierPosition:S}=r(p);if(y){f=p+(f.length>0?" "+f:f);continue}let w=!!S,k;if(w){const U=N.substring(0,S);k=a(U);const B=k&&c[k]?a(N):void 0;B&&B!==k&&(k=B,w=!1)}else k=a(N);if(!k){if(!w){f=p+(f.length>0?" "+f:f);continue}if(k=a(N),!k){f=p+(f.length>0?" "+f:f);continue}w=!1}const E=x.length===0?"":x.length===1?x[0]:o(x).join(":"),M=_?E+$m:E,I=M+k;if(d.indexOf(I)>-1)continue;d.push(I);const R=s(k,w);for(let U=0;U0?" "+f:f)}return f},QT=(...e)=>{let t=0,r,a,s="";for(;t{if(typeof e=="string")return e;let t,r="";for(let a=0;a{let r,a,s,o;const c=h=>{const f=t.reduce((m,p)=>p(m),e());return r=YT(f),a=r.cache.get,s=r.cache.set,o=d,d(h)},d=h=>{const f=a(h);if(f)return f;const m=ZT(h,r);return s(h,m),m};return o=c,(...h)=>o(QT(...h))},JT=[],fn=e=>{const t=r=>r[e]||JT;return t.isThemeGetter=!0,t},G_=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,V_=/^\((?:(\w[\w-]*):)?(.+)\)$/i,eA=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,tA=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,nA=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,rA=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,iA=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,aA=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,ra=e=>eA.test(e),We=e=>!!e&&!Number.isNaN(Number(e)),Fr=e=>!!e&&Number.isInteger(Number(e)),ph=e=>e.endsWith("%")&&We(e.slice(0,-1)),bi=e=>tA.test(e),Y_=()=>!0,sA=e=>nA.test(e)&&!rA.test(e),Np=()=>!1,lA=e=>iA.test(e),oA=e=>aA.test(e),cA=e=>!ke(e)&&!Ce(e),uA=e=>e.startsWith("@container")&&(e[10]==="/"&&e[11]!==void 0||e[11]==="s"&&e[16]!==void 0&&e.startsWith("-size/",10)||e[11]==="n"&&e[18]!==void 0&&e.startsWith("-normal/",10)),dA=e=>ma(e,Z_,Np),ke=e=>G_.test(e),za=e=>ma(e,Q_,sA),ly=e=>ma(e,yA,We),fA=e=>ma(e,J_,Y_),hA=e=>ma(e,W_,Np),oy=e=>ma(e,X_,Np),mA=e=>ma(e,K_,oA),Qc=e=>ma(e,ew,lA),Ce=e=>V_.test(e),Kl=e=>Qa(e,Q_),pA=e=>Qa(e,W_),cy=e=>Qa(e,X_),gA=e=>Qa(e,Z_),bA=e=>Qa(e,K_),Wc=e=>Qa(e,ew,!0),xA=e=>Qa(e,J_,!0),ma=(e,t,r)=>{const a=G_.exec(e);return a?a[1]?t(a[1]):r(a[2]):!1},Qa=(e,t,r=!1)=>{const a=V_.exec(e);return a?a[1]?t(a[1]):r:!1},X_=e=>e==="position"||e==="percentage",K_=e=>e==="image"||e==="url",Z_=e=>e==="length"||e==="size"||e==="bg-size",Q_=e=>e==="length",yA=e=>e==="number",W_=e=>e==="family-name",J_=e=>e==="number"||e==="weight",ew=e=>e==="shadow",vA=()=>{const e=fn("color"),t=fn("font"),r=fn("text"),a=fn("font-weight"),s=fn("tracking"),o=fn("leading"),c=fn("breakpoint"),d=fn("container"),h=fn("spacing"),f=fn("radius"),m=fn("shadow"),p=fn("inset-shadow"),y=fn("text-shadow"),x=fn("drop-shadow"),_=fn("blur"),N=fn("perspective"),S=fn("aspect"),w=fn("ease"),k=fn("animate"),E=()=>["auto","avoid","all","avoid-page","page","left","right","column"],M=()=>["center","top","bottom","left","right","top-left","left-top","top-right","right-top","bottom-right","right-bottom","bottom-left","left-bottom"],I=()=>[...M(),Ce,ke],R=()=>["auto","hidden","clip","visible","scroll"],U=()=>["auto","contain","none"],B=()=>[Ce,ke,h],Z=()=>[ra,"full","auto",...B()],j=()=>[Fr,"none","subgrid",Ce,ke],z=()=>["auto",{span:["full",Fr,Ce,ke]},Fr,Ce,ke],V=()=>[Fr,"auto",Ce,ke],P=()=>["auto","min","max","fr",Ce,ke],T=()=>["start","end","center","between","around","evenly","stretch","baseline","center-safe","end-safe"],$=()=>["start","end","center","stretch","center-safe","end-safe"],O=()=>["auto",...B()],H=()=>[ra,"auto","full","dvw","dvh","lvw","lvh","svw","svh","min","max","fit",...B()],X=()=>[ra,"screen","full","dvw","lvw","svw","min","max","fit",...B()],K=()=>[ra,"screen","full","lh","dvh","lvh","svh","min","max","fit",...B()],C=()=>[e,Ce,ke],D=()=>[...M(),cy,oy,{position:[Ce,ke]}],Y=()=>["no-repeat",{repeat:["","x","y","space","round"]}],L=()=>["auto","cover","contain",gA,dA,{size:[Ce,ke]}],G=()=>[ph,Kl,za],q=()=>["","none","full",f,Ce,ke],Q=()=>["",We,Kl,za],J=()=>["solid","dashed","dotted","double"],W=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],te=()=>[We,ph,cy,oy],ce=()=>["","none",_,Ce,ke],fe=()=>["none",We,Ce,ke],be=()=>["none",We,Ce,ke],we=()=>[We,Ce,ke],Ne=()=>[ra,"full",...B()];return{cacheSize:500,theme:{animate:["spin","ping","pulse","bounce"],aspect:["video"],blur:[bi],breakpoint:[bi],color:[Y_],container:[bi],"drop-shadow":[bi],ease:["in","out","in-out"],font:[cA],"font-weight":["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"],"inset-shadow":[bi],leading:["none","tight","snug","normal","relaxed","loose"],perspective:["dramatic","near","normal","midrange","distant","none"],radius:[bi],shadow:[bi],spacing:["px",We],text:[bi],"text-shadow":[bi],tracking:["tighter","tight","normal","wide","wider","widest"]},classGroups:{aspect:[{aspect:["auto","square",ra,ke,Ce,S]}],container:["container"],"container-type":[{"@container":["","normal","size",Ce,ke]}],"container-named":[uA],columns:[{columns:[We,ke,Ce,d]}],"break-after":[{"break-after":E()}],"break-before":[{"break-before":E()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],sr:["sr-only","not-sr-only"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:I()}],overflow:[{overflow:R()}],"overflow-x":[{"overflow-x":R()}],"overflow-y":[{"overflow-y":R()}],overscroll:[{overscroll:U()}],"overscroll-x":[{"overscroll-x":U()}],"overscroll-y":[{"overscroll-y":U()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:Z()}],"inset-x":[{"inset-x":Z()}],"inset-y":[{"inset-y":Z()}],start:[{"inset-s":Z(),start:Z()}],end:[{"inset-e":Z(),end:Z()}],"inset-bs":[{"inset-bs":Z()}],"inset-be":[{"inset-be":Z()}],top:[{top:Z()}],right:[{right:Z()}],bottom:[{bottom:Z()}],left:[{left:Z()}],visibility:["visible","invisible","collapse"],z:[{z:[Fr,"auto",Ce,ke]}],basis:[{basis:[ra,"full","auto",d,...B()]}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["nowrap","wrap","wrap-reverse"]}],flex:[{flex:[We,ra,"auto","initial","none",ke]}],grow:[{grow:["",We,Ce,ke]}],shrink:[{shrink:["",We,Ce,ke]}],order:[{order:[Fr,"first","last","none",Ce,ke]}],"grid-cols":[{"grid-cols":j()}],"col-start-end":[{col:z()}],"col-start":[{"col-start":V()}],"col-end":[{"col-end":V()}],"grid-rows":[{"grid-rows":j()}],"row-start-end":[{row:z()}],"row-start":[{"row-start":V()}],"row-end":[{"row-end":V()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":P()}],"auto-rows":[{"auto-rows":P()}],gap:[{gap:B()}],"gap-x":[{"gap-x":B()}],"gap-y":[{"gap-y":B()}],"justify-content":[{justify:[...T(),"normal"]}],"justify-items":[{"justify-items":[...$(),"normal"]}],"justify-self":[{"justify-self":["auto",...$()]}],"align-content":[{content:["normal",...T()]}],"align-items":[{items:[...$(),{baseline:["","last"]}]}],"align-self":[{self:["auto",...$(),{baseline:["","last"]}]}],"place-content":[{"place-content":T()}],"place-items":[{"place-items":[...$(),"baseline"]}],"place-self":[{"place-self":["auto",...$()]}],p:[{p:B()}],px:[{px:B()}],py:[{py:B()}],ps:[{ps:B()}],pe:[{pe:B()}],pbs:[{pbs:B()}],pbe:[{pbe:B()}],pt:[{pt:B()}],pr:[{pr:B()}],pb:[{pb:B()}],pl:[{pl:B()}],m:[{m:O()}],mx:[{mx:O()}],my:[{my:O()}],ms:[{ms:O()}],me:[{me:O()}],mbs:[{mbs:O()}],mbe:[{mbe:O()}],mt:[{mt:O()}],mr:[{mr:O()}],mb:[{mb:O()}],ml:[{ml:O()}],"space-x":[{"space-x":B()}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":B()}],"space-y-reverse":["space-y-reverse"],size:[{size:H()}],"inline-size":[{inline:["auto",...X()]}],"min-inline-size":[{"min-inline":["auto",...X()]}],"max-inline-size":[{"max-inline":["none",...X()]}],"block-size":[{block:["auto",...K()]}],"min-block-size":[{"min-block":["auto",...K()]}],"max-block-size":[{"max-block":["none",...K()]}],w:[{w:[d,"screen",...H()]}],"min-w":[{"min-w":[d,"screen","none",...H()]}],"max-w":[{"max-w":[d,"screen","none","prose",{screen:[c]},...H()]}],h:[{h:["screen","lh",...H()]}],"min-h":[{"min-h":["screen","lh","none",...H()]}],"max-h":[{"max-h":["screen","lh",...H()]}],"font-size":[{text:["base",r,Kl,za]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:[a,xA,fA]}],"font-stretch":[{"font-stretch":["ultra-condensed","extra-condensed","condensed","semi-condensed","normal","semi-expanded","expanded","extra-expanded","ultra-expanded",ph,ke]}],"font-family":[{font:[pA,hA,t]}],"font-features":[{"font-features":[ke]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:[s,Ce,ke]}],"line-clamp":[{"line-clamp":[We,"none",Ce,ly]}],leading:[{leading:[o,...B()]}],"list-image":[{"list-image":["none",Ce,ke]}],"list-style-position":[{list:["inside","outside"]}],"list-style-type":[{list:["disc","decimal","none",Ce,ke]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"placeholder-color":[{placeholder:C()}],"text-color":[{text:C()}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...J(),"wavy"]}],"text-decoration-thickness":[{decoration:[We,"from-font","auto",Ce,za]}],"text-decoration-color":[{decoration:C()}],"underline-offset":[{"underline-offset":[We,"auto",Ce,ke]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:B()}],"tab-size":[{tab:[Fr,Ce,ke]}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",Ce,ke]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],wrap:[{wrap:["break-word","anywhere","normal"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",Ce,ke]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:D()}],"bg-repeat":[{bg:Y()}],"bg-size":[{bg:L()}],"bg-image":[{bg:["none",{linear:[{to:["t","tr","r","br","b","bl","l","tl"]},Fr,Ce,ke],radial:["",Ce,ke],conic:[Fr,Ce,ke]},bA,mA]}],"bg-color":[{bg:C()}],"gradient-from-pos":[{from:G()}],"gradient-via-pos":[{via:G()}],"gradient-to-pos":[{to:G()}],"gradient-from":[{from:C()}],"gradient-via":[{via:C()}],"gradient-to":[{to:C()}],rounded:[{rounded:q()}],"rounded-s":[{"rounded-s":q()}],"rounded-e":[{"rounded-e":q()}],"rounded-t":[{"rounded-t":q()}],"rounded-r":[{"rounded-r":q()}],"rounded-b":[{"rounded-b":q()}],"rounded-l":[{"rounded-l":q()}],"rounded-ss":[{"rounded-ss":q()}],"rounded-se":[{"rounded-se":q()}],"rounded-ee":[{"rounded-ee":q()}],"rounded-es":[{"rounded-es":q()}],"rounded-tl":[{"rounded-tl":q()}],"rounded-tr":[{"rounded-tr":q()}],"rounded-br":[{"rounded-br":q()}],"rounded-bl":[{"rounded-bl":q()}],"border-w":[{border:Q()}],"border-w-x":[{"border-x":Q()}],"border-w-y":[{"border-y":Q()}],"border-w-s":[{"border-s":Q()}],"border-w-e":[{"border-e":Q()}],"border-w-bs":[{"border-bs":Q()}],"border-w-be":[{"border-be":Q()}],"border-w-t":[{"border-t":Q()}],"border-w-r":[{"border-r":Q()}],"border-w-b":[{"border-b":Q()}],"border-w-l":[{"border-l":Q()}],"divide-x":[{"divide-x":Q()}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":Q()}],"divide-y-reverse":["divide-y-reverse"],"border-style":[{border:[...J(),"hidden","none"]}],"divide-style":[{divide:[...J(),"hidden","none"]}],"border-color":[{border:C()}],"border-color-x":[{"border-x":C()}],"border-color-y":[{"border-y":C()}],"border-color-s":[{"border-s":C()}],"border-color-e":[{"border-e":C()}],"border-color-bs":[{"border-bs":C()}],"border-color-be":[{"border-be":C()}],"border-color-t":[{"border-t":C()}],"border-color-r":[{"border-r":C()}],"border-color-b":[{"border-b":C()}],"border-color-l":[{"border-l":C()}],"divide-color":[{divide:C()}],"outline-style":[{outline:[...J(),"none","hidden"]}],"outline-offset":[{"outline-offset":[We,Ce,ke]}],"outline-w":[{outline:["",We,Kl,za]}],"outline-color":[{outline:C()}],shadow:[{shadow:["","none",m,Wc,Qc]}],"shadow-color":[{shadow:C()}],"inset-shadow":[{"inset-shadow":["none",p,Wc,Qc]}],"inset-shadow-color":[{"inset-shadow":C()}],"ring-w":[{ring:Q()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:C()}],"ring-offset-w":[{"ring-offset":[We,za]}],"ring-offset-color":[{"ring-offset":C()}],"inset-ring-w":[{"inset-ring":Q()}],"inset-ring-color":[{"inset-ring":C()}],"text-shadow":[{"text-shadow":["none",y,Wc,Qc]}],"text-shadow-color":[{"text-shadow":C()}],opacity:[{opacity:[We,Ce,ke]}],"mix-blend":[{"mix-blend":[...W(),"plus-darker","plus-lighter"]}],"bg-blend":[{"bg-blend":W()}],"mask-clip":[{"mask-clip":["border","padding","content","fill","stroke","view"]},"mask-no-clip"],"mask-composite":[{mask:["add","subtract","intersect","exclude"]}],"mask-image-linear-pos":[{"mask-linear":[We]}],"mask-image-linear-from-pos":[{"mask-linear-from":te()}],"mask-image-linear-to-pos":[{"mask-linear-to":te()}],"mask-image-linear-from-color":[{"mask-linear-from":C()}],"mask-image-linear-to-color":[{"mask-linear-to":C()}],"mask-image-t-from-pos":[{"mask-t-from":te()}],"mask-image-t-to-pos":[{"mask-t-to":te()}],"mask-image-t-from-color":[{"mask-t-from":C()}],"mask-image-t-to-color":[{"mask-t-to":C()}],"mask-image-r-from-pos":[{"mask-r-from":te()}],"mask-image-r-to-pos":[{"mask-r-to":te()}],"mask-image-r-from-color":[{"mask-r-from":C()}],"mask-image-r-to-color":[{"mask-r-to":C()}],"mask-image-b-from-pos":[{"mask-b-from":te()}],"mask-image-b-to-pos":[{"mask-b-to":te()}],"mask-image-b-from-color":[{"mask-b-from":C()}],"mask-image-b-to-color":[{"mask-b-to":C()}],"mask-image-l-from-pos":[{"mask-l-from":te()}],"mask-image-l-to-pos":[{"mask-l-to":te()}],"mask-image-l-from-color":[{"mask-l-from":C()}],"mask-image-l-to-color":[{"mask-l-to":C()}],"mask-image-x-from-pos":[{"mask-x-from":te()}],"mask-image-x-to-pos":[{"mask-x-to":te()}],"mask-image-x-from-color":[{"mask-x-from":C()}],"mask-image-x-to-color":[{"mask-x-to":C()}],"mask-image-y-from-pos":[{"mask-y-from":te()}],"mask-image-y-to-pos":[{"mask-y-to":te()}],"mask-image-y-from-color":[{"mask-y-from":C()}],"mask-image-y-to-color":[{"mask-y-to":C()}],"mask-image-radial":[{"mask-radial":[Ce,ke]}],"mask-image-radial-from-pos":[{"mask-radial-from":te()}],"mask-image-radial-to-pos":[{"mask-radial-to":te()}],"mask-image-radial-from-color":[{"mask-radial-from":C()}],"mask-image-radial-to-color":[{"mask-radial-to":C()}],"mask-image-radial-shape":[{"mask-radial":["circle","ellipse"]}],"mask-image-radial-size":[{"mask-radial":[{closest:["side","corner"],farthest:["side","corner"]}]}],"mask-image-radial-pos":[{"mask-radial-at":M()}],"mask-image-conic-pos":[{"mask-conic":[We]}],"mask-image-conic-from-pos":[{"mask-conic-from":te()}],"mask-image-conic-to-pos":[{"mask-conic-to":te()}],"mask-image-conic-from-color":[{"mask-conic-from":C()}],"mask-image-conic-to-color":[{"mask-conic-to":C()}],"mask-mode":[{mask:["alpha","luminance","match"]}],"mask-origin":[{"mask-origin":["border","padding","content","fill","stroke","view"]}],"mask-position":[{mask:D()}],"mask-repeat":[{mask:Y()}],"mask-size":[{mask:L()}],"mask-type":[{"mask-type":["alpha","luminance"]}],"mask-image":[{mask:["none",Ce,ke]}],filter:[{filter:["","none",Ce,ke]}],blur:[{blur:ce()}],brightness:[{brightness:[We,Ce,ke]}],contrast:[{contrast:[We,Ce,ke]}],"drop-shadow":[{"drop-shadow":["","none",x,Wc,Qc]}],"drop-shadow-color":[{"drop-shadow":C()}],grayscale:[{grayscale:["",We,Ce,ke]}],"hue-rotate":[{"hue-rotate":[We,Ce,ke]}],invert:[{invert:["",We,Ce,ke]}],saturate:[{saturate:[We,Ce,ke]}],sepia:[{sepia:["",We,Ce,ke]}],"backdrop-filter":[{"backdrop-filter":["","none",Ce,ke]}],"backdrop-blur":[{"backdrop-blur":ce()}],"backdrop-brightness":[{"backdrop-brightness":[We,Ce,ke]}],"backdrop-contrast":[{"backdrop-contrast":[We,Ce,ke]}],"backdrop-grayscale":[{"backdrop-grayscale":["",We,Ce,ke]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[We,Ce,ke]}],"backdrop-invert":[{"backdrop-invert":["",We,Ce,ke]}],"backdrop-opacity":[{"backdrop-opacity":[We,Ce,ke]}],"backdrop-saturate":[{"backdrop-saturate":[We,Ce,ke]}],"backdrop-sepia":[{"backdrop-sepia":["",We,Ce,ke]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":B()}],"border-spacing-x":[{"border-spacing-x":B()}],"border-spacing-y":[{"border-spacing-y":B()}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["","all","colors","opacity","shadow","transform","none",Ce,ke]}],"transition-behavior":[{transition:["normal","discrete"]}],duration:[{duration:[We,"initial",Ce,ke]}],ease:[{ease:["linear","initial",w,Ce,ke]}],delay:[{delay:[We,Ce,ke]}],animate:[{animate:["none",k,Ce,ke]}],backface:[{backface:["hidden","visible"]}],perspective:[{perspective:[N,Ce,ke]}],"perspective-origin":[{"perspective-origin":I()}],rotate:[{rotate:fe()}],"rotate-x":[{"rotate-x":fe()}],"rotate-y":[{"rotate-y":fe()}],"rotate-z":[{"rotate-z":fe()}],scale:[{scale:be()}],"scale-x":[{"scale-x":be()}],"scale-y":[{"scale-y":be()}],"scale-z":[{"scale-z":be()}],"scale-3d":["scale-3d"],skew:[{skew:we()}],"skew-x":[{"skew-x":we()}],"skew-y":[{"skew-y":we()}],transform:[{transform:[Ce,ke,"","none","gpu","cpu"]}],"transform-origin":[{origin:I()}],"transform-style":[{transform:["3d","flat"]}],translate:[{translate:Ne()}],"translate-x":[{"translate-x":Ne()}],"translate-y":[{"translate-y":Ne()}],"translate-z":[{"translate-z":Ne()}],"translate-none":["translate-none"],zoom:[{zoom:[Fr,Ce,ke]}],accent:[{accent:C()}],appearance:[{appearance:["none","auto"]}],"caret-color":[{caret:C()}],"color-scheme":[{scheme:["normal","dark","light","light-dark","only-dark","only-light"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",Ce,ke]}],"field-sizing":[{"field-sizing":["fixed","content"]}],"pointer-events":[{"pointer-events":["auto","none"]}],resize:[{resize:["none","","y","x"]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scrollbar-thumb-color":[{"scrollbar-thumb":C()}],"scrollbar-track-color":[{"scrollbar-track":C()}],"scrollbar-gutter":[{"scrollbar-gutter":["auto","stable","both"]}],"scrollbar-w":[{scrollbar:["auto","thin","none"]}],"scroll-m":[{"scroll-m":B()}],"scroll-mx":[{"scroll-mx":B()}],"scroll-my":[{"scroll-my":B()}],"scroll-ms":[{"scroll-ms":B()}],"scroll-me":[{"scroll-me":B()}],"scroll-mbs":[{"scroll-mbs":B()}],"scroll-mbe":[{"scroll-mbe":B()}],"scroll-mt":[{"scroll-mt":B()}],"scroll-mr":[{"scroll-mr":B()}],"scroll-mb":[{"scroll-mb":B()}],"scroll-ml":[{"scroll-ml":B()}],"scroll-p":[{"scroll-p":B()}],"scroll-px":[{"scroll-px":B()}],"scroll-py":[{"scroll-py":B()}],"scroll-ps":[{"scroll-ps":B()}],"scroll-pe":[{"scroll-pe":B()}],"scroll-pbs":[{"scroll-pbs":B()}],"scroll-pbe":[{"scroll-pbe":B()}],"scroll-pt":[{"scroll-pt":B()}],"scroll-pr":[{"scroll-pr":B()}],"scroll-pb":[{"scroll-pb":B()}],"scroll-pl":[{"scroll-pl":B()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",Ce,ke]}],fill:[{fill:["none",...C()]}],"stroke-w":[{stroke:[We,Kl,za,ly]}],stroke:[{stroke:["none",...C()]}],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{"container-named":["container-type"],overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","inset-bs","inset-be","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pbs","pbe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mbs","mbe","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-x","border-w-y","border-w-s","border-w-e","border-w-bs","border-w-be","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-x","border-color-y","border-color-s","border-color-e","border-color-bs","border-color-be","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],translate:["translate-x","translate-y","translate-none"],"translate-none":["translate","translate-x","translate-y","translate-z"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mbs","scroll-mbe","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pbs","scroll-pbe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]},postfixLookupClassGroups:["container-type"],orderSensitiveModifiers:["*","**","after","backdrop","before","details-content","file","first-letter","first-line","marker","placeholder","selection"]}},_A=WT(vA);function Mr(...e){return _A(MT(e))}function wA(e){return new Date(e).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}function qm(e){const t=new Date(e),a=Math.floor((new Date().getTime()-t.getTime())/1e3);return a<60?"just now":a<3600?`${Math.floor(a/60)}m ago`:a<86400?`${Math.floor(a/3600)}h ago`:a<604800?`${Math.floor(a/86400)}d ago`:wA(e)}function EA(e){return`STRIX-${e}`}function Ds(e){return new Intl.NumberFormat("en-US").format(e)}function NA(e,t){const r={};return(e[e.length-1]===""?[...e,""]:e).join((r.padRight?" ":"")+","+(r.padLeft===!1?"":" ")).trim()}const SA=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,kA=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,CA={};function uy(e,t){return(CA.jsx?kA:SA).test(e)}const TA=/[ \t\n\f\r]/g;function AA(e){return typeof e=="object"?e.type==="text"?dy(e.value):!1:dy(e)}function dy(e){return e.replace(TA,"")===""}class Mo{constructor(t,r,a){this.normal=r,this.property=t,a&&(this.space=a)}}Mo.prototype.normal={};Mo.prototype.property={};Mo.prototype.space=void 0;function tw(e,t){const r={},a={};for(const s of e)Object.assign(r,s.property),Object.assign(a,s.normal);return new Mo(r,a,t)}function Pm(e){return e.toLowerCase()}class Vn{constructor(t,r){this.attribute=r,this.property=t}}Vn.prototype.attribute="";Vn.prototype.booleanish=!1;Vn.prototype.boolean=!1;Vn.prototype.commaOrSpaceSeparated=!1;Vn.prototype.commaSeparated=!1;Vn.prototype.defined=!1;Vn.prototype.mustUseProperty=!1;Vn.prototype.number=!1;Vn.prototype.overloadedBoolean=!1;Vn.prototype.property="";Vn.prototype.spaceSeparated=!1;Vn.prototype.space=void 0;let MA=0;const Ge=Wa(),an=Wa(),Fm=Wa(),ve=Wa(),Ct=Wa(),qa=Wa(),rr=Wa();function Wa(){return 2**++MA}const Gm=Object.freeze(Object.defineProperty({__proto__:null,boolean:Ge,booleanish:an,commaOrSpaceSeparated:rr,commaSeparated:qa,number:ve,overloadedBoolean:Fm,spaceSeparated:Ct},Symbol.toStringTag,{value:"Module"})),gh=Object.keys(Gm);class Sp extends Vn{constructor(t,r,a,s){let o=-1;if(super(t,r),fy(this,"space",s),typeof a=="number")for(;++o4&&r.slice(0,4)==="data"&&LA.test(t)){if(t.charAt(4)==="-"){const o=t.slice(5).replace(hy,BA);a="data"+o.charAt(0).toUpperCase()+o.slice(1)}else{const o=t.slice(4);if(!hy.test(o)){let c=o.replace(DA,IA);c.charAt(0)!=="-"&&(c="-"+c),t="data"+c}}s=Sp}return new s(a,t)}function IA(e){return"-"+e.toLowerCase()}function BA(e){return e.charAt(1).toUpperCase()}const UA=tw([nw,OA,aw,sw,lw],"html"),kp=tw([nw,RA,aw,sw,lw],"svg");function HA(e){return e.join(" ").trim()}var Ls={},bh,my;function $A(){if(my)return bh;my=1;var e=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,t=/\n/g,r=/^\s*/,a=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,s=/^:\s*/,o=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,c=/^[;\s]*/,d=/^\s+|\s+$/g,h=` -`,f="/",m="*",p="",y="comment",x="declaration";function _(S,w){if(typeof S!="string")throw new TypeError("First argument must be a string");if(!S)return[];w=w||{};var k=1,E=1;function M(T){var $=T.match(t);$&&(k+=$.length);var O=T.lastIndexOf(h);E=~O?T.length-O:E+T.length}function I(){var T={line:k,column:E};return function($){return $.position=new R(T),Z(),$}}function R(T){this.start=T,this.end={line:k,column:E},this.source=w.source}R.prototype.content=S;function U(T){var $=new Error(w.source+":"+k+":"+E+": "+T);if($.reason=T,$.filename=w.source,$.line=k,$.column=E,$.source=S,!w.silent)throw $}function B(T){var $=T.exec(S);if($){var O=$[0];return M(O),S=S.slice(O.length),$}}function Z(){B(r)}function j(T){var $;for(T=T||[];$=z();)$!==!1&&T.push($);return T}function z(){var T=I();if(!(f!=S.charAt(0)||m!=S.charAt(1))){for(var $=2;p!=S.charAt($)&&(m!=S.charAt($)||f!=S.charAt($+1));)++$;if($+=2,p===S.charAt($-1))return U("End of comment missing");var O=S.slice(2,$-2);return E+=2,M(O),S=S.slice($),E+=2,T({type:y,comment:O})}}function V(){var T=I(),$=B(a);if($){if(z(),!B(s))return U("property missing ':'");var O=B(o),H=T({type:x,property:N($[0].replace(e,p)),value:O?N(O[0].replace(e,p)):p});return B(c),H}}function P(){var T=[];j(T);for(var $;$=V();)$!==!1&&(T.push($),j(T));return T}return Z(),P()}function N(S){return S?S.replace(d,p):p}return bh=_,bh}var py;function qA(){if(py)return Ls;py=1;var e=Ls&&Ls.__importDefault||function(a){return a&&a.__esModule?a:{default:a}};Object.defineProperty(Ls,"__esModule",{value:!0}),Ls.default=r;const t=e($A());function r(a,s){let o=null;if(!a||typeof a!="string")return o;const c=(0,t.default)(a),d=typeof s=="function";return c.forEach(h=>{if(h.type!=="declaration")return;const{property:f,value:m}=h;d?s(f,m,h):m&&(o=o||{},o[f]=m)}),o}return Ls}var Zl={},gy;function PA(){if(gy)return Zl;gy=1,Object.defineProperty(Zl,"__esModule",{value:!0}),Zl.camelCase=void 0;var e=/^--[a-zA-Z0-9_-]+$/,t=/-([a-z])/g,r=/^[^-]+$/,a=/^-(webkit|moz|ms|o|khtml)-/,s=/^-(ms)-/,o=function(f){return!f||r.test(f)||e.test(f)},c=function(f,m){return m.toUpperCase()},d=function(f,m){return"".concat(m,"-")},h=function(f,m){return m===void 0&&(m={}),o(f)?f:(f=f.toLowerCase(),m.reactCompat?f=f.replace(s,d):f=f.replace(a,d),f.replace(t,c))};return Zl.camelCase=h,Zl}var Ql,by;function FA(){if(by)return Ql;by=1;var e=Ql&&Ql.__importDefault||function(s){return s&&s.__esModule?s:{default:s}},t=e(qA()),r=PA();function a(s,o){var c={};return!s||typeof s!="string"||(0,t.default)(s,function(d,h){d&&h&&(c[(0,r.camelCase)(d,o)]=h)}),c}return a.default=a,Ql=a,Ql}var GA=FA();const VA=Co(GA),ow=cw("end"),Cp=cw("start");function cw(e){return t;function t(r){const a=r&&r.position&&r.position[e]||{};if(typeof a.line=="number"&&a.line>0&&typeof a.column=="number"&&a.column>0)return{line:a.line,column:a.column,offset:typeof a.offset=="number"&&a.offset>-1?a.offset:void 0}}}function YA(e){const t=Cp(e),r=ow(e);if(t&&r)return{start:t,end:r}}function lo(e){return!e||typeof e!="object"?"":"position"in e||"type"in e?xy(e.position):"start"in e||"end"in e?xy(e):"line"in e||"column"in e?Vm(e):""}function Vm(e){return yy(e&&e.line)+":"+yy(e&&e.column)}function xy(e){return Vm(e&&e.start)+"-"+Vm(e&&e.end)}function yy(e){return e&&typeof e=="number"?e:1}class Mn extends Error{constructor(t,r,a){super(),typeof r=="string"&&(a=r,r=void 0);let s="",o={},c=!1;if(r&&("line"in r&&"column"in r?o={place:r}:"start"in r&&"end"in r?o={place:r}:"type"in r?o={ancestors:[r],place:r.position}:o={...r}),typeof t=="string"?s=t:!o.cause&&t&&(c=!0,s=t.message,o.cause=t),!o.ruleId&&!o.source&&typeof a=="string"){const h=a.indexOf(":");h===-1?o.ruleId=a:(o.source=a.slice(0,h),o.ruleId=a.slice(h+1))}if(!o.place&&o.ancestors&&o.ancestors){const h=o.ancestors[o.ancestors.length-1];h&&(o.place=h.position)}const d=o.place&&"start"in o.place?o.place.start:o.place;this.ancestors=o.ancestors||void 0,this.cause=o.cause||void 0,this.column=d?d.column:void 0,this.fatal=void 0,this.file="",this.message=s,this.line=d?d.line:void 0,this.name=lo(o.place)||"1:1",this.place=o.place||void 0,this.reason=this.message,this.ruleId=o.ruleId||void 0,this.source=o.source||void 0,this.stack=c&&o.cause&&typeof o.cause.stack=="string"?o.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}Mn.prototype.file="";Mn.prototype.name="";Mn.prototype.reason="";Mn.prototype.message="";Mn.prototype.stack="";Mn.prototype.column=void 0;Mn.prototype.line=void 0;Mn.prototype.ancestors=void 0;Mn.prototype.cause=void 0;Mn.prototype.fatal=void 0;Mn.prototype.place=void 0;Mn.prototype.ruleId=void 0;Mn.prototype.source=void 0;const Tp={}.hasOwnProperty,XA=new Map,KA=/[A-Z]/g,ZA=new Set(["table","tbody","thead","tfoot","tr"]),QA=new Set(["td","th"]),uw="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function WA(e,t){if(!t||t.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const r=t.filePath||void 0;let a;if(t.development){if(typeof t.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");a=sM(r,t.jsxDEV)}else{if(typeof t.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof t.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");a=aM(r,t.jsx,t.jsxs)}const s={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:a,elementAttributeNameCase:t.elementAttributeNameCase||"react",evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:r,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space==="svg"?kp:UA,stylePropertyNameCase:t.stylePropertyNameCase||"dom",tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},o=dw(s,e,void 0);return o&&typeof o!="string"?o:s.create(e,s.Fragment,{children:o||void 0},void 0)}function dw(e,t,r){if(t.type==="element")return JA(e,t,r);if(t.type==="mdxFlowExpression"||t.type==="mdxTextExpression")return eM(e,t);if(t.type==="mdxJsxFlowElement"||t.type==="mdxJsxTextElement")return nM(e,t,r);if(t.type==="mdxjsEsm")return tM(e,t);if(t.type==="root")return rM(e,t,r);if(t.type==="text")return iM(e,t)}function JA(e,t,r){const a=e.schema;let s=a;t.tagName.toLowerCase()==="svg"&&a.space==="html"&&(s=kp,e.schema=s),e.ancestors.push(t);const o=hw(e,t.tagName,!1),c=lM(e,t);let d=Mp(e,t);return ZA.has(t.tagName)&&(d=d.filter(function(h){return typeof h=="string"?!AA(h):!0})),fw(e,c,o,t),Ap(c,d),e.ancestors.pop(),e.schema=a,e.create(t,o,c,r)}function eM(e,t){if(t.data&&t.data.estree&&e.evaluater){const a=t.data.estree.body[0];return a.type,e.evaluater.evaluateExpression(a.expression)}po(e,t.position)}function tM(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);po(e,t.position)}function nM(e,t,r){const a=e.schema;let s=a;t.name==="svg"&&a.space==="html"&&(s=kp,e.schema=s),e.ancestors.push(t);const o=t.name===null?e.Fragment:hw(e,t.name,!0),c=oM(e,t),d=Mp(e,t);return fw(e,c,o,t),Ap(c,d),e.ancestors.pop(),e.schema=a,e.create(t,o,c,r)}function rM(e,t,r){const a={};return Ap(a,Mp(e,t)),e.create(t,e.Fragment,a,r)}function iM(e,t){return t.value}function fw(e,t,r,a){typeof r!="string"&&r!==e.Fragment&&e.passNode&&(t.node=a)}function Ap(e,t){if(t.length>0){const r=t.length>1?t:t[0];r&&(e.children=r)}}function aM(e,t,r){return a;function a(s,o,c,d){const f=Array.isArray(c.children)?r:t;return d?f(o,c,d):f(o,c)}}function sM(e,t){return r;function r(a,s,o,c){const d=Array.isArray(o.children),h=Cp(a);return t(s,o,c,d,{columnNumber:h?h.column-1:void 0,fileName:e,lineNumber:h?h.line:void 0},void 0)}}function lM(e,t){const r={};let a,s;for(s in t.properties)if(s!=="children"&&Tp.call(t.properties,s)){const o=cM(e,s,t.properties[s]);if(o){const[c,d]=o;e.tableCellAlignToStyle&&c==="align"&&typeof d=="string"&&QA.has(t.tagName)?a=d:r[c]=d}}if(a){const o=r.style||(r.style={});o[e.stylePropertyNameCase==="css"?"text-align":"textAlign"]=a}return r}function oM(e,t){const r={};for(const a of t.attributes)if(a.type==="mdxJsxExpressionAttribute")if(a.data&&a.data.estree&&e.evaluater){const o=a.data.estree.body[0];o.type;const c=o.expression;c.type;const d=c.properties[0];d.type,Object.assign(r,e.evaluater.evaluateExpression(d.argument))}else po(e,t.position);else{const s=a.name;let o;if(a.value&&typeof a.value=="object")if(a.value.data&&a.value.data.estree&&e.evaluater){const d=a.value.data.estree.body[0];d.type,o=e.evaluater.evaluateExpression(d.expression)}else po(e,t.position);else o=a.value===null?!0:a.value;r[s]=o}return r}function Mp(e,t){const r=[];let a=-1;const s=e.passKeys?new Map:XA;for(;++as?0:s+t:t=t>s?s:t,r=r>0?r:0,a.length<1e4)c=Array.from(a),c.unshift(t,r),e.splice(...c);else for(r&&e.splice(t,r);o0?(ar(e,e.length,0,t),e):t}const wy={}.hasOwnProperty;function pw(e){const t={};let r=-1;for(;++r13&&r<32||r>126&&r<160||r>55295&&r<57344||r>64975&&r<65008||(r&65535)===65535||(r&65535)===65534||r>1114111?"οΏ½":String.fromCodePoint(r)}function Dr(e){return e.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}const Ln=pa(/[A-Za-z]/),Tn=pa(/[\dA-Za-z]/),xM=pa(/[#-'*+\--9=?A-Z^-~]/);function _u(e){return e!==null&&(e<32||e===127)}const Ym=pa(/\d/),yM=pa(/[\dA-Fa-f]/),vM=pa(/[!-/:-@[-`{-~]/);function Be(e){return e!==null&&e<-2}function Tt(e){return e!==null&&(e<0||e===32)}function tt(e){return e===-2||e===-1||e===32}const qu=pa(new RegExp("\\p{P}|\\p{S}","u")),Ga=pa(/\s/);function pa(e){return t;function t(r){return r!==null&&r>-1&&e.test(String.fromCharCode(r))}}function nl(e){const t=[];let r=-1,a=0,s=0;for(;++r55295&&o<57344){const d=e.charCodeAt(r+1);o<56320&&d>56319&&d<57344?(c=String.fromCharCode(o,d),s=1):c="οΏ½"}else c=String.fromCharCode(o);c&&(t.push(e.slice(a,r),encodeURIComponent(c)),a=r+s+1,c=""),s&&(r+=s,s=0)}return t.join("")+e.slice(a)}function ot(e,t,r,a){const s=a?a-1:Number.POSITIVE_INFINITY;let o=0;return c;function c(h){return tt(h)?(e.enter(r),d(h)):t(h)}function d(h){return tt(h)&&o++c))return;const U=t.events.length;let B=U,Z,j;for(;B--;)if(t.events[B][0]==="exit"&&t.events[B][1].type==="chunkFlow"){if(Z){j=t.events[B][1].end;break}Z=!0}for(w(a),R=U;RE;){const I=r[M];t.containerState=I[1],I[0].exit.call(t,e)}r.length=E}function k(){s.write([null]),o=void 0,s=void 0,t.containerState._closeFlow=void 0}}function SM(e,t,r){return ot(e,e.attempt(this.parser.constructs.document,t,r),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function Ys(e){if(e===null||Tt(e)||Ga(e))return 1;if(qu(e))return 2}function Pu(e,t,r){const a=[];let s=-1;for(;++s1&&e[r][1].end.offset-e[r][1].start.offset>1?2:1;const p={...e[a][1].end},y={...e[r][1].start};Ny(p,-h),Ny(y,h),c={type:h>1?"strongSequence":"emphasisSequence",start:p,end:{...e[a][1].end}},d={type:h>1?"strongSequence":"emphasisSequence",start:{...e[r][1].start},end:y},o={type:h>1?"strongText":"emphasisText",start:{...e[a][1].end},end:{...e[r][1].start}},s={type:h>1?"strong":"emphasis",start:{...c.start},end:{...d.end}},e[a][1].end={...c.start},e[r][1].start={...d.end},f=[],e[a][1].end.offset-e[a][1].start.offset&&(f=br(f,[["enter",e[a][1],t],["exit",e[a][1],t]])),f=br(f,[["enter",s,t],["enter",c,t],["exit",c,t],["enter",o,t]]),f=br(f,Pu(t.parser.constructs.insideSpan.null,e.slice(a+1,r),t)),f=br(f,[["exit",o,t],["enter",d,t],["exit",d,t],["exit",s,t]]),e[r][1].end.offset-e[r][1].start.offset?(m=2,f=br(f,[["enter",e[r][1],t],["exit",e[r][1],t]])):m=0,ar(e,a-1,r-a+3,f),r=a+f.length-m-2;break}}for(r=-1;++r0&&tt(R)?ot(e,k,"linePrefix",o+1)(R):k(R)}function k(R){return R===null||Be(R)?e.check(Sy,N,M)(R):(e.enter("codeFlowValue"),E(R))}function E(R){return R===null||Be(R)?(e.exit("codeFlowValue"),k(R)):(e.consume(R),E)}function M(R){return e.exit("codeFenced"),t(R)}function I(R,U,B){let Z=0;return j;function j($){return R.enter("lineEnding"),R.consume($),R.exit("lineEnding"),z}function z($){return R.enter("codeFencedFence"),tt($)?ot(R,V,"linePrefix",a.parser.constructs.disable.null.includes("codeIndented")?void 0:4)($):V($)}function V($){return $===d?(R.enter("codeFencedFenceSequence"),P($)):B($)}function P($){return $===d?(Z++,R.consume($),P):Z>=c?(R.exit("codeFencedFenceSequence"),tt($)?ot(R,T,"whitespace")($):T($)):B($)}function T($){return $===null||Be($)?(R.exit("codeFencedFence"),U($)):B($)}}}function IM(e,t,r){const a=this;return s;function s(c){return c===null?r(c):(e.enter("lineEnding"),e.consume(c),e.exit("lineEnding"),o)}function o(c){return a.parser.lazy[a.now().line]?r(c):t(c)}}const yh={name:"codeIndented",tokenize:UM},BM={partial:!0,tokenize:HM};function UM(e,t,r){const a=this;return s;function s(f){return e.enter("codeIndented"),ot(e,o,"linePrefix",5)(f)}function o(f){const m=a.events[a.events.length-1];return m&&m[1].type==="linePrefix"&&m[2].sliceSerialize(m[1],!0).length>=4?c(f):r(f)}function c(f){return f===null?h(f):Be(f)?e.attempt(BM,c,h)(f):(e.enter("codeFlowValue"),d(f))}function d(f){return f===null||Be(f)?(e.exit("codeFlowValue"),c(f)):(e.consume(f),d)}function h(f){return e.exit("codeIndented"),t(f)}}function HM(e,t,r){const a=this;return s;function s(c){return a.parser.lazy[a.now().line]?r(c):Be(c)?(e.enter("lineEnding"),e.consume(c),e.exit("lineEnding"),s):ot(e,o,"linePrefix",5)(c)}function o(c){const d=a.events[a.events.length-1];return d&&d[1].type==="linePrefix"&&d[2].sliceSerialize(d[1],!0).length>=4?t(c):Be(c)?s(c):r(c)}}const $M={name:"codeText",previous:PM,resolve:qM,tokenize:FM};function qM(e){let t=e.length-4,r=3,a,s;if((e[r][1].type==="lineEnding"||e[r][1].type==="space")&&(e[t][1].type==="lineEnding"||e[t][1].type==="space")){for(a=r;++a=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+t+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return tthis.left.length?this.right.slice(this.right.length-a+this.left.length,this.right.length-t+this.left.length).reverse():this.left.slice(t).concat(this.right.slice(this.right.length-a+this.left.length).reverse())}splice(t,r,a){const s=r||0;this.setCursor(Math.trunc(t));const o=this.right.splice(this.right.length-s,Number.POSITIVE_INFINITY);return a&&Wl(this.left,a),o.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(t){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(t)}pushMany(t){this.setCursor(Number.POSITIVE_INFINITY),Wl(this.left,t)}unshift(t){this.setCursor(0),this.right.push(t)}unshiftMany(t){this.setCursor(0),Wl(this.right,t.reverse())}setCursor(t){if(!(t===this.left.length||t>this.left.length&&this.right.length===0||t<0&&this.left.length===0))if(t=4?t(c):e.interrupt(a.parser.constructs.flow,r,t)(c)}}function _w(e,t,r,a,s,o,c,d,h){const f=h||Number.POSITIVE_INFINITY;let m=0;return p;function p(w){return w===60?(e.enter(a),e.enter(s),e.enter(o),e.consume(w),e.exit(o),y):w===null||w===32||w===41||_u(w)?r(w):(e.enter(a),e.enter(c),e.enter(d),e.enter("chunkString",{contentType:"string"}),N(w))}function y(w){return w===62?(e.enter(o),e.consume(w),e.exit(o),e.exit(s),e.exit(a),t):(e.enter(d),e.enter("chunkString",{contentType:"string"}),x(w))}function x(w){return w===62?(e.exit("chunkString"),e.exit(d),y(w)):w===null||w===60||Be(w)?r(w):(e.consume(w),w===92?_:x)}function _(w){return w===60||w===62||w===92?(e.consume(w),x):x(w)}function N(w){return!m&&(w===null||w===41||Tt(w))?(e.exit("chunkString"),e.exit(d),e.exit(c),e.exit(a),t(w)):m999||x===null||x===91||x===93&&!h||x===94&&!d&&"_hiddenFootnoteSupport"in c.parser.constructs?r(x):x===93?(e.exit(o),e.enter(s),e.consume(x),e.exit(s),e.exit(a),t):Be(x)?(e.enter("lineEnding"),e.consume(x),e.exit("lineEnding"),m):(e.enter("chunkString",{contentType:"string"}),p(x))}function p(x){return x===null||x===91||x===93||Be(x)||d++>999?(e.exit("chunkString"),m(x)):(e.consume(x),h||(h=!tt(x)),x===92?y:p)}function y(x){return x===91||x===92||x===93?(e.consume(x),d++,p):p(x)}}function Ew(e,t,r,a,s,o){let c;return d;function d(y){return y===34||y===39||y===40?(e.enter(a),e.enter(s),e.consume(y),e.exit(s),c=y===40?41:y,h):r(y)}function h(y){return y===c?(e.enter(s),e.consume(y),e.exit(s),e.exit(a),t):(e.enter(o),f(y))}function f(y){return y===c?(e.exit(o),h(c)):y===null?r(y):Be(y)?(e.enter("lineEnding"),e.consume(y),e.exit("lineEnding"),ot(e,f,"linePrefix")):(e.enter("chunkString",{contentType:"string"}),m(y))}function m(y){return y===c||y===null||Be(y)?(e.exit("chunkString"),f(y)):(e.consume(y),y===92?p:m)}function p(y){return y===c||y===92?(e.consume(y),m):m(y)}}function oo(e,t){let r;return a;function a(s){return Be(s)?(e.enter("lineEnding"),e.consume(s),e.exit("lineEnding"),r=!0,a):tt(s)?ot(e,a,r?"linePrefix":"lineSuffix")(s):t(s)}}const WM={name:"definition",tokenize:e5},JM={partial:!0,tokenize:t5};function e5(e,t,r){const a=this;let s;return o;function o(x){return e.enter("definition"),c(x)}function c(x){return ww.call(a,e,d,r,"definitionLabel","definitionLabelMarker","definitionLabelString")(x)}function d(x){return s=Dr(a.sliceSerialize(a.events[a.events.length-1][1]).slice(1,-1)),x===58?(e.enter("definitionMarker"),e.consume(x),e.exit("definitionMarker"),h):r(x)}function h(x){return Tt(x)?oo(e,f)(x):f(x)}function f(x){return _w(e,m,r,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(x)}function m(x){return e.attempt(JM,p,p)(x)}function p(x){return tt(x)?ot(e,y,"whitespace")(x):y(x)}function y(x){return x===null||Be(x)?(e.exit("definition"),a.parser.defined.push(s),t(x)):r(x)}}function t5(e,t,r){return a;function a(d){return Tt(d)?oo(e,s)(d):r(d)}function s(d){return Ew(e,o,r,"definitionTitle","definitionTitleMarker","definitionTitleString")(d)}function o(d){return tt(d)?ot(e,c,"whitespace")(d):c(d)}function c(d){return d===null||Be(d)?t(d):r(d)}}const n5={name:"hardBreakEscape",tokenize:r5};function r5(e,t,r){return a;function a(o){return e.enter("hardBreakEscape"),e.consume(o),s}function s(o){return Be(o)?(e.exit("hardBreakEscape"),t(o)):r(o)}}const i5={name:"headingAtx",resolve:a5,tokenize:s5};function a5(e,t){let r=e.length-2,a=3,s,o;return e[a][1].type==="whitespace"&&(a+=2),r-2>a&&e[r][1].type==="whitespace"&&(r-=2),e[r][1].type==="atxHeadingSequence"&&(a===r-1||r-4>a&&e[r-2][1].type==="whitespace")&&(r-=a+1===r?2:4),r>a&&(s={type:"atxHeadingText",start:e[a][1].start,end:e[r][1].end},o={type:"chunkText",start:e[a][1].start,end:e[r][1].end,contentType:"text"},ar(e,a,r-a+1,[["enter",s,t],["enter",o,t],["exit",o,t],["exit",s,t]])),e}function s5(e,t,r){let a=0;return s;function s(m){return e.enter("atxHeading"),o(m)}function o(m){return e.enter("atxHeadingSequence"),c(m)}function c(m){return m===35&&a++<6?(e.consume(m),c):m===null||Tt(m)?(e.exit("atxHeadingSequence"),d(m)):r(m)}function d(m){return m===35?(e.enter("atxHeadingSequence"),h(m)):m===null||Be(m)?(e.exit("atxHeading"),t(m)):tt(m)?ot(e,d,"whitespace")(m):(e.enter("atxHeadingText"),f(m))}function h(m){return m===35?(e.consume(m),h):(e.exit("atxHeadingSequence"),d(m))}function f(m){return m===null||m===35||Tt(m)?(e.exit("atxHeadingText"),d(m)):(e.consume(m),f)}}const l5=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],Cy=["pre","script","style","textarea"],o5={concrete:!0,name:"htmlFlow",resolveTo:d5,tokenize:f5},c5={partial:!0,tokenize:m5},u5={partial:!0,tokenize:h5};function d5(e){let t=e.length;for(;t--&&!(e[t][0]==="enter"&&e[t][1].type==="htmlFlow"););return t>1&&e[t-2][1].type==="linePrefix"&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function f5(e,t,r){const a=this;let s,o,c,d,h;return f;function f(L){return m(L)}function m(L){return e.enter("htmlFlow"),e.enter("htmlFlowData"),e.consume(L),p}function p(L){return L===33?(e.consume(L),y):L===47?(e.consume(L),o=!0,N):L===63?(e.consume(L),s=3,a.interrupt?t:C):Ln(L)?(e.consume(L),c=String.fromCharCode(L),S):r(L)}function y(L){return L===45?(e.consume(L),s=2,x):L===91?(e.consume(L),s=5,d=0,_):Ln(L)?(e.consume(L),s=4,a.interrupt?t:C):r(L)}function x(L){return L===45?(e.consume(L),a.interrupt?t:C):r(L)}function _(L){const G="CDATA[";return L===G.charCodeAt(d++)?(e.consume(L),d===G.length?a.interrupt?t:V:_):r(L)}function N(L){return Ln(L)?(e.consume(L),c=String.fromCharCode(L),S):r(L)}function S(L){if(L===null||L===47||L===62||Tt(L)){const G=L===47,q=c.toLowerCase();return!G&&!o&&Cy.includes(q)?(s=1,a.interrupt?t(L):V(L)):l5.includes(c.toLowerCase())?(s=6,G?(e.consume(L),w):a.interrupt?t(L):V(L)):(s=7,a.interrupt&&!a.parser.lazy[a.now().line]?r(L):o?k(L):E(L))}return L===45||Tn(L)?(e.consume(L),c+=String.fromCharCode(L),S):r(L)}function w(L){return L===62?(e.consume(L),a.interrupt?t:V):r(L)}function k(L){return tt(L)?(e.consume(L),k):j(L)}function E(L){return L===47?(e.consume(L),j):L===58||L===95||Ln(L)?(e.consume(L),M):tt(L)?(e.consume(L),E):j(L)}function M(L){return L===45||L===46||L===58||L===95||Tn(L)?(e.consume(L),M):I(L)}function I(L){return L===61?(e.consume(L),R):tt(L)?(e.consume(L),I):E(L)}function R(L){return L===null||L===60||L===61||L===62||L===96?r(L):L===34||L===39?(e.consume(L),h=L,U):tt(L)?(e.consume(L),R):B(L)}function U(L){return L===h?(e.consume(L),h=null,Z):L===null||Be(L)?r(L):(e.consume(L),U)}function B(L){return L===null||L===34||L===39||L===47||L===60||L===61||L===62||L===96||Tt(L)?I(L):(e.consume(L),B)}function Z(L){return L===47||L===62||tt(L)?E(L):r(L)}function j(L){return L===62?(e.consume(L),z):r(L)}function z(L){return L===null||Be(L)?V(L):tt(L)?(e.consume(L),z):r(L)}function V(L){return L===45&&s===2?(e.consume(L),O):L===60&&s===1?(e.consume(L),H):L===62&&s===4?(e.consume(L),D):L===63&&s===3?(e.consume(L),C):L===93&&s===5?(e.consume(L),K):Be(L)&&(s===6||s===7)?(e.exit("htmlFlowData"),e.check(c5,Y,P)(L)):L===null||Be(L)?(e.exit("htmlFlowData"),P(L)):(e.consume(L),V)}function P(L){return e.check(u5,T,Y)(L)}function T(L){return e.enter("lineEnding"),e.consume(L),e.exit("lineEnding"),$}function $(L){return L===null||Be(L)?P(L):(e.enter("htmlFlowData"),V(L))}function O(L){return L===45?(e.consume(L),C):V(L)}function H(L){return L===47?(e.consume(L),c="",X):V(L)}function X(L){if(L===62){const G=c.toLowerCase();return Cy.includes(G)?(e.consume(L),D):V(L)}return Ln(L)&&c.length<8?(e.consume(L),c+=String.fromCharCode(L),X):V(L)}function K(L){return L===93?(e.consume(L),C):V(L)}function C(L){return L===62?(e.consume(L),D):L===45&&s===2?(e.consume(L),C):V(L)}function D(L){return L===null||Be(L)?(e.exit("htmlFlowData"),Y(L)):(e.consume(L),D)}function Y(L){return e.exit("htmlFlow"),t(L)}}function h5(e,t,r){const a=this;return s;function s(c){return Be(c)?(e.enter("lineEnding"),e.consume(c),e.exit("lineEnding"),o):r(c)}function o(c){return a.parser.lazy[a.now().line]?r(c):t(c)}}function m5(e,t,r){return a;function a(s){return e.enter("lineEnding"),e.consume(s),e.exit("lineEnding"),e.attempt(Oo,t,r)}}const p5={name:"htmlText",tokenize:g5};function g5(e,t,r){const a=this;let s,o,c;return d;function d(C){return e.enter("htmlText"),e.enter("htmlTextData"),e.consume(C),h}function h(C){return C===33?(e.consume(C),f):C===47?(e.consume(C),I):C===63?(e.consume(C),E):Ln(C)?(e.consume(C),B):r(C)}function f(C){return C===45?(e.consume(C),m):C===91?(e.consume(C),o=0,_):Ln(C)?(e.consume(C),k):r(C)}function m(C){return C===45?(e.consume(C),x):r(C)}function p(C){return C===null?r(C):C===45?(e.consume(C),y):Be(C)?(c=p,H(C)):(e.consume(C),p)}function y(C){return C===45?(e.consume(C),x):p(C)}function x(C){return C===62?O(C):C===45?y(C):p(C)}function _(C){const D="CDATA[";return C===D.charCodeAt(o++)?(e.consume(C),o===D.length?N:_):r(C)}function N(C){return C===null?r(C):C===93?(e.consume(C),S):Be(C)?(c=N,H(C)):(e.consume(C),N)}function S(C){return C===93?(e.consume(C),w):N(C)}function w(C){return C===62?O(C):C===93?(e.consume(C),w):N(C)}function k(C){return C===null||C===62?O(C):Be(C)?(c=k,H(C)):(e.consume(C),k)}function E(C){return C===null?r(C):C===63?(e.consume(C),M):Be(C)?(c=E,H(C)):(e.consume(C),E)}function M(C){return C===62?O(C):E(C)}function I(C){return Ln(C)?(e.consume(C),R):r(C)}function R(C){return C===45||Tn(C)?(e.consume(C),R):U(C)}function U(C){return Be(C)?(c=U,H(C)):tt(C)?(e.consume(C),U):O(C)}function B(C){return C===45||Tn(C)?(e.consume(C),B):C===47||C===62||Tt(C)?Z(C):r(C)}function Z(C){return C===47?(e.consume(C),O):C===58||C===95||Ln(C)?(e.consume(C),j):Be(C)?(c=Z,H(C)):tt(C)?(e.consume(C),Z):O(C)}function j(C){return C===45||C===46||C===58||C===95||Tn(C)?(e.consume(C),j):z(C)}function z(C){return C===61?(e.consume(C),V):Be(C)?(c=z,H(C)):tt(C)?(e.consume(C),z):Z(C)}function V(C){return C===null||C===60||C===61||C===62||C===96?r(C):C===34||C===39?(e.consume(C),s=C,P):Be(C)?(c=V,H(C)):tt(C)?(e.consume(C),V):(e.consume(C),T)}function P(C){return C===s?(e.consume(C),s=void 0,$):C===null?r(C):Be(C)?(c=P,H(C)):(e.consume(C),P)}function T(C){return C===null||C===34||C===39||C===60||C===61||C===96?r(C):C===47||C===62||Tt(C)?Z(C):(e.consume(C),T)}function $(C){return C===47||C===62||Tt(C)?Z(C):r(C)}function O(C){return C===62?(e.consume(C),e.exit("htmlTextData"),e.exit("htmlText"),t):r(C)}function H(C){return e.exit("htmlTextData"),e.enter("lineEnding"),e.consume(C),e.exit("lineEnding"),X}function X(C){return tt(C)?ot(e,K,"linePrefix",a.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(C):K(C)}function K(C){return e.enter("htmlTextData"),c(C)}}const jp={name:"labelEnd",resolveAll:v5,resolveTo:_5,tokenize:w5},b5={tokenize:E5},x5={tokenize:N5},y5={tokenize:S5};function v5(e){let t=-1;const r=[];for(;++t=3&&(f===null||Be(f))?(e.exit("thematicBreak"),t(f)):r(f)}function h(f){return f===s?(e.consume(f),a++,h):(e.exit("thematicBreakSequence"),tt(f)?ot(e,d,"whitespace")(f):d(f))}}const Fn={continuation:{tokenize:L5},exit:I5,name:"list",tokenize:D5},R5={partial:!0,tokenize:B5},j5={partial:!0,tokenize:z5};function D5(e,t,r){const a=this,s=a.events[a.events.length-1];let o=s&&s[1].type==="linePrefix"?s[2].sliceSerialize(s[1],!0).length:0,c=0;return d;function d(x){const _=a.containerState.type||(x===42||x===43||x===45?"listUnordered":"listOrdered");if(_==="listUnordered"?!a.containerState.marker||x===a.containerState.marker:Ym(x)){if(a.containerState.type||(a.containerState.type=_,e.enter(_,{_container:!0})),_==="listUnordered")return e.enter("listItemPrefix"),x===42||x===45?e.check(mu,r,f)(x):f(x);if(!a.interrupt||x===49)return e.enter("listItemPrefix"),e.enter("listItemValue"),h(x)}return r(x)}function h(x){return Ym(x)&&++c<10?(e.consume(x),h):(!a.interrupt||c<2)&&(a.containerState.marker?x===a.containerState.marker:x===41||x===46)?(e.exit("listItemValue"),f(x)):r(x)}function f(x){return e.enter("listItemMarker"),e.consume(x),e.exit("listItemMarker"),a.containerState.marker=a.containerState.marker||x,e.check(Oo,a.interrupt?r:m,e.attempt(R5,y,p))}function m(x){return a.containerState.initialBlankLine=!0,o++,y(x)}function p(x){return tt(x)?(e.enter("listItemPrefixWhitespace"),e.consume(x),e.exit("listItemPrefixWhitespace"),y):r(x)}function y(x){return a.containerState.size=o+a.sliceSerialize(e.exit("listItemPrefix"),!0).length,t(x)}}function L5(e,t,r){const a=this;return a.containerState._closeFlow=void 0,e.check(Oo,s,o);function s(d){return a.containerState.furtherBlankLines=a.containerState.furtherBlankLines||a.containerState.initialBlankLine,ot(e,t,"listItemIndent",a.containerState.size+1)(d)}function o(d){return a.containerState.furtherBlankLines||!tt(d)?(a.containerState.furtherBlankLines=void 0,a.containerState.initialBlankLine=void 0,c(d)):(a.containerState.furtherBlankLines=void 0,a.containerState.initialBlankLine=void 0,e.attempt(j5,t,c)(d))}function c(d){return a.containerState._closeFlow=!0,a.interrupt=void 0,ot(e,e.attempt(Fn,t,r),"linePrefix",a.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(d)}}function z5(e,t,r){const a=this;return ot(e,s,"listItemIndent",a.containerState.size+1);function s(o){const c=a.events[a.events.length-1];return c&&c[1].type==="listItemIndent"&&c[2].sliceSerialize(c[1],!0).length===a.containerState.size?t(o):r(o)}}function I5(e){e.exit(this.containerState.type)}function B5(e,t,r){const a=this;return ot(e,s,"listItemPrefixWhitespace",a.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function s(o){const c=a.events[a.events.length-1];return!tt(o)&&c&&c[1].type==="listItemPrefixWhitespace"?t(o):r(o)}}const Ty={name:"setextUnderline",resolveTo:U5,tokenize:H5};function U5(e,t){let r=e.length,a,s,o;for(;r--;)if(e[r][0]==="enter"){if(e[r][1].type==="content"){a=r;break}e[r][1].type==="paragraph"&&(s=r)}else e[r][1].type==="content"&&e.splice(r,1),!o&&e[r][1].type==="definition"&&(o=r);const c={type:"setextHeading",start:{...e[a][1].start},end:{...e[e.length-1][1].end}};return e[s][1].type="setextHeadingText",o?(e.splice(s,0,["enter",c,t]),e.splice(o+1,0,["exit",e[a][1],t]),e[a][1].end={...e[o][1].end}):e[a][1]=c,e.push(["exit",c,t]),e}function H5(e,t,r){const a=this;let s;return o;function o(f){let m=a.events.length,p;for(;m--;)if(a.events[m][1].type!=="lineEnding"&&a.events[m][1].type!=="linePrefix"&&a.events[m][1].type!=="content"){p=a.events[m][1].type==="paragraph";break}return!a.parser.lazy[a.now().line]&&(a.interrupt||p)?(e.enter("setextHeadingLine"),s=f,c(f)):r(f)}function c(f){return e.enter("setextHeadingLineSequence"),d(f)}function d(f){return f===s?(e.consume(f),d):(e.exit("setextHeadingLineSequence"),tt(f)?ot(e,h,"lineSuffix")(f):h(f))}function h(f){return f===null||Be(f)?(e.exit("setextHeadingLine"),t(f)):r(f)}}const $5={tokenize:q5};function q5(e){const t=this,r=e.attempt(Oo,a,e.attempt(this.parser.constructs.flowInitial,s,ot(e,e.attempt(this.parser.constructs.flow,s,e.attempt(YM,s)),"linePrefix")));return r;function a(o){if(o===null){e.consume(o);return}return e.enter("lineEndingBlank"),e.consume(o),e.exit("lineEndingBlank"),t.currentConstruct=void 0,r}function s(o){if(o===null){e.consume(o);return}return e.enter("lineEnding"),e.consume(o),e.exit("lineEnding"),t.currentConstruct=void 0,r}}const P5={resolveAll:Sw()},F5=Nw("string"),G5=Nw("text");function Nw(e){return{resolveAll:Sw(e==="text"?V5:void 0),tokenize:t};function t(r){const a=this,s=this.parser.constructs[e],o=r.attempt(s,c,d);return c;function c(m){return f(m)?o(m):d(m)}function d(m){if(m===null){r.consume(m);return}return r.enter("data"),r.consume(m),h}function h(m){return f(m)?(r.exit("data"),o(m)):(r.consume(m),h)}function f(m){if(m===null)return!0;const p=s[m];let y=-1;if(p)for(;++y-1){const d=c[0];typeof d=="string"?c[0]=d.slice(a):c.shift()}o>0&&c.push(e[s].slice(0,o))}return c}function aO(e,t){let r=-1;const a=[];let s;for(;++r