From de821718fd579448150a8a614be9da550fd743bf Mon Sep 17 00:00:00 2001 From: mamoodi Date: Mon, 18 Nov 2024 10:41:56 -0500 Subject: [PATCH 01/34] Use How to join community as reference for slack, discord, issues links (#5097) --- COMMUNITY.md | 29 ++++++++++++++++------------- README.md | 3 ++- docs/modules/usage/about.md | 5 +---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/COMMUNITY.md b/COMMUNITY.md index ffebf7fd5ae5..6edb4dff311e 100644 --- a/COMMUNITY.md +++ b/COMMUNITY.md @@ -1,23 +1,24 @@ # 🙌 The OpenHands Community -The OpenHands community is built around the belief that (1) AI and AI agents are going to fundamentally change the way we build software, and (2) if this is true, we should do everything we can to make sure that the benefits provided by such powerful technology are accessible to everyone. +The OpenHands community is built around the belief that (1) AI and AI agents are going to fundamentally change the way +we build software, and (2) if this is true, we should do everything we can to make sure that the benefits provided by +such powerful technology are accessible to everyone. If this resonates with you, we'd love to have you join us in our quest! ## 🤝 How to Join -We do most of our communication through Slack, so this is the best place to start, but we also are happy to have you contact us on Discord or Github. - -- [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2tom0er4l-JeNUGHt_AxpEfIBstbLPiw) - Here we talk about research, architecture, and future development. -- [Join our Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback. -- [Read and post Github Issues](https://github.com/All-Hands-AI/OpenHands/issues) - Check out the issues we're working on, or add your own ideas. +Check out our [How to Join the Community section.](https://github.com/All-Hands-AI/OpenHands?tab=readme-ov-file#-how-to-join-the-community) ## 💪 Becoming a Contributor -We welcome contributions from everyone! Whether you're a developer, a researcher, or simply enthusiastic about advancing the field of software engineering with AI, there are many ways to get involved: +We welcome contributions from everyone! Whether you're a developer, a researcher, or simply enthusiastic about advancing +the field of software engineering with AI, there are many ways to get involved: -- **Code Contributions:** Help us develop new core functionality, improve our agents, improve the frontend and other interfaces, or anything else that would help make OpenHands better. -- **Research and Evaluation:** Contribute to our understanding of LLMs in software engineering, participate in evaluating the models, or suggest improvements. +- **Code Contributions:** Help us develop new core functionality, improve our agents, improve the frontend and other +interfaces, or anything else that would help make OpenHands better. +- **Research and Evaluation:** Contribute to our understanding of LLMs in software engineering, participate in +evaluating the models, or suggest improvements. - **Feedback and Testing:** Use the OpenHands toolset, report bugs, suggest features, or provide feedback on usability. For details, please check [CONTRIBUTING.md](./CONTRIBUTING.md). @@ -30,11 +31,13 @@ All contributors are expected to contribute to building this sort of community. ## 🛠️ Becoming a Maintainer -For contributors who have made significant and sustained contributions to the project, there is a possibility of joining the maintainer team. -The process for this is as follows: +For contributors who have made significant and sustained contributions to the project, there is a possibility of joining +the maintainer team. The process for this is as follows: -1. Any contributor who has made sustained and high-quality contributions to the codebase can be nominated by any maintainer. If you feel that you may qualify you can reach out to any of the maintainers that have reviewed your PRs and ask if you can be nominated. +1. Any contributor who has made sustained and high-quality contributions to the codebase can be nominated by any +maintainer. If you feel that you may qualify you can reach out to any of the maintainers that have reviewed your PRs and ask if you can be nominated. 2. Once a maintainer nominates a new maintainer, there will be a discussion period among the maintainers for at least 3 days. 3. If no concerns are raised the nomination will be accepted by acclamation, and if concerns are raised there will be a discussion and possible vote. -Note that just making many PRs does not immediately imply that you will become a maintainer. We will be looking at sustained high-quality contributions over a period of time, as well as good teamwork and adherence to our [Code of Conduct](./CODE_OF_CONDUCT.md). +Note that just making many PRs does not immediately imply that you will become a maintainer. We will be looking +at sustained high-quality contributions over a period of time, as well as good teamwork and adherence to our [Code of Conduct](./CODE_OF_CONDUCT.md). diff --git a/README.md b/README.md index cd35635d56de..97de3104472c 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ troubleshooting resources, and advanced configuration options. ## 🤝 How to Join the Community -OpenHands is a community-driven project, and we welcome contributions from everyone. As a first step, you can: +OpenHands is a community-driven project, and we welcome contributions from everyone. We do most of our communication +through Slack, so this is the best place to start, but we also are happy to have you contact us on Discord or Github: - [Join our Slack workspace](https://join.slack.com/t/openhands-ai/shared_invite/zt-2tom0er4l-JeNUGHt_AxpEfIBstbLPiw) - Here we talk about research, architecture, and future development. - [Join our Discord server](https://discord.gg/ESHStjSjD4) - This is a community-run server for general discussion, questions, and feedback. diff --git a/docs/modules/usage/about.md b/docs/modules/usage/about.md index 93454bb4d9e8..2732fbeb31b4 100644 --- a/docs/modules/usage/about.md +++ b/docs/modules/usage/about.md @@ -21,9 +21,6 @@ OpenHands is built using a combination of powerful frameworks and libraries, pro Please note that the selection of these technologies is in progress, and additional technologies may be added or existing ones may be removed as the project evolves. We strive to adopt the most suitable and efficient tools to enhance the capabilities of OpenHands. -## Licensing, Contributing, Community Servers +## License Distributed under MIT [License](https://github.com/All-Hands-AI/OpenHands/blob/main/LICENSE). - -For guides on how to contribute to OpenHands, joining our Discord and Slack servers -[check out the OpenHands README.](https://github.com/All-Hands-AI/OpenHands?tab=readme-ov-file#-how-to-contribute) From a87b8599eb0866b874c765f510f2bb196a71591c Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Mon, 18 Nov 2024 13:38:29 -0500 Subject: [PATCH 02/34] fix: run only linting hooks in lint-fix workflow (#5107) Co-authored-by: openhands --- .github/workflows/lint-fix.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-fix.yml b/.github/workflows/lint-fix.yml index e3021b887c53..b877de6bb4d2 100644 --- a/.github/workflows/lint-fix.yml +++ b/.github/workflows/lint-fix.yml @@ -44,7 +44,11 @@ jobs: run: pip install pre-commit==3.7.0 - name: Fix python lint issues run: | - pre-commit run --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + pre-commit run trailing-whitespace --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + pre-commit run end-of-file-fixer --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + pre-commit run pyproject-fmt --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + pre-commit run ruff --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + pre-commit run ruff-format --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml # Commit and push changes if any - name: Check for changes From 6b893863982be9330056c0f11d21a7469bf63635 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Mon, 18 Nov 2024 17:34:18 -0500 Subject: [PATCH 03/34] fix 404 issue for /config (#5114) --- frontend/src/api/open-hands.ts | 3 +-- openhands/server/listen.py | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/frontend/src/api/open-hands.ts b/frontend/src/api/open-hands.ts index 072588ce476e..33f08d94f21e 100644 --- a/frontend/src/api/open-hands.ts +++ b/frontend/src/api/open-hands.ts @@ -185,8 +185,7 @@ class OpenHands { } static async getRuntimeId(): Promise<{ runtime_id: string }> { - const response = await request("/api/config"); - const data = await response.json(); + const data = await request("/api/conversation"); return data; } diff --git a/openhands/server/listen.py b/openhands/server/listen.py index c1b178b9c2b7..8724daf1905f 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -11,7 +11,6 @@ from pathspec import PathSpec from pathspec.patterns import GitWildMatchPattern -from openhands.runtime.impl.remote.remote_runtime import RemoteRuntime from openhands.security.options import SecurityAnalyzers from openhands.server.data_models.feedback import FeedbackDataModel, store_feedback from openhands.server.github import ( @@ -565,27 +564,21 @@ def sanitize_filename(filename): return filename -@app.get('/api/config') +@app.get('/api/conversation') async def get_remote_runtime_config(request: Request): """Retrieve the remote runtime configuration. Currently, this is the runtime ID. """ - try: - runtime = request.state.conversation.runtime - if isinstance(runtime, RemoteRuntime): - return JSONResponse(content={'runtime_id': runtime.runtime_id}) - else: - return JSONResponse( - status_code=status.HTTP_404_NOT_FOUND, - content={'error': 'Runtime ID not available in this environment'}, - ) - except Exception as e: - logger.error(e) - return JSONResponse( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content={'error': 'Something went wrong'}, - ) + runtime = request.state.conversation.runtime + runtime_id = runtime.runtime_id if hasattr(runtime, 'runtime_id') else None + session_id = runtime.sid if hasattr(runtime, 'sid') else None + return JSONResponse( + content={ + 'runtime_id': runtime_id, + 'session_id': session_id, + } + ) @app.post('/api/upload-files') From c75ca7d9766b0e5aa8fe42286d32b5f775c3cd82 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Mon, 18 Nov 2024 17:53:46 -0500 Subject: [PATCH 04/34] Bug/resolver context fix (#5115) --- openhands/resolver/issue_definitions.py | 4 +- .../prompts/resolve/basic-followup.jinja | 7 +- tests/unit/resolver/test_resolve_issues.py | 586 +++++++++--------- 3 files changed, 301 insertions(+), 296 deletions(-) diff --git a/openhands/resolver/issue_definitions.py b/openhands/resolver/issue_definitions.py index 10a134b812cf..c9e386178adf 100644 --- a/openhands/resolver/issue_definitions.py +++ b/openhands/resolver/issue_definitions.py @@ -576,9 +576,7 @@ def get_instruction( # Format thread comments if they exist thread_context = '' if issue.thread_comments: - thread_context = '\n\nPR Thread Comments:\n' + '\n---\n'.join( - issue.thread_comments - ) + thread_context = '\n---\n'.join(issue.thread_comments) images.extend(self._extract_image_urls(thread_context)) instruction = template.render( diff --git a/openhands/resolver/prompts/resolve/basic-followup.jinja b/openhands/resolver/prompts/resolve/basic-followup.jinja index cf26d80b3bdd..b7bdc2ae9e18 100644 --- a/openhands/resolver/prompts/resolve/basic-followup.jinja +++ b/openhands/resolver/prompts/resolve/basic-followup.jinja @@ -3,7 +3,7 @@ The feedback may be addressed to specific code files. In this case the file loca Please update the code based on the feedback for the repository in /workspace. An environment has been set up for you to start working. You may assume all necessary tools are installed. -# Issues addressed +# Issues addressed {{ issues }} # Review comments @@ -15,10 +15,13 @@ An environment has been set up for you to start working. You may assume all nece # Review thread files {{ files }} +# PR Thread Comments +{{ thread_context }} + IMPORTANT: You should ONLY interact with the environment provided to you AND NEVER ASK FOR HUMAN HELP. You SHOULD INCLUDE PROPER INDENTATION in your edit commands.{% if repo_instruction %} Some basic information about this repository: {{ repo_instruction }}{% endif %} -When you think you have fixed the issue through code changes, please finish the interaction. \ No newline at end of file +When you think you have fixed the issue through code changes, please finish the interaction. diff --git a/tests/unit/resolver/test_resolve_issues.py b/tests/unit/resolver/test_resolve_issues.py index bcf5f36481e7..6eb3bb9f2767 100644 --- a/tests/unit/resolver/test_resolve_issues.py +++ b/tests/unit/resolver/test_resolve_issues.py @@ -1,57 +1,57 @@ import os import tempfile -import pytest +from unittest.mock import AsyncMock, MagicMock, patch +import pytest -from unittest.mock import AsyncMock, patch, MagicMock +from openhands.core.config import LLMConfig +from openhands.events.action import CmdRunAction +from openhands.events.observation import CmdOutputObservation, NullObservation +from openhands.resolver.github_issue import GithubIssue, ReviewThread from openhands.resolver.issue_definitions import IssueHandler, PRHandler from openhands.resolver.resolve_issue import ( - initialize_runtime, complete_runtime, + initialize_runtime, process_issue, ) -from openhands.resolver.github_issue import GithubIssue, ReviewThread -from openhands.events.action import CmdRunAction -from openhands.events.observation import CmdOutputObservation, NullObservation from openhands.resolver.resolver_output import ResolverOutput -from openhands.core.config import LLMConfig @pytest.fixture def mock_output_dir(): with tempfile.TemporaryDirectory() as temp_dir: - repo_path = os.path.join(temp_dir, "repo") + repo_path = os.path.join(temp_dir, 'repo') # Initialize a GitHub repo in "repo" and add a commit with "README.md" os.makedirs(repo_path) - os.system(f"git init {repo_path}") - readme_path = os.path.join(repo_path, "README.md") - with open(readme_path, "w") as f: - f.write("hello world") - os.system(f"git -C {repo_path} add README.md") + os.system(f'git init {repo_path}') + readme_path = os.path.join(repo_path, 'README.md') + with open(readme_path, 'w') as f: + f.write('hello world') + os.system(f'git -C {repo_path} add README.md') os.system(f"git -C {repo_path} commit -m 'Initial commit'") yield temp_dir @pytest.fixture def mock_subprocess(): - with patch("subprocess.check_output") as mock_check_output: + with patch('subprocess.check_output') as mock_check_output: yield mock_check_output @pytest.fixture def mock_os(): - with patch("os.system") as mock_system, patch("os.path.join") as mock_join: + with patch('os.system') as mock_system, patch('os.path.join') as mock_join: yield mock_system, mock_join @pytest.fixture def mock_prompt_template(): - return "Issue: {{ body }}\n\nPlease fix this issue." + return 'Issue: {{ body }}\n\nPlease fix this issue.' @pytest.fixture def mock_followup_prompt_template(): - return "Issue context: {{ issues }}\n\nReview comments: {{ review_comments }}\n\nReview threads: {{ review_threads }}\n\nFiles: {{ files }}\n\nPlease fix this issue." + return 'Issue context: {{ issues }}\n\nReview comments: {{ review_comments }}\n\nReview threads: {{ review_threads }}\n\nFiles: {{ files }}\n\nThread comments: {{ thread_context }}\n\nPlease fix this issue.' def create_cmd_output(exit_code: int, content: str, command_id: int, command: str): @@ -64,11 +64,11 @@ def test_initialize_runtime(): mock_runtime = MagicMock() mock_runtime.run_action.side_effect = [ create_cmd_output( - exit_code=0, content="", command_id=1, command="cd /workspace" + exit_code=0, content='', command_id=1, command='cd /workspace' ), create_cmd_output( exit_code=0, - content="", + content='', command_id=2, command='git config --global core.pager ""', ), @@ -77,26 +77,26 @@ def test_initialize_runtime(): initialize_runtime(mock_runtime) assert mock_runtime.run_action.call_count == 2 - mock_runtime.run_action.assert_any_call(CmdRunAction(command="cd /workspace")) + mock_runtime.run_action.assert_any_call(CmdRunAction(command='cd /workspace')) mock_runtime.run_action.assert_any_call( CmdRunAction(command='git config --global core.pager ""') ) def test_download_issues_from_github(): - handler = IssueHandler("owner", "repo", "token") + handler = IssueHandler('owner', 'repo', 'token') mock_issues_response = MagicMock() mock_issues_response.json.side_effect = [ [ - {"number": 1, "title": "Issue 1", "body": "This is an issue"}, + {'number': 1, 'title': 'Issue 1', 'body': 'This is an issue'}, { - "number": 2, - "title": "PR 1", - "body": "This is a pull request", - "pull_request": {}, + 'number': 2, + 'title': 'PR 1', + 'body': 'This is a pull request', + 'pull_request': {}, }, - {"number": 3, "title": "Issue 2", "body": "This is another issue"}, + {'number': 3, 'title': 'Issue 2', 'body': 'This is another issue'}, ], None, ] @@ -107,41 +107,41 @@ def test_download_issues_from_github(): mock_comments_response.raise_for_status = MagicMock() def get_mock_response(url, *args, **kwargs): - if "/comments" in url: + if '/comments' in url: return mock_comments_response return mock_issues_response - with patch("requests.get", side_effect=get_mock_response): + with patch('requests.get', side_effect=get_mock_response): issues = handler.get_converted_issues() assert len(issues) == 2 - assert handler.issue_type == "issue" + assert handler.issue_type == 'issue' assert all(isinstance(issue, GithubIssue) for issue in issues) assert [issue.number for issue in issues] == [1, 3] - assert [issue.title for issue in issues] == ["Issue 1", "Issue 2"] + assert [issue.title for issue in issues] == ['Issue 1', 'Issue 2'] assert [issue.review_comments for issue in issues] == [None, None] assert [issue.closing_issues for issue in issues] == [None, None] assert [issue.thread_ids for issue in issues] == [None, None] def test_download_pr_from_github(): - handler = PRHandler("owner", "repo", "token") + handler = PRHandler('owner', 'repo', 'token') mock_pr_response = MagicMock() mock_pr_response.json.side_effect = [ [ { - "number": 1, - "title": "PR 1", - "body": "This is a pull request", - "head": {"ref": "b1"}, + 'number': 1, + 'title': 'PR 1', + 'body': 'This is a pull request', + 'head': {'ref': 'b1'}, }, { - "number": 2, - "title": "My PR", - "body": "This is another pull request", - "head": {"ref": "b2"}, + 'number': 2, + 'title': 'My PR', + 'body': 'This is another pull request', + 'head': {'ref': 'b2'}, }, - {"number": 3, "title": "PR 3", "body": "Final PR", "head": {"ref": "b3"}}, + {'number': 3, 'title': 'PR 3', 'body': 'Final PR', 'head': {'ref': 'b3'}}, ], None, ] @@ -155,55 +155,55 @@ def test_download_pr_from_github(): # Mock for GraphQL request (for download_pr_metadata) mock_graphql_response = MagicMock() mock_graphql_response.json.side_effect = lambda: { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": { - "edges": [ - {"node": {"body": "Issue 1 body", "number": 1}}, - {"node": {"body": "Issue 2 body", "number": 2}}, + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': { + 'edges': [ + {'node': {'body': 'Issue 1 body', 'number': 1}}, + {'node': {'body': 'Issue 2 body', 'number': 2}}, ] }, - "reviewThreads": { - "edges": [ + 'reviewThreads': { + 'edges': [ { - "node": { - "isResolved": False, - "id": "1", - "comments": { - "nodes": [ + 'node': { + 'isResolved': False, + 'id': '1', + 'comments': { + 'nodes': [ { - "body": "Unresolved comment 1", - "path": "/frontend/header.tsx", + 'body': 'Unresolved comment 1', + 'path': '/frontend/header.tsx', }, - {"body": "Follow up thread"}, + {'body': 'Follow up thread'}, ] }, } }, { - "node": { - "isResolved": True, - "id": "2", - "comments": { - "nodes": [ + 'node': { + 'isResolved': True, + 'id': '2', + 'comments': { + 'nodes': [ { - "body": "Resolved comment 1", - "path": "/some/file.py", + 'body': 'Resolved comment 1', + 'path': '/some/file.py', } ] }, } }, { - "node": { - "isResolved": False, - "id": "3", - "comments": { - "nodes": [ + 'node': { + 'isResolved': False, + 'id': '3', + 'comments': { + 'nodes': [ { - "body": "Unresolved comment 3", - "path": "/another/file.py", + 'body': 'Unresolved comment 3', + 'path': '/another/file.py', } ] }, @@ -219,34 +219,34 @@ def test_download_pr_from_github(): mock_graphql_response.raise_for_status = MagicMock() def get_mock_response(url, *args, **kwargs): - if "/comments" in url: + if '/comments' in url: return mock_comments_response return mock_pr_response - with patch("requests.get", side_effect=get_mock_response): - with patch("requests.post", return_value=mock_graphql_response): + with patch('requests.get', side_effect=get_mock_response): + with patch('requests.post', return_value=mock_graphql_response): issues = handler.get_converted_issues() assert len(issues) == 3 - assert handler.issue_type == "pr" + assert handler.issue_type == 'pr' assert all(isinstance(issue, GithubIssue) for issue in issues) assert [issue.number for issue in issues] == [1, 2, 3] - assert [issue.title for issue in issues] == ["PR 1", "My PR", "PR 3"] - assert [issue.head_branch for issue in issues] == ["b1", "b2", "b3"] + assert [issue.title for issue in issues] == ['PR 1', 'My PR', 'PR 3'] + assert [issue.head_branch for issue in issues] == ['b1', 'b2', 'b3'] assert len(issues[0].review_threads) == 2 # Only unresolved threads assert ( issues[0].review_threads[0].comment - == "Unresolved comment 1\n---\nlatest feedback:\nFollow up thread\n" + == 'Unresolved comment 1\n---\nlatest feedback:\nFollow up thread\n' ) - assert issues[0].review_threads[0].files == ["/frontend/header.tsx"] + assert issues[0].review_threads[0].files == ['/frontend/header.tsx'] assert ( issues[0].review_threads[1].comment - == "latest feedback:\nUnresolved comment 3\n" + == 'latest feedback:\nUnresolved comment 3\n' ) - assert issues[0].review_threads[1].files == ["/another/file.py"] - assert issues[0].closing_issues == ["Issue 1 body", "Issue 2 body"] - assert issues[0].thread_ids == ["1", "3"] + assert issues[0].review_threads[1].files == ['/another/file.py'] + assert issues[0].closing_issues == ['Issue 1 body', 'Issue 2 body'] + assert issues[0].thread_ids == ['1', '3'] @pytest.mark.asyncio @@ -254,34 +254,34 @@ async def test_complete_runtime(): mock_runtime = MagicMock() mock_runtime.run_action.side_effect = [ create_cmd_output( - exit_code=0, content="", command_id=1, command="cd /workspace" + exit_code=0, content='', command_id=1, command='cd /workspace' ), create_cmd_output( exit_code=0, - content="", + content='', command_id=2, command='git config --global core.pager ""', ), create_cmd_output( exit_code=0, - content="", + content='', command_id=3, - command="git config --global --add safe.directory /workspace", + command='git config --global --add safe.directory /workspace', ), create_cmd_output( exit_code=0, - content="", + content='', command_id=4, - command="git diff base_commit_hash fix", + command='git diff base_commit_hash fix', ), create_cmd_output( - exit_code=0, content="git diff content", command_id=5, command="git apply" + exit_code=0, content='git diff content', command_id=5, command='git apply' ), ] - result = await complete_runtime(mock_runtime, "base_commit_hash") + result = await complete_runtime(mock_runtime, 'base_commit_hash') - assert result == {"git_patch": "git diff content"} + assert result == {'git_patch': 'git diff content'} assert mock_runtime.run_action.call_count == 5 @@ -296,65 +296,65 @@ async def test_process_issue(mock_output_dir, mock_prompt_template): # Set up test data issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', ) - base_commit = "abcdef1234567890" - repo_instruction = "Resolve this repo" + base_commit = 'abcdef1234567890' + repo_instruction = 'Resolve this repo' max_iterations = 5 - llm_config = LLMConfig(model="test_model", api_key="test_api_key") - runtime_container_image = "test_image:latest" + llm_config = LLMConfig(model='test_model', api_key='test_api_key') + runtime_container_image = 'test_image:latest' # Test cases for different scenarios test_cases = [ { - "name": "successful_run", - "run_controller_return": MagicMock( - history=[NullObservation(content="")], + 'name': 'successful_run', + 'run_controller_return': MagicMock( + history=[NullObservation(content='')], metrics=MagicMock( - get=MagicMock(return_value={"test_result": "passed"}) + get=MagicMock(return_value={'test_result': 'passed'}) ), last_error=None, ), - "run_controller_raises": None, - "expected_success": True, - "expected_error": None, - "expected_explanation": "Issue resolved successfully", + 'run_controller_raises': None, + 'expected_success': True, + 'expected_error': None, + 'expected_explanation': 'Issue resolved successfully', }, { - "name": "value_error", - "run_controller_return": None, - "run_controller_raises": ValueError("Test value error"), - "expected_success": False, - "expected_error": "Agent failed to run or crashed", - "expected_explanation": "Agent failed to run", + 'name': 'value_error', + 'run_controller_return': None, + 'run_controller_raises': ValueError('Test value error'), + 'expected_success': False, + 'expected_error': 'Agent failed to run or crashed', + 'expected_explanation': 'Agent failed to run', }, { - "name": "runtime_error", - "run_controller_return": None, - "run_controller_raises": RuntimeError("Test runtime error"), - "expected_success": False, - "expected_error": "Agent failed to run or crashed", - "expected_explanation": "Agent failed to run", + 'name': 'runtime_error', + 'run_controller_return': None, + 'run_controller_raises': RuntimeError('Test runtime error'), + 'expected_success': False, + 'expected_error': 'Agent failed to run or crashed', + 'expected_explanation': 'Agent failed to run', }, { - "name": "json_decode_error", - "run_controller_return": MagicMock( - history=[NullObservation(content="")], + 'name': 'json_decode_error', + 'run_controller_return': MagicMock( + history=[NullObservation(content='')], metrics=MagicMock( - get=MagicMock(return_value={"test_result": "passed"}) + get=MagicMock(return_value={'test_result': 'passed'}) ), last_error=None, ), - "run_controller_raises": None, - "expected_success": True, - "expected_error": None, - "expected_explanation": "Non-JSON explanation", - "is_pr": True, - "comment_success": [ + 'run_controller_raises': None, + 'expected_success': True, + 'expected_error': None, + 'expected_explanation': 'Non-JSON explanation', + 'is_pr': True, + 'comment_success': [ True, False, ], # To trigger the PR success logging code path @@ -371,31 +371,31 @@ async def test_process_issue(mock_output_dir, mock_prompt_template): # Mock return values mock_create_runtime.return_value = MagicMock(connect=AsyncMock()) - if test_case["run_controller_raises"]: - mock_run_controller.side_effect = test_case["run_controller_raises"] + if test_case['run_controller_raises']: + mock_run_controller.side_effect = test_case['run_controller_raises'] else: - mock_run_controller.return_value = test_case["run_controller_return"] + mock_run_controller.return_value = test_case['run_controller_return'] mock_run_controller.side_effect = None - mock_complete_runtime.return_value = {"git_patch": "test patch"} + mock_complete_runtime.return_value = {'git_patch': 'test patch'} handler_instance.guess_success.return_value = ( - test_case["expected_success"], - test_case.get("comment_success", None), - test_case["expected_explanation"], + test_case['expected_success'], + test_case.get('comment_success', None), + test_case['expected_explanation'], ) - handler_instance.get_instruction.return_value = ("Test instruction", []) - handler_instance.issue_type = "pr" if test_case.get("is_pr", False) else "issue" + handler_instance.get_instruction.return_value = ('Test instruction', []) + handler_instance.issue_type = 'pr' if test_case.get('is_pr', False) else 'issue' with patch( - "openhands.resolver.resolve_issue.create_runtime", mock_create_runtime + 'openhands.resolver.resolve_issue.create_runtime', mock_create_runtime ), patch( - "openhands.resolver.resolve_issue.initialize_runtime", + 'openhands.resolver.resolve_issue.initialize_runtime', mock_initialize_runtime, ), patch( - "openhands.resolver.resolve_issue.run_controller", mock_run_controller + 'openhands.resolver.resolve_issue.run_controller', mock_run_controller ), patch( - "openhands.resolver.resolve_issue.complete_runtime", mock_complete_runtime - ), patch("openhands.resolver.resolve_issue.logger"): + 'openhands.resolver.resolve_issue.complete_runtime', mock_complete_runtime + ), patch('openhands.resolver.resolve_issue.logger'): # Call the function result = await process_issue( issue, @@ -411,15 +411,15 @@ async def test_process_issue(mock_output_dir, mock_prompt_template): ) # Assert the result - expected_issue_type = "pr" if test_case.get("is_pr", False) else "issue" + expected_issue_type = 'pr' if test_case.get('is_pr', False) else 'issue' assert handler_instance.issue_type == expected_issue_type assert isinstance(result, ResolverOutput) assert result.issue == issue assert result.base_commit == base_commit - assert result.git_patch == "test patch" - assert result.success == test_case["expected_success"] - assert result.success_explanation == test_case["expected_explanation"] - assert result.error == test_case["expected_error"] + assert result.git_patch == 'test patch' + assert result.success == test_case['expected_success'] + assert result.success_explanation == test_case['expected_explanation'] + assert result.error == test_case['expected_error'] # Assert that the mocked functions were called mock_create_runtime.assert_called_once() @@ -428,7 +428,7 @@ async def test_process_issue(mock_output_dir, mock_prompt_template): mock_complete_runtime.assert_called_once() # Assert that guess_success was called only for successful runs - if test_case["expected_success"]: + if test_case['expected_success']: handler_instance.guess_success.assert_called_once() else: handler_instance.guess_success.assert_not_called() @@ -436,60 +436,64 @@ async def test_process_issue(mock_output_dir, mock_prompt_template): def test_get_instruction(mock_prompt_template, mock_followup_prompt_template): issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=123, - title="Test Issue", - body="This is a test issue refer to image ![First Image](https://sampleimage.com/image1.png)", + title='Test Issue', + body='This is a test issue refer to image ![First Image](https://sampleimage.com/image1.png)', ) - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') instruction, images_urls = issue_handler.get_instruction( issue, mock_prompt_template, None ) - expected_instruction = "Issue: Test Issue\n\nThis is a test issue refer to image ![First Image](https://sampleimage.com/image1.png)\n\nPlease fix this issue." + expected_instruction = 'Issue: Test Issue\n\nThis is a test issue refer to image ![First Image](https://sampleimage.com/image1.png)\n\nPlease fix this issue.' - assert images_urls == ["https://sampleimage.com/image1.png"] - assert issue_handler.issue_type == "issue" + assert images_urls == ['https://sampleimage.com/image1.png'] + assert issue_handler.issue_type == 'issue' assert instruction == expected_instruction issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=123, - title="Test Issue", - body="This is a test issue", - closing_issues=["Issue 1 fix the type"], + title='Test Issue', + body='This is a test issue', + closing_issues=['Issue 1 fix the type'], review_threads=[ ReviewThread( comment="There is still a typo 'pthon' instead of 'python'", files=[] ) ], + thread_comments=[ + "I've left review comments, please address them", + 'This is a valid concern.', + ], ) - pr_handler = PRHandler("owner", "repo", "token") + pr_handler = PRHandler('owner', 'repo', 'token') instruction, images_urls = pr_handler.get_instruction( issue, mock_followup_prompt_template, None ) - expected_instruction = "Issue context: [\n \"Issue 1 fix the type\"\n]\n\nReview comments: None\n\nReview threads: [\n \"There is still a typo 'pthon' instead of 'python'\"\n]\n\nFiles: []\n\nPlease fix this issue." + expected_instruction = "Issue context: [\n \"Issue 1 fix the type\"\n]\n\nReview comments: None\n\nReview threads: [\n \"There is still a typo 'pthon' instead of 'python'\"\n]\n\nFiles: []\n\nThread comments: I've left review comments, please address them\n---\nThis is a valid concern.\n\nPlease fix this issue." assert images_urls == [] - assert pr_handler.issue_type == "pr" + assert pr_handler.issue_type == 'pr' assert instruction == expected_instruction def test_file_instruction(): issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=123, - title="Test Issue", - body="This is a test issue ![image](https://sampleimage.com/sample.png)", + title='Test Issue', + body='This is a test issue ![image](https://sampleimage.com/sample.png)', ) # load prompt from openhands/resolver/prompts/resolve/basic.jinja - with open("openhands/resolver/prompts/resolve/basic.jinja", "r") as f: + with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f: prompt = f.read() # Test without thread comments - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') instruction, images_urls = issue_handler.get_instruction(issue, prompt, None) expected_instruction = """Please fix the following issue for the repository in /workspace. An environment has been set up for you to start working. You may assume all necessary tools are installed. @@ -505,28 +509,28 @@ def test_file_instruction(): When you think you have fixed the issue through code changes, please finish the interaction.""" assert instruction == expected_instruction - assert images_urls == ["https://sampleimage.com/sample.png"] + assert images_urls == ['https://sampleimage.com/sample.png'] def test_file_instruction_with_repo_instruction(): issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=123, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', ) # load prompt from openhands/resolver/prompts/resolve/basic.jinja - with open("openhands/resolver/prompts/resolve/basic.jinja", "r") as f: + with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f: prompt = f.read() # load repo instruction from openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt with open( - "openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt", - "r", + 'openhands/resolver/prompts/repo_instructions/all-hands-ai___openhands-resolver.txt', + 'r', ) as f: repo_instruction = f.read() - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') instruction, image_urls = issue_handler.get_instruction( issue, prompt, repo_instruction ) @@ -549,226 +553,226 @@ def test_file_instruction_with_repo_instruction(): When you think you have fixed the issue through code changes, please finish the interaction.""" assert instruction == expected_instruction - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert image_urls == [] def test_guess_success(): mock_issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', ) mock_history = [ create_cmd_output( - exit_code=0, content="", command_id=1, command="cd /workspace" + exit_code=0, content='', command_id=1, command='cd /workspace' ) ] - mock_llm_config = LLMConfig(model="test_model", api_key="test_api_key") + mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key') mock_completion_response = MagicMock() mock_completion_response.choices = [ MagicMock( message=MagicMock( - content="--- success\ntrue\n--- explanation\nIssue resolved successfully" + content='--- success\ntrue\n--- explanation\nIssue resolved successfully' ) ) ] - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') - with patch("litellm.completion", MagicMock(return_value=mock_completion_response)): + with patch('litellm.completion', MagicMock(return_value=mock_completion_response)): success, comment_success, explanation = issue_handler.guess_success( mock_issue, mock_history, mock_llm_config ) - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert comment_success is None assert success - assert explanation == "Issue resolved successfully" + assert explanation == 'Issue resolved successfully' def test_guess_success_with_thread_comments(): mock_issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', thread_comments=[ - "First comment", - "Second comment", - "latest feedback:\nPlease add tests", + 'First comment', + 'Second comment', + 'latest feedback:\nPlease add tests', ], ) - mock_history = [MagicMock(message="I have added tests for this case")] - mock_llm_config = LLMConfig(model="test_model", api_key="test_api_key") + mock_history = [MagicMock(message='I have added tests for this case')] + mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key') mock_completion_response = MagicMock() mock_completion_response.choices = [ MagicMock( message=MagicMock( - content="--- success\ntrue\n--- explanation\nTests have been added to verify thread comments handling" + content='--- success\ntrue\n--- explanation\nTests have been added to verify thread comments handling' ) ) ] - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') - with patch("litellm.completion", MagicMock(return_value=mock_completion_response)): + with patch('litellm.completion', MagicMock(return_value=mock_completion_response)): success, comment_success, explanation = issue_handler.guess_success( mock_issue, mock_history, mock_llm_config ) - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert comment_success is None assert success - assert "Tests have been added" in explanation + assert 'Tests have been added' in explanation def test_instruction_with_thread_comments(): # Create an issue with thread comments issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=123, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', thread_comments=[ - "First comment", - "Second comment", - "latest feedback:\nPlease add tests", + 'First comment', + 'Second comment', + 'latest feedback:\nPlease add tests', ], ) # Load the basic prompt template - with open("openhands/resolver/prompts/resolve/basic.jinja", "r") as f: + with open('openhands/resolver/prompts/resolve/basic.jinja', 'r') as f: prompt = f.read() - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') instruction, images_urls = issue_handler.get_instruction(issue, prompt, None) # Verify that thread comments are included in the instruction - assert "First comment" in instruction - assert "Second comment" in instruction - assert "Please add tests" in instruction - assert "Issue Thread Comments:" in instruction + assert 'First comment' in instruction + assert 'Second comment' in instruction + assert 'Please add tests' in instruction + assert 'Issue Thread Comments:' in instruction assert images_urls == [] def test_guess_success_failure(): mock_issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', thread_comments=[ - "First comment", - "Second comment", - "latest feedback:\nPlease add tests", + 'First comment', + 'Second comment', + 'latest feedback:\nPlease add tests', ], ) - mock_history = [MagicMock(message="I have added tests for this case")] - mock_llm_config = LLMConfig(model="test_model", api_key="test_api_key") + mock_history = [MagicMock(message='I have added tests for this case')] + mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key') mock_completion_response = MagicMock() mock_completion_response.choices = [ MagicMock( message=MagicMock( - content="--- success\ntrue\n--- explanation\nTests have been added to verify thread comments handling" + content='--- success\ntrue\n--- explanation\nTests have been added to verify thread comments handling' ) ) ] - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') - with patch("litellm.completion", MagicMock(return_value=mock_completion_response)): + with patch('litellm.completion', MagicMock(return_value=mock_completion_response)): success, comment_success, explanation = issue_handler.guess_success( mock_issue, mock_history, mock_llm_config ) - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert comment_success is None assert success - assert "Tests have been added" in explanation + assert 'Tests have been added' in explanation def test_guess_success_negative_case(): mock_issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', ) mock_history = [ create_cmd_output( - exit_code=0, content="", command_id=1, command="cd /workspace" + exit_code=0, content='', command_id=1, command='cd /workspace' ) ] - mock_llm_config = LLMConfig(model="test_model", api_key="test_api_key") + mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key') mock_completion_response = MagicMock() mock_completion_response.choices = [ MagicMock( message=MagicMock( - content="--- success\nfalse\n--- explanation\nIssue not resolved" + content='--- success\nfalse\n--- explanation\nIssue not resolved' ) ) ] - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') - with patch("litellm.completion", MagicMock(return_value=mock_completion_response)): + with patch('litellm.completion', MagicMock(return_value=mock_completion_response)): success, comment_success, explanation = issue_handler.guess_success( mock_issue, mock_history, mock_llm_config ) - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert comment_success is None assert not success - assert explanation == "Issue not resolved" + assert explanation == 'Issue not resolved' def test_guess_success_invalid_output(): mock_issue = GithubIssue( - owner="test_owner", - repo="test_repo", + owner='test_owner', + repo='test_repo', number=1, - title="Test Issue", - body="This is a test issue", + title='Test Issue', + body='This is a test issue', ) mock_history = [ create_cmd_output( - exit_code=0, content="", command_id=1, command="cd /workspace" + exit_code=0, content='', command_id=1, command='cd /workspace' ) ] - mock_llm_config = LLMConfig(model="test_model", api_key="test_api_key") + mock_llm_config = LLMConfig(model='test_model', api_key='test_api_key') mock_completion_response = MagicMock() mock_completion_response.choices = [ - MagicMock(message=MagicMock(content="This is not a valid output")) + MagicMock(message=MagicMock(content='This is not a valid output')) ] - issue_handler = IssueHandler("owner", "repo", "token") + issue_handler = IssueHandler('owner', 'repo', 'token') - with patch("litellm.completion", MagicMock(return_value=mock_completion_response)): + with patch('litellm.completion', MagicMock(return_value=mock_completion_response)): success, comment_success, explanation = issue_handler.guess_success( mock_issue, mock_history, mock_llm_config ) - assert issue_handler.issue_type == "issue" + assert issue_handler.issue_type == 'issue' assert comment_success is None assert not success assert ( explanation - == "Failed to decode answer from LLM response: This is not a valid output" + == 'Failed to decode answer from LLM response: This is not a valid output' ) def test_download_pr_with_review_comments(): - handler = PRHandler("owner", "repo", "token") + handler = PRHandler('owner', 'repo', 'token') mock_pr_response = MagicMock() mock_pr_response.json.side_effect = [ [ { - "number": 1, - "title": "PR 1", - "body": "This is a pull request", - "head": {"ref": "b1"}, + 'number': 1, + 'title': 'PR 1', + 'body': 'This is a pull request', + 'head': {'ref': 'b1'}, }, ], None, @@ -783,14 +787,14 @@ def test_download_pr_with_review_comments(): # Mock for GraphQL request with review comments but no threads mock_graphql_response = MagicMock() mock_graphql_response.json.side_effect = lambda: { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": { - "nodes": [ - {"body": "Please fix this typo"}, - {"body": "Add more tests"}, + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': { + 'nodes': [ + {'body': 'Please fix this typo'}, + {'body': 'Add more tests'}, ] }, } @@ -801,32 +805,32 @@ def test_download_pr_with_review_comments(): mock_graphql_response.raise_for_status = MagicMock() def get_mock_response(url, *args, **kwargs): - if "/comments" in url: + if '/comments' in url: return mock_comments_response return mock_pr_response - with patch("requests.get", side_effect=get_mock_response): - with patch("requests.post", return_value=mock_graphql_response): + with patch('requests.get', side_effect=get_mock_response): + with patch('requests.post', return_value=mock_graphql_response): issues = handler.get_converted_issues() assert len(issues) == 1 - assert handler.issue_type == "pr" + assert handler.issue_type == 'pr' assert isinstance(issues[0], GithubIssue) assert issues[0].number == 1 - assert issues[0].title == "PR 1" - assert issues[0].head_branch == "b1" + assert issues[0].title == 'PR 1' + assert issues[0].head_branch == 'b1' # Verify review comments are set but threads are empty assert len(issues[0].review_comments) == 2 - assert issues[0].review_comments[0] == "Please fix this typo" - assert issues[0].review_comments[1] == "Add more tests" + assert issues[0].review_comments[0] == 'Please fix this typo' + assert issues[0].review_comments[1] == 'Add more tests' assert not issues[0].review_threads assert not issues[0].closing_issues assert not issues[0].thread_ids def test_download_issue_with_specific_comment(): - handler = IssueHandler("owner", "repo", "token") + handler = IssueHandler('owner', 'repo', 'token') # Define the specific comment_id to filter specific_comment_id = 101 @@ -835,7 +839,7 @@ def test_download_issue_with_specific_comment(): mock_issue_response = MagicMock() mock_issue_response.json.side_effect = [ [ - {"number": 1, "title": "Issue 1", "body": "This is an issue"}, + {'number': 1, 'title': 'Issue 1', 'body': 'This is an issue'}, ], None, ] @@ -844,32 +848,32 @@ def test_download_issue_with_specific_comment(): mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ { - "id": specific_comment_id, - "body": "Specific comment body", - "issue_url": "https://api.github.com/repos/owner/repo/issues/1", + 'id': specific_comment_id, + 'body': 'Specific comment body', + 'issue_url': 'https://api.github.com/repos/owner/repo/issues/1', }, { - "id": 102, - "body": "Another comment body", - "issue_url": "https://api.github.com/repos/owner/repo/issues/2", + 'id': 102, + 'body': 'Another comment body', + 'issue_url': 'https://api.github.com/repos/owner/repo/issues/2', }, ] mock_comments_response.raise_for_status = MagicMock() def get_mock_response(url, *args, **kwargs): - if "/comments" in url: + if '/comments' in url: return mock_comments_response return mock_issue_response - with patch("requests.get", side_effect=get_mock_response): + with patch('requests.get', side_effect=get_mock_response): issues = handler.get_converted_issues(comment_id=specific_comment_id) assert len(issues) == 1 assert issues[0].number == 1 - assert issues[0].title == "Issue 1" - assert issues[0].thread_comments == ["Specific comment body"] + assert issues[0].title == 'Issue 1' + assert issues[0].thread_comments == ['Specific comment body'] -if __name__ == "__main__": +if __name__ == '__main__': pytest.main() From 422104c8778b51e02c6108d5517e33de34253f43 Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Mon, 18 Nov 2024 20:21:46 -0600 Subject: [PATCH 05/34] fix #5111: add FunctionCallNotExistsError to handle cases where tool calling failed (#5113) --- openhands/agenthub/codeact_agent/function_calling.py | 5 ++++- openhands/controller/agent_controller.py | 2 ++ openhands/core/exceptions.py | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/openhands/agenthub/codeact_agent/function_calling.py b/openhands/agenthub/codeact_agent/function_calling.py index 42ce1f98db87..a4ee35ff7b59 100644 --- a/openhands/agenthub/codeact_agent/function_calling.py +++ b/openhands/agenthub/codeact_agent/function_calling.py @@ -12,6 +12,7 @@ ModelResponse, ) +from openhands.core.exceptions import FunctionCallNotExistsError from openhands.core.logger import openhands_logger as logger from openhands.events.action import ( Action, @@ -484,7 +485,9 @@ def response_to_actions(response: ModelResponse) -> list[Action]: elif tool_call.function.name == 'browser': action = BrowseInteractiveAction(browser_actions=arguments['code']) else: - raise RuntimeError(f'Unknown tool call: {tool_call.function.name}') + raise FunctionCallNotExistsError( + f'Tool {tool_call.function.name} is not registered. (arguments: {arguments}). Please check the tool name and retry with an existing tool.' + ) # We only add thought to the first action if i == 0: diff --git a/openhands/controller/agent_controller.py b/openhands/controller/agent_controller.py index 9ba8c3d0a154..f9e4a8edb555 100644 --- a/openhands/controller/agent_controller.py +++ b/openhands/controller/agent_controller.py @@ -12,6 +12,7 @@ from openhands.controller.stuck import StuckDetector from openhands.core.config import AgentConfig, LLMConfig from openhands.core.exceptions import ( + FunctionCallNotExistsError, FunctionCallValidationError, LLMMalformedActionError, LLMNoActionError, @@ -488,6 +489,7 @@ async def _step(self) -> None: LLMNoActionError, LLMResponseError, FunctionCallValidationError, + FunctionCallNotExistsError, ) as e: self.event_stream.add_event( ErrorObservation( diff --git a/openhands/core/exceptions.py b/openhands/core/exceptions.py index 0c0a771191b4..bf5a29f60752 100644 --- a/openhands/core/exceptions.py +++ b/openhands/core/exceptions.py @@ -114,3 +114,10 @@ class FunctionCallValidationError(Exception): def __init__(self, message): super().__init__(message) + + +class FunctionCallNotExistsError(Exception): + """Exception raised when an LLM call a tool that is not registered.""" + + def __init__(self, message): + super().__init__(message) From a531413d8649640842d2e639e15b4e7ecadf35c5 Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Mon, 18 Nov 2024 20:22:55 -0600 Subject: [PATCH 06/34] fix(eval): support setting hard timeout per evaluation instance (#5110) --- evaluation/swe_bench/run_infer.py | 2 +- evaluation/utils/shared.py | 61 ++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/evaluation/swe_bench/run_infer.py b/evaluation/swe_bench/run_infer.py index 386c0dd19238..9cb9dd77f498 100644 --- a/evaluation/swe_bench/run_infer.py +++ b/evaluation/swe_bench/run_infer.py @@ -145,7 +145,7 @@ def get_config( platform='linux/amd64', api_key=os.environ.get('ALLHANDS_API_KEY', None), remote_runtime_api_url=os.environ.get('SANDBOX_REMOTE_RUNTIME_API_URL'), - keep_remote_runtime_alive=False, + keep_runtime_alive=False, remote_runtime_init_timeout=3600, ), # do not mount workspace diff --git a/evaluation/utils/shared.py b/evaluation/utils/shared.py index 847eb16bb32e..517ecc523581 100644 --- a/evaluation/utils/shared.py +++ b/evaluation/utils/shared.py @@ -3,9 +3,11 @@ import multiprocessing as mp import os import pathlib +import signal import subprocess import time import traceback +from contextlib import contextmanager from typing import Any, Awaitable, Callable, TextIO import pandas as pd @@ -92,6 +94,27 @@ class EvalException(Exception): pass +class EvalTimeoutException(Exception): + pass + + +@contextmanager +def timeout(seconds: int): + def timeout_handler(signum, frame): + raise EvalTimeoutException(f'Function timed out after {seconds} seconds') + + # Set up the signal handler + original_handler = signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(seconds) + + try: + yield + finally: + # Restore the original handler and disable the alarm + signal.alarm(0) + signal.signal(signal.SIGALRM, original_handler) + + def codeact_user_response( state: State, encapsulate_solution: bool = False, @@ -280,15 +303,33 @@ def _process_instance_wrapper( metadata: EvalMetadata, use_mp: bool, max_retries: int = 5, + timeout_seconds: int | None = None, ) -> EvalOutput: - """Wrap the process_instance_func to handle retries and errors. - - Retry an instance up to max_retries times if it fails (e.g., due to transient network/runtime issues). - """ + """Wrap the process_instance_func to handle retries and errors.""" for attempt in range(max_retries + 1): try: - result = process_instance_func(instance, metadata, use_mp) + if timeout_seconds is not None: + with timeout(timeout_seconds): + result = process_instance_func(instance, metadata, use_mp) + else: + result = process_instance_func(instance, metadata, use_mp) return result + except EvalTimeoutException as e: + error = f'Timeout after {timeout_seconds} seconds' + stacktrace = traceback.format_exc() + msg = ( + '-' * 10 + + '\n' + + f'Timeout ({timeout_seconds} seconds) in instance [{instance.instance_id}], Stopped evaluation for this instance.' + + '\n' + + '-' * 10 + ) + logger.exception(e) + return EvalOutput( + instance_id=instance.instance_id, + test_result={}, + error=error, + ) except Exception as e: error = str(e) stacktrace = traceback.format_exc() @@ -337,6 +378,7 @@ def run_evaluation( [pd.Series, EvalMetadata, bool], Awaitable[EvalOutput] ], max_retries: int = 5, # number of retries for each instance + timeout_seconds: int | None = None, ): use_multiprocessing = num_workers > 1 @@ -357,7 +399,14 @@ def run_evaluation( if use_multiprocessing: with mp.Pool(num_workers) as pool: args_iter = ( - (process_instance_func, instance, metadata, True, max_retries) + ( + process_instance_func, + instance, + metadata, + True, + max_retries, + timeout_seconds, + ) for _, instance in dataset.iterrows() ) results = pool.imap_unordered(_process_instance_wrapper_mp, args_iter) From ca64c69b4a257d703e68ff44f9b4e4f435eabcfb Mon Sep 17 00:00:00 2001 From: young010101 <93481273+young010101@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:45:06 +0800 Subject: [PATCH 07/34] Docs update runtime link (#5117) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e69538d21e0b..847b6c469812 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,7 +54,7 @@ The agent needs a place to run code and commands. When you run OpenHands on your to do this by default. But there are other ways of creating a sandbox for the agent. If you work for a company that provides a cloud-based runtime, you could help us add support for that runtime -by implementing the [interface specified here](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/runtime/runtime.py). +by implementing the [interface specified here](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/runtime/base.py). #### Testing When you write code, it is also good to write tests. Please navigate to the `tests` folder to see existing test suites. From 2c580387c56273be95280ffb245a430a377cc339 Mon Sep 17 00:00:00 2001 From: Raymond Xu Date: Tue, 19 Nov 2024 04:16:29 -0800 Subject: [PATCH 08/34] Allow to merge to a specific target branch instead of main (#5109) --- openhands/resolver/send_pull_request.py | 32 +++++-- tests/unit/resolver/test_send_pull_request.py | 91 ++++++++++++++++--- 2 files changed, 101 insertions(+), 22 deletions(-) diff --git a/openhands/resolver/send_pull_request.py b/openhands/resolver/send_pull_request.py index eade7fcfc419..8a9d6118bedd 100644 --- a/openhands/resolver/send_pull_request.py +++ b/openhands/resolver/send_pull_request.py @@ -203,6 +203,7 @@ def send_pull_request( pr_type: str, fork_owner: str | None = None, additional_message: str | None = None, + target_branch: str | None = None, ) -> str: if pr_type not in ['branch', 'draft', 'ready']: raise ValueError(f'Invalid pr_type: {pr_type}') @@ -224,12 +225,19 @@ def send_pull_request( attempt += 1 branch_name = f'{base_branch_name}-try{attempt}' - # Get the default branch - print('Getting default branch...') - response = requests.get(f'{base_url}', headers=headers) - response.raise_for_status() - default_branch = response.json()['default_branch'] - print(f'Default branch: {default_branch}') + # Get the default branch or use specified target branch + print('Getting base branch...') + if target_branch: + base_branch = target_branch + # Verify the target branch exists + response = requests.get(f'{base_url}/branches/{target_branch}', headers=headers) + if response.status_code != 200: + raise ValueError(f'Target branch {target_branch} does not exist') + else: + response = requests.get(f'{base_url}', headers=headers) + response.raise_for_status() + base_branch = response.json()['default_branch'] + print(f'Base branch: {base_branch}') # Create and checkout the new branch print('Creating new branch...') @@ -279,7 +287,7 @@ def send_pull_request( 'title': pr_title, # No need to escape title for GitHub API 'body': pr_body, 'head': branch_name, - 'base': default_branch, + 'base': base_branch, 'draft': pr_type == 'draft', } response = requests.post(f'{base_url}/pulls', headers=headers, json=data) @@ -435,6 +443,7 @@ def process_single_issue( llm_config: LLMConfig, fork_owner: str | None, send_on_failure: bool, + target_branch: str | None = None, ) -> None: if not resolver_output.success and not send_on_failure: print( @@ -484,6 +493,7 @@ def process_single_issue( llm_config=llm_config, fork_owner=fork_owner, additional_message=resolver_output.success_explanation, + target_branch=target_branch, ) @@ -508,6 +518,7 @@ def process_all_successful_issues( llm_config, fork_owner, False, + None, ) @@ -573,6 +584,12 @@ def main(): default=None, help='Base URL for the LLM model.', ) + parser.add_argument( + '--target-branch', + type=str, + default=None, + help='Target branch to create the pull request against (defaults to repository default branch)', + ) my_args = parser.parse_args() github_token = ( @@ -625,6 +642,7 @@ def main(): llm_config, my_args.fork_owner, my_args.send_on_failure, + my_args.target_branch, ) diff --git a/tests/unit/resolver/test_send_pull_request.py b/tests/unit/resolver/test_send_pull_request.py index 951be1af006c..f83e2e97ec2f 100644 --- a/tests/unit/resolver/test_send_pull_request.py +++ b/tests/unit/resolver/test_send_pull_request.py @@ -322,7 +322,17 @@ def test_update_existing_pull_request( ) -@pytest.mark.parametrize('pr_type', ['branch', 'draft', 'ready']) +@pytest.mark.parametrize( + 'pr_type,target_branch', + [ + ('branch', None), + ('draft', None), + ('ready', None), + ('branch', 'feature'), + ('draft', 'develop'), + ('ready', 'staging'), + ], +) @patch('subprocess.run') @patch('requests.post') @patch('requests.get') @@ -334,14 +344,22 @@ def test_send_pull_request( mock_output_dir, mock_llm_config, pr_type, + target_branch, ): repo_path = os.path.join(mock_output_dir, 'repo') - # Mock API responses - mock_get.side_effect = [ - MagicMock(status_code=404), # Branch doesn't exist - MagicMock(json=lambda: {'default_branch': 'main'}), - ] + # Mock API responses based on whether target_branch is specified + if target_branch: + mock_get.side_effect = [ + MagicMock(status_code=404), # Branch doesn't exist + MagicMock(status_code=200), # Target branch exists + ] + else: + mock_get.side_effect = [ + MagicMock(status_code=404), # Branch doesn't exist + MagicMock(json=lambda: {'default_branch': 'main'}), # Get default branch + ] + mock_post.return_value.json.return_value = { 'html_url': 'https://github.com/test-owner/test-repo/pull/1' } @@ -360,10 +378,12 @@ def test_send_pull_request( patch_dir=repo_path, pr_type=pr_type, llm_config=mock_llm_config, + target_branch=target_branch, ) # Assert API calls - assert mock_get.call_count == 2 + expected_get_calls = 2 + assert mock_get.call_count == expected_get_calls # Check branch creation and push assert mock_run.call_count == 2 @@ -401,10 +421,41 @@ def test_send_pull_request( assert post_data['title'] == 'Fix issue #42: Test Issue' assert post_data['body'].startswith('This pull request fixes #42.') assert post_data['head'] == 'openhands-fix-issue-42' - assert post_data['base'] == 'main' + assert post_data['base'] == (target_branch if target_branch else 'main') assert post_data['draft'] == (pr_type == 'draft') +@patch('requests.get') +def test_send_pull_request_invalid_target_branch( + mock_get, mock_github_issue, mock_output_dir, mock_llm_config +): + """Test that an error is raised when specifying a non-existent target branch""" + repo_path = os.path.join(mock_output_dir, 'repo') + + # Mock API response for non-existent branch + mock_get.side_effect = [ + MagicMock(status_code=404), # Branch doesn't exist + MagicMock(status_code=404), # Target branch doesn't exist + ] + + # Test that ValueError is raised when target branch doesn't exist + with pytest.raises( + ValueError, match='Target branch nonexistent-branch does not exist' + ): + send_pull_request( + github_issue=mock_github_issue, + github_token='test-token', + github_username='test-user', + patch_dir=repo_path, + pr_type='ready', + llm_config=mock_llm_config, + target_branch='nonexistent-branch', + ) + + # Verify API calls + assert mock_get.call_count == 2 + + @patch('subprocess.run') @patch('requests.post') @patch('requests.get') @@ -616,6 +667,7 @@ def test_process_single_pr_update( mock_llm_config, None, False, + None, ) mock_initialize_repo.assert_called_once_with(mock_output_dir, 1, 'pr', 'branch 1') @@ -688,6 +740,7 @@ def test_process_single_issue( mock_llm_config, None, False, + None, ) # Assert that the mocked functions were called with correct arguments @@ -704,9 +757,10 @@ def test_process_single_issue( github_username=github_username, patch_dir=f'{mock_output_dir}/patches/issue_1', pr_type=pr_type, + llm_config=mock_llm_config, fork_owner=None, additional_message=resolver_output.success_explanation, - llm_config=mock_llm_config, + target_branch=None, ) @@ -757,6 +811,7 @@ def test_process_single_issue_unsuccessful( mock_llm_config, None, False, + None, ) # Assert that none of the mocked functions were called @@ -863,6 +918,7 @@ def test_process_all_successful_issues( mock_llm_config, None, False, + None, ), call( 'output_dir', @@ -873,6 +929,7 @@ def test_process_all_successful_issues( mock_llm_config, None, False, + None, ), ] ) @@ -971,6 +1028,7 @@ def test_main( mock_args.llm_model = 'mock_model' mock_args.llm_base_url = 'mock_url' mock_args.llm_api_key = 'mock_key' + mock_args.target_branch = None mock_parser.return_value.parse_args.return_value = mock_args # Setup environment variables @@ -994,12 +1052,8 @@ def test_main( api_key=mock_args.llm_api_key, ) - # Assert function calls - mock_parser.assert_called_once() - mock_getenv.assert_any_call('GITHUB_TOKEN') - mock_path_exists.assert_called_with('/mock/output') - mock_load_single_resolver_output.assert_called_with('/mock/output/output.jsonl', 42) - mock_process_single_issue.assert_called_with( + # Use any_call instead of assert_called_with for more flexible matching + assert mock_process_single_issue.call_args == call( '/mock/output', mock_resolver_output, 'mock_token', @@ -1008,8 +1062,15 @@ def test_main( llm_config, None, False, + mock_args.target_branch, ) + # Other assertions + mock_parser.assert_called_once() + mock_getenv.assert_any_call('GITHUB_TOKEN') + mock_path_exists.assert_called_with('/mock/output') + mock_load_single_resolver_output.assert_called_with('/mock/output/output.jsonl', 42) + # Test for 'all_successful' issue number mock_args.issue_number = 'all_successful' main() From 1f723293db928ce665e7081da20603bd8e0469ef Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Tue, 19 Nov 2024 08:34:25 -0500 Subject: [PATCH 09/34] Add macro invocations to example workflow (#5121) --- .../resolver/examples/openhands-resolver.yml | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/openhands/resolver/examples/openhands-resolver.yml b/openhands/resolver/examples/openhands-resolver.yml index 6555e15057c7..fb40dde8d97e 100644 --- a/openhands/resolver/examples/openhands-resolver.yml +++ b/openhands/resolver/examples/openhands-resolver.yml @@ -7,6 +7,10 @@ on: types: [labeled] issue_comment: types: [created] + pull_request_review_comment: + types: [created] + pull_request_review: + types: [submitted] permissions: contents: write @@ -16,12 +20,20 @@ permissions: jobs: call-openhands-resolver: if: | - ${{ - github.event.label.name == 'fix-me' || - (github.event_name == 'issue_comment' && - startsWith(github.event.comment.body, vars.OPENHANDS_MACRO || '@openhands-agent') && - (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'MEMBER')) - }} + github.event.label.name == 'fix-me' || + + ( + ((github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') && + (startsWith(github.event.comment.body, inputs.macro || '@openhands-agent') || startsWith(github.event.comment.body, inputs.macro || vars.OPENHANDS_MACRO)) && + (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'MEMBER') + ) || + + (github.event_name == 'pull_request_review' && + (startsWith(github.event.review.body, inputs.macro || '@openhands-agent') || startsWith(github.event.review.body, inputs.macro || vars.OPENHANDS_MACRO)) && + (github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'COLLABORATOR' || github.event.review.author_association == 'MEMBER') + ) + ) + uses: All-Hands-AI/OpenHands/.github/workflows/openhands-resolver.yml@main with: macro: ${{ vars.OPENHANDS_MACRO || '@openhands-agent' }} From ff84a3eede3d2f4e52e25822d525d676193abc78 Mon Sep 17 00:00:00 2001 From: Xingyao Wang Date: Tue, 19 Nov 2024 10:41:27 -0600 Subject: [PATCH 10/34] chore: remove specified sid (#5127) --- evaluation/discoverybench/run_infer.py | 5 +---- openhands/core/main.py | 5 ++++- openhands/resolver/resolve_issue.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/evaluation/discoverybench/run_infer.py b/evaluation/discoverybench/run_infer.py index 1b3a98c37e14..7cfd2dbac7ad 100644 --- a/evaluation/discoverybench/run_infer.py +++ b/evaluation/discoverybench/run_infer.py @@ -250,9 +250,6 @@ def process_instance( config = get_config(metadata) - # use a session id for concurrent evaluation - sid = 'ID_' + str(instance.instance_id) - # Setup the logger properly, so you can run # multi-processing to parallelize the evaluation if reset_logger: @@ -284,7 +281,7 @@ def process_instance( instruction += AGENT_CLS_TO_INST_SUFFIX[metadata.agent_class] # Here's how you can run the agent (similar to the `main` function) and get the final task state - runtime = create_runtime(config, sid=sid) + runtime = create_runtime(config) call_async_from_sync(runtime.connect) initialize_runtime(runtime, instance.data_files) diff --git a/openhands/core/main.py b/openhands/core/main.py index 06dede3d5d55..d55aa0175102 100644 --- a/openhands/core/main.py +++ b/openhands/core/main.py @@ -59,7 +59,8 @@ def create_runtime( """Create a runtime for the agent to run on. config: The app config. - sid: The session id. + sid: (optional) The session id. IMPORTANT: please don't set this unless you know what you're doing. + Set it to incompatible value will cause unexpected behavior on RemoteRuntime. headless_mode: Whether the agent is run in headless mode. `create_runtime` is typically called within evaluation scripts, where we don't want to have the VSCode UI open, so it defaults to True. """ @@ -105,6 +106,8 @@ async def run_controller( Args: config: The app config. initial_user_action: An Action object containing initial user input + sid: (optional) The session id. IMPORTANT: please don't set this unless you know what you're doing. + Set it to incompatible value will cause unexpected behavior on RemoteRuntime. runtime: (optional) A runtime for the agent to run on. agent: (optional) A agent to run. exit_on_message: quit if agent asks for a message from user (optional) diff --git a/openhands/resolver/resolve_issue.py b/openhands/resolver/resolve_issue.py index 67eb20bee1e0..cbe8cfa6df61 100644 --- a/openhands/resolver/resolve_issue.py +++ b/openhands/resolver/resolve_issue.py @@ -199,7 +199,7 @@ async def process_issue( ) config.set_llm_config(llm_config) - runtime = create_runtime(config, sid=f'{issue.number}') + runtime = create_runtime(config) await runtime.connect() async def on_event(evt): From de07fcfddcc0ceb28ac1d31e739f65191e075dd9 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Tue, 19 Nov 2024 12:17:55 -0500 Subject: [PATCH 11/34] Moving resolver settings to repo variables (#5130) --- openhands/resolver/examples/openhands-resolver.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands/resolver/examples/openhands-resolver.yml b/openhands/resolver/examples/openhands-resolver.yml index fb40dde8d97e..2e2f42be0bac 100644 --- a/openhands/resolver/examples/openhands-resolver.yml +++ b/openhands/resolver/examples/openhands-resolver.yml @@ -37,7 +37,7 @@ jobs: uses: All-Hands-AI/OpenHands/.github/workflows/openhands-resolver.yml@main with: macro: ${{ vars.OPENHANDS_MACRO || '@openhands-agent' }} - max_iterations: 50 + max_iterations: ${{ vars.OPENHANDS_MAX_ITER || 50 }} secrets: PAT_TOKEN: ${{ secrets.PAT_TOKEN }} PAT_USERNAME: ${{ secrets.PAT_USERNAME }} From 7f5022c8fe9238af4d2818782601f4ea4452e827 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Tue, 19 Nov 2024 12:23:42 -0500 Subject: [PATCH 12/34] Refactor issue filtering (#5129) --- openhands/resolver/issue_definitions.py | 35 +- openhands/resolver/resolve_all_issues.py | 7 +- openhands/resolver/resolve_issue.py | 7 +- tests/unit/resolver/test_issue_handler.py | 425 +++++++++++---------- tests/unit/resolver/test_resolve_issues.py | 10 +- 5 files changed, 256 insertions(+), 228 deletions(-) diff --git a/openhands/resolver/issue_definitions.py b/openhands/resolver/issue_definitions.py index c9e386178adf..a0d0eb570aa7 100644 --- a/openhands/resolver/issue_definitions.py +++ b/openhands/resolver/issue_definitions.py @@ -18,7 +18,9 @@ class IssueHandlerInterface(ABC): issue_type: ClassVar[str] @abstractmethod - def get_converted_issues(self, comment_id: int | None = None) -> list[GithubIssue]: + def get_converted_issues( + self, issue_numbers: list[int] | None = None, comment_id: int | None = None + ) -> list[GithubIssue]: """Download issues from GitHub.""" pass @@ -138,13 +140,29 @@ def _get_issue_comments( return all_comments if all_comments else None - def get_converted_issues(self, comment_id: int | None = None) -> list[GithubIssue]: + def get_converted_issues( + self, issue_numbers: list[int] | None = None, comment_id: int | None = None + ) -> list[GithubIssue]: """Download issues from Github. Returns: List of Github issues. """ + + if not issue_numbers: + raise ValueError('Unspecified issue number') + all_issues = self._download_issues_from_github() + logger.info(f'Limiting resolving to issues {issue_numbers}.') + all_issues = [ + issue + for issue in all_issues + if issue['number'] in issue_numbers and 'pull_request' not in issue + ] + + if len(issue_numbers) == 1 and not all_issues: + raise ValueError(f'Issue {issue_numbers[0]} not found') + converted_issues = [] for issue in all_issues: if any([issue.get(key) is None for key in ['number', 'title', 'body']]): @@ -153,9 +171,6 @@ def get_converted_issues(self, comment_id: int | None = None) -> list[GithubIssu ) continue - if 'pull_request' in issue: - continue - # Get issue thread comments thread_comments = self._get_issue_comments( issue['number'], comment_id=comment_id @@ -486,8 +501,16 @@ def __get_context_from_external_issues_references( return closing_issues - def get_converted_issues(self, comment_id: int | None = None) -> list[GithubIssue]: + def get_converted_issues( + self, issue_numbers: list[int] | None = None, comment_id: int | None = None + ) -> list[GithubIssue]: + if not issue_numbers: + raise ValueError('Unspecified issue numbers') + all_issues = self._download_issues_from_github() + logger.info(f'Limiting resolving to issues {issue_numbers}.') + all_issues = [issue for issue in all_issues if issue['number'] in issue_numbers] + converted_issues = [] for issue in all_issues: # For PRs, body can be None diff --git a/openhands/resolver/resolve_all_issues.py b/openhands/resolver/resolve_all_issues.py index a561b24a61a7..01d076446e97 100644 --- a/openhands/resolver/resolve_all_issues.py +++ b/openhands/resolver/resolve_all_issues.py @@ -83,11 +83,10 @@ async def resolve_issues( issue_handler = issue_handler_factory(issue_type, owner, repo, token) # Load dataset - issues: list[GithubIssue] = issue_handler.get_converted_issues() + issues: list[GithubIssue] = issue_handler.get_converted_issues( + issue_numbers=issue_numbers + ) - if issue_numbers is not None: - issues = [issue for issue in issues if issue.number in issue_numbers] - logger.info(f'Limiting resolving to issues {issue_numbers}.') if limit_issues is not None: issues = issues[:limit_issues] logger.info(f'Limiting resolving to first {limit_issues} issues.') diff --git a/openhands/resolver/resolve_issue.py b/openhands/resolver/resolve_issue.py index cbe8cfa6df61..b371d8160b20 100644 --- a/openhands/resolver/resolve_issue.py +++ b/openhands/resolver/resolve_issue.py @@ -339,13 +339,10 @@ async def resolve_issue( # Load dataset issues: list[GithubIssue] = issue_handler.get_converted_issues( - comment_id=comment_id + issue_numbers=[issue_number], comment_id=comment_id ) - # Find the specific issue - issue = next((i for i in issues if i.number == issue_number), None) - if not issue: - raise ValueError(f'Issue {issue_number} not found') + issue = issues[0] if comment_id is not None: if ( diff --git a/tests/unit/resolver/test_issue_handler.py b/tests/unit/resolver/test_issue_handler.py index 7df7f0fe4027..d0c17d9088e9 100644 --- a/tests/unit/resolver/test_issue_handler.py +++ b/tests/unit/resolver/test_issue_handler.py @@ -1,17 +1,18 @@ -from unittest.mock import patch, MagicMock -from openhands.resolver.issue_definitions import IssueHandler, PRHandler -from openhands.resolver.github_issue import GithubIssue, ReviewThread -from openhands.events.action.message import MessageAction +from unittest.mock import MagicMock, patch + from openhands.core.config import LLMConfig +from openhands.events.action.message import MessageAction +from openhands.resolver.github_issue import GithubIssue, ReviewThread +from openhands.resolver.issue_definitions import IssueHandler, PRHandler def test_get_converted_issues_initializes_review_comments(): # Mock the necessary dependencies - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for issues mock_issues_response = MagicMock() mock_issues_response.json.return_value = [ - {"number": 1, "title": "Test Issue", "body": "Test Body"} + {'number': 1, 'title': 'Test Issue', 'body': 'Test Body'} ] # Mock the response for comments mock_comments_response = MagicMock() @@ -26,10 +27,10 @@ def test_get_converted_issues_initializes_review_comments(): ] # Need two comment responses because we make two API calls # Create an instance of IssueHandler - handler = IssueHandler("test-owner", "test-repo", "test-token") + handler = IssueHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - issues = handler.get_converted_issues() + issues = handler.get_converted_issues(issue_numbers=[1]) # Verify that we got exactly one issue assert len(issues) == 1 @@ -39,35 +40,35 @@ def test_get_converted_issues_initializes_review_comments(): # Verify other fields are set correctly assert issues[0].number == 1 - assert issues[0].title == "Test Issue" - assert issues[0].body == "Test Body" - assert issues[0].owner == "test-owner" - assert issues[0].repo == "test-repo" + assert issues[0].title == 'Test Issue' + assert issues[0].body == 'Test Body' + assert issues[0].owner == 'test-owner' + assert issues[0].repo == 'test-repo' def test_pr_handler_guess_success_with_thread_comments(): # Create a PR handler instance - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Create a mock issue with thread comments but no review comments issue = GithubIssue( - owner="test-owner", - repo="test-repo", + owner='test-owner', + repo='test-repo', number=1, - title="Test PR", - body="Test Body", - thread_comments=["First comment", "Second comment"], - closing_issues=["Issue description"], + title='Test PR', + body='Test Body', + thread_comments=['First comment', 'Second comment'], + closing_issues=['Issue description'], review_comments=None, thread_ids=None, - head_branch="test-branch", + head_branch='test-branch', ) # Create mock history - history = [MessageAction(content="Fixed the issue by implementing X and Y")] + history = [MessageAction(content='Fixed the issue by implementing X and Y')] # Create mock LLM config - llm_config = LLMConfig(model="test-model", api_key="test-key") + llm_config = LLMConfig(model='test-model', api_key='test-key') # Mock the LLM response mock_response = MagicMock() @@ -84,7 +85,7 @@ def test_pr_handler_guess_success_with_thread_comments(): ] # Test the guess_success method - with patch("litellm.completion", return_value=mock_response): + with patch('litellm.completion', return_value=mock_response): success, success_list, explanation = handler.guess_success( issue, history, llm_config ) @@ -92,39 +93,39 @@ def test_pr_handler_guess_success_with_thread_comments(): # Verify the results assert success is True assert success_list == [True] - assert "successfully address" in explanation + assert 'successfully address' in explanation def test_pr_handler_get_converted_issues_with_comments(): # Mock the necessary dependencies - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for PRs mock_prs_response = MagicMock() mock_prs_response.json.return_value = [ { - "number": 1, - "title": "Test PR", - "body": "Test Body fixes #1", - "head": {"ref": "test-branch"}, + 'number': 1, + 'title': 'Test PR', + 'body': 'Test Body fixes #1', + 'head': {'ref': 'test-branch'}, } ] # Mock the response for PR comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"body": "First comment"}, - {"body": "Second comment"}, + {'body': 'First comment'}, + {'body': 'Second comment'}, ] # Mock the response for PR metadata (GraphQL) mock_graphql_response = MagicMock() mock_graphql_response.json.return_value = { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": {"nodes": []}, - "reviewThreads": {"edges": []}, + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': {'nodes': []}, + 'reviewThreads': {'edges': []}, } } } @@ -138,7 +139,7 @@ def test_pr_handler_get_converted_issues_with_comments(): # Mock the response for fetching the external issue referenced in PR body mock_external_issue_response = MagicMock() mock_external_issue_response.json.return_value = { - "body": "This is additional context from an externally referenced issue." + 'body': 'This is additional context from an externally referenced issue.' } mock_get.side_effect = [ @@ -150,56 +151,56 @@ def test_pr_handler_get_converted_issues_with_comments(): ] # Mock the post request for GraphQL - with patch("requests.post") as mock_post: + with patch('requests.post') as mock_post: mock_post.return_value = mock_graphql_response # Create an instance of PRHandler - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - prs = handler.get_converted_issues() + prs = handler.get_converted_issues(issue_numbers=[1]) # Verify that we got exactly one PR assert len(prs) == 1 # Verify that thread_comments are set correctly - assert prs[0].thread_comments == ["First comment", "Second comment"] + assert prs[0].thread_comments == ['First comment', 'Second comment'] # Verify other fields are set correctly assert prs[0].number == 1 - assert prs[0].title == "Test PR" - assert prs[0].body == "Test Body fixes #1" - assert prs[0].owner == "test-owner" - assert prs[0].repo == "test-repo" - assert prs[0].head_branch == "test-branch" + assert prs[0].title == 'Test PR' + assert prs[0].body == 'Test Body fixes #1' + assert prs[0].owner == 'test-owner' + assert prs[0].repo == 'test-repo' + assert prs[0].head_branch == 'test-branch' assert prs[0].closing_issues == [ - "This is additional context from an externally referenced issue." + 'This is additional context from an externally referenced issue.' ] def test_pr_handler_guess_success_only_review_comments(): # Create a PR handler instance - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Create a mock issue with only review comments issue = GithubIssue( - owner="test-owner", - repo="test-repo", + owner='test-owner', + repo='test-repo', number=1, - title="Test PR", - body="Test Body", + title='Test PR', + body='Test Body', thread_comments=None, - closing_issues=["Issue description"], - review_comments=["Please fix the formatting", "Add more tests"], + closing_issues=['Issue description'], + review_comments=['Please fix the formatting', 'Add more tests'], thread_ids=None, - head_branch="test-branch", + head_branch='test-branch', ) # Create mock history - history = [MessageAction(content="Fixed the formatting and added more tests")] + history = [MessageAction(content='Fixed the formatting and added more tests')] # Create mock LLM config - llm_config = LLMConfig(model="test-model", api_key="test-key") + llm_config = LLMConfig(model='test-model', api_key='test-key') # Mock the LLM response mock_response = MagicMock() @@ -216,7 +217,7 @@ def test_pr_handler_guess_success_only_review_comments(): ] # Test the guess_success method - with patch("litellm.completion", return_value=mock_response): + with patch('litellm.completion', return_value=mock_response): success, success_list, explanation = handler.guess_success( issue, history, llm_config ) @@ -224,32 +225,32 @@ def test_pr_handler_guess_success_only_review_comments(): # Verify the results assert success is True assert success_list == [True] - assert "successfully address" in explanation + assert 'successfully address' in explanation def test_pr_handler_guess_success_no_comments(): # Create a PR handler instance - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Create a mock issue with no comments issue = GithubIssue( - owner="test-owner", - repo="test-repo", + owner='test-owner', + repo='test-repo', number=1, - title="Test PR", - body="Test Body", + title='Test PR', + body='Test Body', thread_comments=None, - closing_issues=["Issue description"], + closing_issues=['Issue description'], review_comments=None, thread_ids=None, - head_branch="test-branch", + head_branch='test-branch', ) # Create mock history - history = [MessageAction(content="Fixed the issue")] + history = [MessageAction(content='Fixed the issue')] # Create mock LLM config - llm_config = LLMConfig(model="test-model", api_key="test-key") + llm_config = LLMConfig(model='test-model', api_key='test-key') # Test that it returns appropriate message when no comments are present success, success_list, explanation = handler.guess_success( @@ -257,29 +258,29 @@ def test_pr_handler_guess_success_no_comments(): ) assert success is False assert success_list is None - assert explanation == "No feedback was found to process" + assert explanation == 'No feedback was found to process' def test_get_issue_comments_with_specific_comment_id(): # Mock the necessary dependencies - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"id": 123, "body": "First comment"}, - {"id": 456, "body": "Second comment"}, + {'id': 123, 'body': 'First comment'}, + {'id': 456, 'body': 'Second comment'}, ] mock_get.return_value = mock_comments_response # Create an instance of IssueHandler - handler = IssueHandler("test-owner", "test-repo", "test-token") + handler = IssueHandler('test-owner', 'test-repo', 'test-token') # Get comments with a specific comment_id specific_comment = handler._get_issue_comments(issue_number=1, comment_id=123) # Verify only the specific comment is returned - assert specific_comment == ["First comment"] + assert specific_comment == ['First comment'] def test_pr_handler_get_converted_issues_with_specific_thread_comment(): @@ -287,50 +288,50 @@ def test_pr_handler_get_converted_issues_with_specific_thread_comment(): specific_comment_id = 123 # Mock GraphQL response for review threads - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for PRs mock_prs_response = MagicMock() mock_prs_response.json.return_value = [ { - "number": 1, - "title": "Test PR", - "body": "Test Body", - "head": {"ref": "test-branch"}, + 'number': 1, + 'title': 'Test PR', + 'body': 'Test Body', + 'head': {'ref': 'test-branch'}, } ] # Mock the response for PR comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"body": "First comment", "id": 123}, - {"body": "Second comment", "id": 124}, + {'body': 'First comment', 'id': 123}, + {'body': 'Second comment', 'id': 124}, ] # Mock the response for PR metadata (GraphQL) mock_graphql_response = MagicMock() mock_graphql_response.json.return_value = { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": {"nodes": []}, - "reviewThreads": { - "edges": [ + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': {'nodes': []}, + 'reviewThreads': { + 'edges': [ { - "node": { - "id": "review-thread-1", - "isResolved": False, - "comments": { - "nodes": [ + 'node': { + 'id': 'review-thread-1', + 'isResolved': False, + 'comments': { + 'nodes': [ { - "fullDatabaseId": 121, - "body": "Specific review comment", - "path": "file1.txt", + 'fullDatabaseId': 121, + 'body': 'Specific review comment', + 'path': 'file1.txt', }, { - "fullDatabaseId": 456, - "body": "Another review comment", - "path": "file2.txt", + 'fullDatabaseId': 456, + 'body': 'Another review comment', + 'path': 'file2.txt', }, ] }, @@ -356,30 +357,32 @@ def test_pr_handler_get_converted_issues_with_specific_thread_comment(): ] # Mock the post request for GraphQL - with patch("requests.post") as mock_post: + with patch('requests.post') as mock_post: mock_post.return_value = mock_graphql_response # Create an instance of PRHandler - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - prs = handler.get_converted_issues(comment_id=specific_comment_id) + prs = handler.get_converted_issues( + issue_numbers=[1], comment_id=specific_comment_id + ) # Verify that we got exactly one PR assert len(prs) == 1 # Verify that thread_comments are set correctly - assert prs[0].thread_comments == ["First comment"] + assert prs[0].thread_comments == ['First comment'] assert prs[0].review_comments == [] assert prs[0].review_threads == [] # Verify other fields are set correctly assert prs[0].number == 1 - assert prs[0].title == "Test PR" - assert prs[0].body == "Test Body" - assert prs[0].owner == "test-owner" - assert prs[0].repo == "test-repo" - assert prs[0].head_branch == "test-branch" + assert prs[0].title == 'Test PR' + assert prs[0].body == 'Test Body' + assert prs[0].owner == 'test-owner' + assert prs[0].repo == 'test-repo' + assert prs[0].head_branch == 'test-branch' def test_pr_handler_get_converted_issues_with_specific_review_thread_comment(): @@ -387,50 +390,50 @@ def test_pr_handler_get_converted_issues_with_specific_review_thread_comment(): specific_comment_id = 123 # Mock GraphQL response for review threads - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for PRs mock_prs_response = MagicMock() mock_prs_response.json.return_value = [ { - "number": 1, - "title": "Test PR", - "body": "Test Body", - "head": {"ref": "test-branch"}, + 'number': 1, + 'title': 'Test PR', + 'body': 'Test Body', + 'head': {'ref': 'test-branch'}, } ] # Mock the response for PR comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"body": "First comment", "id": 120}, - {"body": "Second comment", "id": 124}, + {'body': 'First comment', 'id': 120}, + {'body': 'Second comment', 'id': 124}, ] # Mock the response for PR metadata (GraphQL) mock_graphql_response = MagicMock() mock_graphql_response.json.return_value = { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": {"nodes": []}, - "reviewThreads": { - "edges": [ + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': {'nodes': []}, + 'reviewThreads': { + 'edges': [ { - "node": { - "id": "review-thread-1", - "isResolved": False, - "comments": { - "nodes": [ + 'node': { + 'id': 'review-thread-1', + 'isResolved': False, + 'comments': { + 'nodes': [ { - "fullDatabaseId": specific_comment_id, - "body": "Specific review comment", - "path": "file1.txt", + 'fullDatabaseId': specific_comment_id, + 'body': 'Specific review comment', + 'path': 'file1.txt', }, { - "fullDatabaseId": 456, - "body": "Another review comment", - "path": "file1.txt", + 'fullDatabaseId': 456, + 'body': 'Another review comment', + 'path': 'file1.txt', }, ] }, @@ -456,14 +459,16 @@ def test_pr_handler_get_converted_issues_with_specific_review_thread_comment(): ] # Mock the post request for GraphQL - with patch("requests.post") as mock_post: + with patch('requests.post') as mock_post: mock_post.return_value = mock_graphql_response # Create an instance of PRHandler - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - prs = handler.get_converted_issues(comment_id=specific_comment_id) + prs = handler.get_converted_issues( + issue_numbers=[1], comment_id=specific_comment_id + ) # Verify that we got exactly one PR assert len(prs) == 1 @@ -475,17 +480,17 @@ def test_pr_handler_get_converted_issues_with_specific_review_thread_comment(): assert isinstance(prs[0].review_threads[0], ReviewThread) assert ( prs[0].review_threads[0].comment - == "Specific review comment\n---\nlatest feedback:\nAnother review comment\n" + == 'Specific review comment\n---\nlatest feedback:\nAnother review comment\n' ) - assert prs[0].review_threads[0].files == ["file1.txt"] + assert prs[0].review_threads[0].files == ['file1.txt'] # Verify other fields are set correctly assert prs[0].number == 1 - assert prs[0].title == "Test PR" - assert prs[0].body == "Test Body" - assert prs[0].owner == "test-owner" - assert prs[0].repo == "test-repo" - assert prs[0].head_branch == "test-branch" + assert prs[0].title == 'Test PR' + assert prs[0].body == 'Test Body' + assert prs[0].owner == 'test-owner' + assert prs[0].repo == 'test-repo' + assert prs[0].head_branch == 'test-branch' def test_pr_handler_get_converted_issues_with_specific_comment_and_issue_refs(): @@ -493,50 +498,50 @@ def test_pr_handler_get_converted_issues_with_specific_comment_and_issue_refs(): specific_comment_id = 123 # Mock GraphQL response for review threads - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for PRs mock_prs_response = MagicMock() mock_prs_response.json.return_value = [ { - "number": 1, - "title": "Test PR fixes #3", - "body": "Test Body", - "head": {"ref": "test-branch"}, + 'number': 1, + 'title': 'Test PR fixes #3', + 'body': 'Test Body', + 'head': {'ref': 'test-branch'}, } ] # Mock the response for PR comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"body": "First comment", "id": 120}, - {"body": "Second comment", "id": 124}, + {'body': 'First comment', 'id': 120}, + {'body': 'Second comment', 'id': 124}, ] # Mock the response for PR metadata (GraphQL) mock_graphql_response = MagicMock() mock_graphql_response.json.return_value = { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": {"nodes": []}, - "reviewThreads": { - "edges": [ + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': {'nodes': []}, + 'reviewThreads': { + 'edges': [ { - "node": { - "id": "review-thread-1", - "isResolved": False, - "comments": { - "nodes": [ + 'node': { + 'id': 'review-thread-1', + 'isResolved': False, + 'comments': { + 'nodes': [ { - "fullDatabaseId": specific_comment_id, - "body": "Specific review comment that references #6", - "path": "file1.txt", + 'fullDatabaseId': specific_comment_id, + 'body': 'Specific review comment that references #6', + 'path': 'file1.txt', }, { - "fullDatabaseId": 456, - "body": "Another review comment referencing #7", - "path": "file2.txt", + 'fullDatabaseId': 456, + 'body': 'Another review comment referencing #7', + 'path': 'file2.txt', }, ] }, @@ -557,13 +562,13 @@ def test_pr_handler_get_converted_issues_with_specific_comment_and_issue_refs(): # Mock the response for fetching the external issue referenced in PR body mock_external_issue_response_in_body = MagicMock() mock_external_issue_response_in_body.json.return_value = { - "body": "External context #1." + 'body': 'External context #1.' } # Mock the response for fetching the external issue referenced in review thread mock_external_issue_response_review_thread = MagicMock() mock_external_issue_response_review_thread.json.return_value = { - "body": "External context #2." + 'body': 'External context #2.' } mock_get.side_effect = [ @@ -576,14 +581,16 @@ def test_pr_handler_get_converted_issues_with_specific_comment_and_issue_refs(): ] # Mock the post request for GraphQL - with patch("requests.post") as mock_post: + with patch('requests.post') as mock_post: mock_post.return_value = mock_graphql_response # Create an instance of PRHandler - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - prs = handler.get_converted_issues(comment_id=specific_comment_id) + prs = handler.get_converted_issues( + issue_numbers=[1], comment_id=specific_comment_id + ) # Verify that we got exactly one PR assert len(prs) == 1 @@ -595,52 +602,52 @@ def test_pr_handler_get_converted_issues_with_specific_comment_and_issue_refs(): assert isinstance(prs[0].review_threads[0], ReviewThread) assert ( prs[0].review_threads[0].comment - == "Specific review comment that references #6\n---\nlatest feedback:\nAnother review comment referencing #7\n" + == 'Specific review comment that references #6\n---\nlatest feedback:\nAnother review comment referencing #7\n' ) assert prs[0].closing_issues == [ - "External context #1.", - "External context #2.", + 'External context #1.', + 'External context #2.', ] # Only includes references inside comment ID and body PR # Verify other fields are set correctly assert prs[0].number == 1 - assert prs[0].title == "Test PR fixes #3" - assert prs[0].body == "Test Body" - assert prs[0].owner == "test-owner" - assert prs[0].repo == "test-repo" - assert prs[0].head_branch == "test-branch" + assert prs[0].title == 'Test PR fixes #3' + assert prs[0].body == 'Test Body' + assert prs[0].owner == 'test-owner' + assert prs[0].repo == 'test-repo' + assert prs[0].head_branch == 'test-branch' def test_pr_handler_get_converted_issues_with_duplicate_issue_refs(): # Mock the necessary dependencies - with patch("requests.get") as mock_get: + with patch('requests.get') as mock_get: # Mock the response for PRs mock_prs_response = MagicMock() mock_prs_response.json.return_value = [ { - "number": 1, - "title": "Test PR", - "body": "Test Body fixes #1", - "head": {"ref": "test-branch"}, + 'number': 1, + 'title': 'Test PR', + 'body': 'Test Body fixes #1', + 'head': {'ref': 'test-branch'}, } ] # Mock the response for PR comments mock_comments_response = MagicMock() mock_comments_response.json.return_value = [ - {"body": "First comment addressing #1"}, - {"body": "Second comment addressing #2"}, + {'body': 'First comment addressing #1'}, + {'body': 'Second comment addressing #2'}, ] # Mock the response for PR metadata (GraphQL) mock_graphql_response = MagicMock() mock_graphql_response.json.return_value = { - "data": { - "repository": { - "pullRequest": { - "closingIssuesReferences": {"edges": []}, - "reviews": {"nodes": []}, - "reviewThreads": {"edges": []}, + 'data': { + 'repository': { + 'pullRequest': { + 'closingIssuesReferences': {'edges': []}, + 'reviews': {'nodes': []}, + 'reviewThreads': {'edges': []}, } } } @@ -654,13 +661,13 @@ def test_pr_handler_get_converted_issues_with_duplicate_issue_refs(): # Mock the response for fetching the external issue referenced in PR body mock_external_issue_response_in_body = MagicMock() mock_external_issue_response_in_body.json.return_value = { - "body": "External context #1." + 'body': 'External context #1.' } # Mock the response for fetching the external issue referenced in review thread mock_external_issue_response_in_comment = MagicMock() mock_external_issue_response_in_comment.json.return_value = { - "body": "External context #2." + 'body': 'External context #2.' } mock_get.side_effect = [ @@ -673,32 +680,32 @@ def test_pr_handler_get_converted_issues_with_duplicate_issue_refs(): ] # Mock the post request for GraphQL - with patch("requests.post") as mock_post: + with patch('requests.post') as mock_post: mock_post.return_value = mock_graphql_response # Create an instance of PRHandler - handler = PRHandler("test-owner", "test-repo", "test-token") + handler = PRHandler('test-owner', 'test-repo', 'test-token') # Get converted issues - prs = handler.get_converted_issues() + prs = handler.get_converted_issues(issue_numbers=[1]) # Verify that we got exactly one PR assert len(prs) == 1 # Verify that thread_comments are set correctly assert prs[0].thread_comments == [ - "First comment addressing #1", - "Second comment addressing #2", + 'First comment addressing #1', + 'Second comment addressing #2', ] # Verify other fields are set correctly assert prs[0].number == 1 - assert prs[0].title == "Test PR" - assert prs[0].body == "Test Body fixes #1" - assert prs[0].owner == "test-owner" - assert prs[0].repo == "test-repo" - assert prs[0].head_branch == "test-branch" + assert prs[0].title == 'Test PR' + assert prs[0].body == 'Test Body fixes #1' + assert prs[0].owner == 'test-owner' + assert prs[0].repo == 'test-repo' + assert prs[0].head_branch == 'test-branch' assert prs[0].closing_issues == [ - "External context #1.", - "External context #2.", + 'External context #1.', + 'External context #2.', ] diff --git a/tests/unit/resolver/test_resolve_issues.py b/tests/unit/resolver/test_resolve_issues.py index 6eb3bb9f2767..3f08db7e2bea 100644 --- a/tests/unit/resolver/test_resolve_issues.py +++ b/tests/unit/resolver/test_resolve_issues.py @@ -112,7 +112,7 @@ def get_mock_response(url, *args, **kwargs): return mock_issues_response with patch('requests.get', side_effect=get_mock_response): - issues = handler.get_converted_issues() + issues = handler.get_converted_issues(issue_numbers=[1, 3]) assert len(issues) == 2 assert handler.issue_type == 'issue' @@ -225,7 +225,7 @@ def get_mock_response(url, *args, **kwargs): with patch('requests.get', side_effect=get_mock_response): with patch('requests.post', return_value=mock_graphql_response): - issues = handler.get_converted_issues() + issues = handler.get_converted_issues(issue_numbers=[1, 2, 3]) assert len(issues) == 3 assert handler.issue_type == 'pr' @@ -811,7 +811,7 @@ def get_mock_response(url, *args, **kwargs): with patch('requests.get', side_effect=get_mock_response): with patch('requests.post', return_value=mock_graphql_response): - issues = handler.get_converted_issues() + issues = handler.get_converted_issues(issue_numbers=[1]) assert len(issues) == 1 assert handler.issue_type == 'pr' @@ -867,7 +867,9 @@ def get_mock_response(url, *args, **kwargs): return mock_issue_response with patch('requests.get', side_effect=get_mock_response): - issues = handler.get_converted_issues(comment_id=specific_comment_id) + issues = handler.get_converted_issues( + issue_numbers=[1], comment_id=specific_comment_id + ) assert len(issues) == 1 assert issues[0].number == 1 From f0ca45c59ef8586c5846703f86eb69dfbd265ef4 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Tue, 19 Nov 2024 12:26:11 -0500 Subject: [PATCH 13/34] Add clarity for Openhands-resolver guide (#5124) --- docs/modules/usage/how-to/github-action.md | 35 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/modules/usage/how-to/github-action.md b/docs/modules/usage/how-to/github-action.md index 70c43beea174..3b55ab4952a7 100644 --- a/docs/modules/usage/how-to/github-action.md +++ b/docs/modules/usage/how-to/github-action.md @@ -4,13 +4,42 @@ This guide explains how to use the OpenHands GitHub Action, both within the Open ## Using the Action in the OpenHands Repository -To use the OpenHands GitHub Action in the OpenHands repository, an OpenHands maintainer can: +To use the OpenHands GitHub Action in a repository, you can: 1. Create an issue in the repository. -2. Add the `fix-me` label to the issue. -3. The action will automatically trigger and attempt to resolve the issue. +2. Add the `fix-me` label to the issue or leave a comment on the issue starting with `@openhands-agent`. + +The action will automatically trigger and attempt to resolve the issue. ## Installing the Action in a New Repository To install the OpenHands GitHub Action in your own repository, follow the [README for the OpenHands Resolver](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/resolver/README.md). + +## Usage Tips + +### Iterative resolution + +1. Create an issue in the repository. +2. Add the `fix-me` label to the issue, or leave a comment starting with `@openhands-agent` +3. Review the attempt to resolve the issue by checking the pull request +4. Follow up with feedback through general comments, review comments, or inline thread comments +5. Add the `fix-me` label to the pull request, or address a specific comment by starting with `@openhands-agent` + +### Label versus Macro + +- Label (`fix-me`): Requests OpenHands to address the **entire** issue or pull request. +- Macro (`@openhands-agent`): Requests OpenHands to consider only the issue/pull request description and **the specific comment**. + +## Advanced Settings + +### Add custom repository settings + +You can provide custom directions for OpenHands by following the [README for the resolver](https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/resolver/README.md#providing-custom-instructions). + +### Configure custom macro + +To customize the default macro (`@openhands-agent`): + +1. [Create a repository variable](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) named `OPENHANDS_MACRO` +2. Assign the variable a custom value From e052c25572fb3f9001b47a627d86048a5c65b548 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Tue, 19 Nov 2024 12:49:20 -0500 Subject: [PATCH 14/34] Fix GitHub prompt (#5123) --- openhands/agenthub/codeact_agent/micro/github.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openhands/agenthub/codeact_agent/micro/github.md b/openhands/agenthub/codeact_agent/micro/github.md index abd48fa5c75c..c03bb546cd80 100644 --- a/openhands/agenthub/codeact_agent/micro/github.md +++ b/openhands/agenthub/codeact_agent/micro/github.md @@ -21,11 +21,9 @@ Here are some instructions for pushing, but ONLY do this if the user asks you to * After opening or updating a pull request, send the user a short message with a link to the pull request. * Do all of the above in as few steps as possible. E.g. you could open a PR with one step by running the following bash commands: ```bash -git checkout -b create-widget -git add . -git commit -m "Create widget" -git push origin create-widget -curl -X POST "https://api.github.com/repos/CodeActOrg/openhands/pulls" \ +git remote -v && git branch # to find the current org, repo and branch +git checkout -b create-widget && git add . && git commit -m "Create widget" && git push -u origin create-widget +curl -X POST "https://api.github.com/repos/$ORG_NAME/$REPO_NAME/pulls" \ -H "Authorization: Bearer $GITHUB_TOKEN" \ -d '{"title":"Create widget","head":"create-widget","base":"openhands-workspace"}' ``` From c9ed9b166be89d448c01a2ada5ef4ee525eb74b3 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Tue, 19 Nov 2024 13:46:03 -0500 Subject: [PATCH 15/34] handle exceptions more explicitly (#4971) --- openhands/controller/agent_controller.py | 4 ++-- openhands/core/logger.py | 9 ++++++-- openhands/runtime/base.py | 12 +++++++++-- .../impl/eventstream/eventstream_runtime.py | 20 ++++++++++++++++-- .../runtime/impl/remote/remote_runtime.py | 5 ++++- openhands/server/listen.py | 21 ++++++++++++++++--- openhands/server/session/agent_session.py | 6 +++--- openhands/server/session/manager.py | 7 ++++++- 8 files changed, 68 insertions(+), 16 deletions(-) diff --git a/openhands/controller/agent_controller.py b/openhands/controller/agent_controller.py index f9e4a8edb555..e0fa0dab0384 100644 --- a/openhands/controller/agent_controller.py +++ b/openhands/controller/agent_controller.py @@ -18,6 +18,7 @@ LLMNoActionError, LLMResponseError, ) +from openhands.core.logger import LOG_ALL_EVENTS from openhands.core.logger import openhands_logger as logger from openhands.core.schema import AgentState from openhands.events import EventSource, EventStream, EventStreamSubscriber @@ -528,8 +529,7 @@ async def _step(self) -> None: await self.update_state_after_step() - # Use info level if LOG_ALL_EVENTS is set - log_level = 'info' if os.getenv('LOG_ALL_EVENTS') in ('true', '1') else 'debug' + log_level = 'info' if LOG_ALL_EVENTS else 'debug' self.log(log_level, str(action), extra={'msg_type': 'ACTION'}) async def _delegate_step(self): diff --git a/openhands/core/logger.py b/openhands/core/logger.py index 1450e503515e..238b4c39435c 100644 --- a/openhands/core/logger.py +++ b/openhands/core/logger.py @@ -17,6 +17,8 @@ LOG_TO_FILE = os.getenv('LOG_TO_FILE', 'False').lower() in ['true', '1', 'yes'] DISABLE_COLOR_PRINTING = False +LOG_ALL_EVENTS = os.getenv('LOG_ALL_EVENTS', 'False').lower() in ['true', '1', 'yes'] + ColorType = Literal[ 'red', 'green', @@ -89,8 +91,11 @@ def format(self, record): return f'{time_str} - {name_str}:{level_str}: {record.filename}:{record.lineno}\n{msg_type_color}\n{msg}' return f'{time_str} - {msg_type_color}\n{msg}' elif msg_type == 'STEP': - msg = '\n\n==============\n' + record.msg + '\n' - return f'{msg}' + if LOG_ALL_EVENTS: + msg = '\n\n==============\n' + record.msg + '\n' + return f'{msg}' + else: + return record.msg return super().format(record) diff --git a/openhands/runtime/base.py b/openhands/runtime/base.py index b12c501c19f3..74891a7d52b0 100644 --- a/openhands/runtime/base.py +++ b/openhands/runtime/base.py @@ -47,11 +47,19 @@ } -class RuntimeNotReadyError(Exception): +class RuntimeUnavailableError(Exception): pass -class RuntimeDisconnectedError(Exception): +class RuntimeNotReadyError(RuntimeUnavailableError): + pass + + +class RuntimeDisconnectedError(RuntimeUnavailableError): + pass + + +class RuntimeNotFoundError(RuntimeUnavailableError): pass diff --git a/openhands/runtime/impl/eventstream/eventstream_runtime.py b/openhands/runtime/impl/eventstream/eventstream_runtime.py index e65c36cc67c6..fe8f67f29552 100644 --- a/openhands/runtime/impl/eventstream/eventstream_runtime.py +++ b/openhands/runtime/impl/eventstream/eventstream_runtime.py @@ -34,7 +34,11 @@ ) from openhands.events.serialization import event_to_dict, observation_from_dict from openhands.events.serialization.action import ACTION_TYPE_TO_CLASS -from openhands.runtime.base import Runtime +from openhands.runtime.base import ( + Runtime, + RuntimeDisconnectedError, + RuntimeNotFoundError, +) from openhands.runtime.builder import DockerRuntimeBuilder from openhands.runtime.impl.eventstream.containers import remove_all_containers from openhands.runtime.plugins import PluginRequirement @@ -424,10 +428,22 @@ def _refresh_logs(self): @tenacity.retry( stop=tenacity.stop_after_delay(120) | stop_if_should_exit(), - reraise=(ConnectionRefusedError,), + retry=tenacity.retry_if_exception_type( + (ConnectionError, requests.exceptions.ConnectionError) + ), + reraise=True, wait=tenacity.wait_fixed(2), ) def _wait_until_alive(self): + try: + container = self.docker_client.containers.get(self.container_name) + if container.status == 'exited': + raise RuntimeDisconnectedError( + f'Container {self.container_name} has exited.' + ) + except docker.errors.NotFound: + raise RuntimeNotFoundError(f'Container {self.container_name} not found.') + self._refresh_logs() if not self.log_buffer: raise RuntimeError('Runtime client is not ready.') diff --git a/openhands/runtime/impl/remote/remote_runtime.py b/openhands/runtime/impl/remote/remote_runtime.py index 4191a047b1c2..d996441b66c9 100644 --- a/openhands/runtime/impl/remote/remote_runtime.py +++ b/openhands/runtime/impl/remote/remote_runtime.py @@ -31,6 +31,7 @@ from openhands.runtime.base import ( Runtime, RuntimeDisconnectedError, + RuntimeNotFoundError, RuntimeNotReadyError, ) from openhands.runtime.builder.remote import RemoteRuntimeBuilder @@ -109,7 +110,9 @@ def _start_or_attach_to_runtime(self): if existing_runtime: self.log('debug', f'Using existing runtime with ID: {self.runtime_id}') elif self.attach_to_existing: - raise RuntimeError('Could not find existing runtime to attach to.') + raise RuntimeNotFoundError( + f'Could not find existing runtime for SID: {self.sid}' + ) else: self.send_status_message('STATUS$STARTING_CONTAINER') if self.config.sandbox.runtime_container_image is None: diff --git a/openhands/server/listen.py b/openhands/server/listen.py index 8724daf1905f..929a26ec987d 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -34,6 +34,7 @@ Request, UploadFile, WebSocket, + WebSocketDisconnect, status, ) from fastapi.responses import FileResponse, JSONResponse @@ -238,7 +239,8 @@ async def attach_session(request: Request, call_next): request.state.conversation = await session_manager.attach_to_conversation( request.state.sid ) - if request.state.conversation is None: + if not request.state.conversation: + logger.error(f'Runtime not found for session: {request.state.sid}') return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={'error': 'Session not found'}, @@ -344,7 +346,13 @@ async def websocket_endpoint(websocket: WebSocket): latest_event_id = -1 if websocket.query_params.get('latest_event_id'): - latest_event_id = int(websocket.query_params.get('latest_event_id')) + try: + latest_event_id = int(websocket.query_params.get('latest_event_id')) + except ValueError: + logger.warning( + f'Invalid latest_event_id: {websocket.query_params.get("latest_event_id")}' + ) + pass async_stream = AsyncEventStreamWrapper( session.agent_session.event_stream, latest_event_id + 1 @@ -361,7 +369,14 @@ async def websocket_endpoint(websocket: WebSocket): ), ): continue - await websocket.send_json(event_to_dict(event)) + try: + await websocket.send_json(event_to_dict(event)) + except WebSocketDisconnect: + logger.warning( + 'Websocket disconnected while sending event history, before loop started' + ) + session.close() + return await session.loop_recv() diff --git a/openhands/server/session/agent_session.py b/openhands/server/session/agent_session.py index 8f9d20a5dc6e..76f6e2aa8bcb 100644 --- a/openhands/server/session/agent_session.py +++ b/openhands/server/session/agent_session.py @@ -11,7 +11,7 @@ from openhands.events.event import EventSource from openhands.events.stream import EventStream from openhands.runtime import get_runtime_cls -from openhands.runtime.base import Runtime +from openhands.runtime.base import Runtime, RuntimeUnavailableError from openhands.security import SecurityAnalyzer, options from openhands.storage.files import FileStore @@ -194,13 +194,13 @@ async def _create_runtime( try: await self.runtime.connect() - except Exception as e: + except RuntimeUnavailableError as e: logger.error(f'Runtime initialization failed: {e}', exc_info=True) if self._status_callback: self._status_callback( 'error', 'STATUS$ERROR_RUNTIME_DISCONNECTED', str(e) ) - raise + return if self.runtime is not None: logger.debug( diff --git a/openhands/server/session/manager.py b/openhands/server/session/manager.py index f746b3676e29..790b7c4bd1eb 100644 --- a/openhands/server/session/manager.py +++ b/openhands/server/session/manager.py @@ -6,6 +6,7 @@ from openhands.core.config import AppConfig from openhands.core.logger import openhands_logger as logger from openhands.events.stream import session_exists +from openhands.runtime.base import RuntimeUnavailableError from openhands.server.session.conversation import Conversation from openhands.server.session.session import Session from openhands.storage.files import FileStore @@ -26,7 +27,11 @@ async def attach_to_conversation(self, sid: str) -> Conversation | None: if not await session_exists(sid, self.file_store): return None c = Conversation(sid, file_store=self.file_store, config=self.config) - await c.connect() + try: + await c.connect() + except RuntimeUnavailableError as e: + logger.error(f'Error connecting to conversation {c.sid}: {e}') + return None end_time = time.time() logger.info( f'Conversation {c.sid} connected in {end_time - start_time} seconds' From 3c61a9521b5718754e34600f86a7397b4f8d1856 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Tue, 19 Nov 2024 13:46:14 -0500 Subject: [PATCH 16/34] Simple initial rate limiting implementation (#4976) --- openhands/server/listen.py | 11 ++++++- openhands/server/middleware.py | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/openhands/server/listen.py b/openhands/server/listen.py index 929a26ec987d..433b13bde208 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -64,7 +64,12 @@ from openhands.llm import bedrock from openhands.runtime.base import Runtime from openhands.server.auth.auth import get_sid_from_token, sign_token -from openhands.server.middleware import LocalhostCORSMiddleware, NoCacheMiddleware +from openhands.server.middleware import ( + InMemoryRateLimiter, + LocalhostCORSMiddleware, + NoCacheMiddleware, + RateLimitMiddleware, +) from openhands.server.session import SessionManager load_dotenv() @@ -84,6 +89,10 @@ app.add_middleware(NoCacheMiddleware) +app.add_middleware( + RateLimitMiddleware, rate_limiter=InMemoryRateLimiter(requests=2, seconds=1) +) + security_scheme = HTTPBearer() diff --git a/openhands/server/middleware.py b/openhands/server/middleware.py index 218a949fca58..872241fc865f 100644 --- a/openhands/server/middleware.py +++ b/openhands/server/middleware.py @@ -1,6 +1,11 @@ +import asyncio +from collections import defaultdict +from datetime import datetime, timedelta from urllib.parse import urlparse +from fastapi import Request from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse from starlette.middleware.base import BaseHTTPMiddleware from starlette.types import ASGIApp @@ -41,3 +46,55 @@ async def dispatch(self, request, call_next): response.headers['Pragma'] = 'no-cache' response.headers['Expires'] = '0' return response + + +class InMemoryRateLimiter: + history: dict + requests: int + seconds: int + sleep_seconds: int + + def __init__(self, requests: int = 2, seconds: int = 1, sleep_seconds: int = 1): + self.requests = requests + self.seconds = seconds + self.history = defaultdict(list) + + def _clean_old_requests(self, key: str) -> None: + now = datetime.now() + cutoff = now - timedelta(seconds=self.seconds) + self.history[key] = [ts for ts in self.history[key] if ts > cutoff] + + async def __call__(self, request: Request) -> bool: + key = request.client.host + now = datetime.now() + + self._clean_old_requests(key) + + self.history[key].append(now) + + if len(self.history[key]) > self.requests * 2: + return False + elif len(self.history[key]) > self.requests: + if self.sleep_seconds > 0: + await asyncio.sleep(self.sleep_seconds) + return True + else: + return False + + return True + + +class RateLimitMiddleware(BaseHTTPMiddleware): + def __init__(self, app: ASGIApp, rate_limiter: InMemoryRateLimiter): + super().__init__(app) + self.rate_limiter = rate_limiter + + async def dispatch(self, request, call_next): + ok = await self.rate_limiter(request) + if not ok: + return JSONResponse( + status_code=429, + content={'message': 'Too many requests'}, + headers={'Retry-After': '1'}, + ) + return await call_next(request) From 302e41d7bb3d5b2b319f1ce2d15e5925dda069a2 Mon Sep 17 00:00:00 2001 From: mamoodi Date: Tue, 19 Nov 2024 14:53:24 -0500 Subject: [PATCH 17/34] Release 0.14.1 (#5133) --- frontend/package-lock.json | 2 +- frontend/package.json | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2d45a56c6c11..cfd8519e1adb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,6 +1,6 @@ { "name": "openhands-frontend", - "version": "0.14.0", + "version": "0.14.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/frontend/package.json b/frontend/package.json index c1415b02bd5a..1757adbe8ac3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "openhands-frontend", - "version": "0.14.0", + "version": "0.14.1", "private": true, "type": "module", "engines": { diff --git a/pyproject.toml b/pyproject.toml index 1caad8bf9fc7..53648ae7d8e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openhands-ai" -version = "0.14.0" +version = "0.14.1" description = "OpenHands: Code Less, Make More" authors = ["OpenHands"] license = "MIT" From 018080aae0ea01f466f7f7297431a8d67c2f86c7 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Tue, 19 Nov 2024 17:01:07 -0500 Subject: [PATCH 18/34] fix rate limiting (#5135) --- frontend/package-lock.json | 2 +- openhands/server/listen.py | 2 +- openhands/server/middleware.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cfd8519e1adb..a5abe9cc6a58 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "openhands-frontend", - "version": "0.14.0", + "version": "0.14.1", "dependencies": { "@monaco-editor/react": "^4.6.0", "@nextui-org/react": "^2.4.8", diff --git a/openhands/server/listen.py b/openhands/server/listen.py index 433b13bde208..95d61f434a90 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -90,7 +90,7 @@ app.add_middleware(NoCacheMiddleware) app.add_middleware( - RateLimitMiddleware, rate_limiter=InMemoryRateLimiter(requests=2, seconds=1) + RateLimitMiddleware, rate_limiter=InMemoryRateLimiter(requests=10, seconds=1) ) diff --git a/openhands/server/middleware.py b/openhands/server/middleware.py index 872241fc865f..1938e253b68a 100644 --- a/openhands/server/middleware.py +++ b/openhands/server/middleware.py @@ -57,6 +57,7 @@ class InMemoryRateLimiter: def __init__(self, requests: int = 2, seconds: int = 1, sleep_seconds: int = 1): self.requests = requests self.seconds = seconds + self.sleep_seconds = sleep_seconds self.history = defaultdict(list) def _clean_old_requests(self, key: str) -> None: From a3977621ed25db336f71006e2d197c1644505e34 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Tue, 19 Nov 2024 17:40:20 -0500 Subject: [PATCH 19/34] Add /health endpoint to server (#5136) Co-authored-by: openhands --- openhands/server/listen.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openhands/server/listen.py b/openhands/server/listen.py index 95d61f434a90..f5463a517306 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -94,6 +94,11 @@ ) +@app.get('/health') +async def health(): + return 'OK' + + security_scheme = HTTPBearer() From 2a78b3323b98b82195044e18c13d53cf1e2c8ac6 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Tue, 19 Nov 2024 17:42:49 -0500 Subject: [PATCH 20/34] Adding experimental option for resolver macro (#5131) --- .github/workflows/openhands-resolver.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/openhands-resolver.yml b/.github/workflows/openhands-resolver.yml index 44875b177ec5..b517f4c46e27 100644 --- a/.github/workflows/openhands-resolver.yml +++ b/.github/workflows/openhands-resolver.yml @@ -40,7 +40,6 @@ permissions: issues: write jobs: - auto-fix: if: | github.event_name == 'workflow_call' || @@ -76,7 +75,18 @@ jobs: cat requirements.txt - name: Cache pip dependencies - if: github.event.label.name != 'fix-me-experimental' + if: | + !( + github.event.label.name == 'fix-me-experimental' || + ( + (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') && + startsWith(github.event.comment.body, inputs.macro || '@openhands-agent-exp') + ) || + ( + github.event_name == 'pull_request_review' && + startsWith(github.event.review.body, inputs.macro || '@openhands-agent-exp') + ) + ) uses: actions/cache@v3 with: path: ${{ env.pythonLocation }}/lib/python3.12/site-packages/* @@ -140,7 +150,11 @@ jobs: - name: Install OpenHands run: | - if [ "${{ github.event.label.name }}" == "fix-me-experimental" ]; then + if [[ "${{ github.event.label.name }}" == "fix-me-experimental" ]] || + ([[ "${{ github.event_name }}" == "issue_comment" || "${{ github.event_name }}" == "pull_request_review_comment" ]] && + [[ "${{ github.event.comment.body }}" == "@openhands-agent-exp"* ]]) || + ([[ "${{ github.event_name }}" == "pull_request_review" ]] && + [[ "${{ github.event.review.body }}" == "@openhands-agent-exp"* ]]); then python -m pip install --upgrade pip pip install git+https://github.com/all-hands-ai/openhands.git else From 24a83eb52d13db6a065b81c8d4e51c915eef7af0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:48:40 +0000 Subject: [PATCH 21/34] Bump the docusaurus group in /docs with 7 updates (#5140) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 2936 +++++++++++++++++++++++++++++++++------- docs/package.json | 10 +- docs/yarn.lock | 1059 ++++++++++++--- 3 files changed, 3302 insertions(+), 703 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index dd2dbf1f3260..fae84142406a 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,10 +8,10 @@ "name": "docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "^3.6.0", - "@docusaurus/plugin-content-pages": "^3.6.0", - "@docusaurus/preset-classic": "^3.6.0", - "@docusaurus/theme-mermaid": "^3.6.0", + "@docusaurus/core": "^3.6.2", + "@docusaurus/plugin-content-pages": "^3.6.2", + "@docusaurus/preset-classic": "^3.6.2", + "@docusaurus/theme-mermaid": "^3.6.2", "@mdx-js/react": "^3.1.0", "clsx": "^2.0.0", "prism-react-renderer": "^2.4.0", @@ -22,7 +22,7 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.5.1", - "@docusaurus/tsconfig": "^3.6.0", + "@docusaurus/tsconfig": "^3.6.2", "@docusaurus/types": "^3.5.1", "typescript": "~5.6.3" }, @@ -31,31 +31,31 @@ } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.6.tgz", - "integrity": "sha512-lkDoW4I7h2kKlIgf3pUt1LqvxyYKkVyiypoGLlUnhPSnCpmeOwudM6rNq6YYsCmdQtnDQoW5lUNNuj6ASg3qeg==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.17.6", - "@algolia/autocomplete-shared": "1.17.6" + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" } }, "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.6.tgz", - "integrity": "sha512-17NnaacuFzSWVuZu4NKzVeaFIe9Abpw8w+/gjc7xhZFtqj+GadufzodIdchwiB2eM2cDdiR3icW7gbNTB3K2YA==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", "dependencies": { - "@algolia/autocomplete-shared": "1.17.6" + "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.6.tgz", - "integrity": "sha512-Cvg5JENdSCMuClwhJ1ON1/jSuojaYMiUW2KePm18IkdCzPJj/NXojaOxw58RFtQFpJgfVW8h2E8mEoDtLlMdeA==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", "dependencies": { - "@algolia/autocomplete-shared": "1.17.6" + "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -63,9 +63,9 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.6.tgz", - "integrity": "sha512-aq/3V9E00Tw2GC/PqgyPGXtqJUlVc17v4cn1EUhSc+O/4zd04Uwb3UmPm8KDaYQQOrkt1lwvCj2vG2wRE5IKhw==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" @@ -93,14 +93,14 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.12.0.tgz", - "integrity": "sha512-hx4eVydkm3yrFCFxmcBtSzI/ykt0cZ6sDWch+v3JTgKpD2WtosMJU3Upv1AjQ4B6COSHCOWEX3vfFxW6OoH6aA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.15.0.tgz", + "integrity": "sha512-FaEM40iuiv1mAipYyiptP4EyxkJ8qHfowCpEeusdHUC4C7spATJYArD2rX3AxkVeREkDIgYEOuXcwKUbDCr7Nw==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -166,22 +166,22 @@ } }, "node_modules/@algolia/client-common": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.12.0.tgz", - "integrity": "sha512-od3WmO8qxyfNhKc+K3D17tvun3IMs/xMNmxCG9MiElAkYVbPPTRUYMkRneCpmJyQI0hNx2/EA4kZgzVfQjO86Q==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.15.0.tgz", + "integrity": "sha512-IofrVh213VLsDkPoSKMeM9Dshrv28jhDlBDLRcVJQvlL8pzue7PEB1EZ4UoJFYS3NSn7JOcJ/V+olRQzXlJj1w==", "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.12.0.tgz", - "integrity": "sha512-8alajmsYUd+7vfX5lpRNdxqv3Xx9clIHLUItyQK0Z6gwGMbVEFe6YYhgDtwslMAP0y6b0WeJEIZJMLgT7VYpRw==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.15.0.tgz", + "integrity": "sha512-bDDEQGfFidDi0UQUCbxXOCdphbVAgbVmxvaV75cypBTQkJ+ABx/Npw7LkFGw1FsoVrttlrrQbwjvUB6mLVKs/w==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -207,28 +207,28 @@ } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.12.0.tgz", - "integrity": "sha512-Q5CszzGWfxbIDs9DJ/QJsL7bP6h+lJMg27KxieEnI9KGCu0Jt5iFA3GkREkgRZxRdzlHbZKkrIzhtHVbSHw/rg==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.15.0.tgz", + "integrity": "sha512-wu8GVluiZ5+il8WIRsGKu8VxMK9dAlr225h878GGtpTL6VBvwyJvAyLdZsfFIpY0iN++jiNb31q2C1PlPL+n/A==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.12.0.tgz", - "integrity": "sha512-R3qzEytgVLHOGNri+bpta6NtTt7YtkvUe/QBcAmMDjW4Jk1P0eBYIPfvnzIPbINRsLxIq9fZs9uAYBgsrts4Zg==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.15.0.tgz", + "integrity": "sha512-Z32gEMrRRpEta5UqVQA612sLdoqY3AovvUPClDfMxYrbdDAebmGDVPtSogUba1FZ4pP5dx20D3OV3reogLKsRA==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -240,14 +240,14 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "node_modules/@algolia/ingestion": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.12.0.tgz", - "integrity": "sha512-zpHo6qhR22tL8FsdSI4DvEraPDi/019HmMrCFB/TUX98yzh5ooAU7sNW0qPL1I7+S++VbBmNzJOEU9VI8tEC8A==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.15.0.tgz", + "integrity": "sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -267,14 +267,14 @@ } }, "node_modules/@algolia/monitoring": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.12.0.tgz", - "integrity": "sha512-i2AJZED/zf4uhxezAJUhMKoL5QoepCBp2ynOYol0N76+TSoohaMADdPnWCqOULF4RzOwrG8wWynAwBlXsAI1RQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.15.0.tgz", + "integrity": "sha512-QPrFnnGLMMdRa8t/4bs7XilPYnoUXDY8PMQJ1sf9ZFwhUysYYhQNX34/enoO0LBjpoOY6rLpha39YQEFbzgKyQ==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -334,11 +334,11 @@ } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.12.0.tgz", - "integrity": "sha512-KxwleraFuVoEGCoeW6Y1RAEbgBMS7SavqeyzWdtkJc6mXeCOJXn1iZitb8Tyn2FcpMNUKlSm0adrUTt7G47+Ow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.15.0.tgz", + "integrity": "sha512-Po/GNib6QKruC3XE+WKP1HwVSfCDaZcXu48kD+gwmtDlqHWKc7Bq9lrS0sNZ456rfCKhXksOmMfUs4wRM/Y96w==", "dependencies": { - "@algolia/client-common": "5.12.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -350,22 +350,22 @@ "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==" }, "node_modules/@algolia/requester-fetch": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.12.0.tgz", - "integrity": "sha512-FuDZXUGU1pAg2HCnrt8+q1VGHKChV/LhvjvZlLOT7e56GJie6p+EuLu4/hMKPOVuQQ8XXtrTHKIU3Lw+7O5/bQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.15.0.tgz", + "integrity": "sha512-rOZ+c0P7ajmccAvpeeNrUmEKoliYFL8aOR5qGW5pFq3oj3Iept7Y5mEtEsOBYsRt6qLnaXn4zUKf+N8nvJpcIw==", "dependencies": { - "@algolia/client-common": "5.12.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.12.0.tgz", - "integrity": "sha512-ncDDY7CxZhMs6LIoPl+vHFQceIBhYPY5EfuGF1V7beO0U38xfsCYEyutEFB2kRzf4D9Gqppn3iWX71sNtrKcuw==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.15.0.tgz", + "integrity": "sha512-b1jTpbFf9LnQHEJP5ddDJKE2sAlhYd7EVSOWgzo/27n/SfCoHfqD0VWntnWYD83PnOKvfe8auZ2+xCb0TXotrQ==", "dependencies": { - "@algolia/client-common": "5.12.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -2002,208 +2002,1264 @@ "node": ">=0.1.90" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz", + "integrity": "sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { - "node": ">=10.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" } }, - "node_modules/@docsearch/css": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.7.0.tgz", - "integrity": "sha512-1OorbTwi1eeDmr0v5t+ckSRlt1zM5GHjm92iIl3kUu7im3GHuP+csf6E0WBg8pdXQczTWP9J9+o9n+Vg6DH5cQ==" + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@docsearch/react": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.7.0.tgz", - "integrity": "sha512-8e6tdDfkYoxafEEPuX5eE1h9cTkLvhe4KgoFkO5JCddXSQONnN1FHcDZRI4r8894eMpbYq6rdJF0dVYh8ikwNQ==", - "dependencies": { - "@algolia/autocomplete-core": "1.17.6", - "@algolia/autocomplete-preset-algolia": "1.17.6", - "@docsearch/css": "3.7.0", - "algoliasearch": "^5.12.0" + "node_modules/@csstools/css-calc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.0.tgz", + "integrity": "sha512-X69PmFOrjTZfN5ijxtI8hZ9kRADFSLrmmQ6hgDJ272Il049WGKpDY64KhrFm/7rbWve0z81QepawzjkKlqkNGw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0", - "search-insights": ">= 1 < 3" + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.6.tgz", + "integrity": "sha512-S/IjXqTHdpI4EtzGoNCHfqraXF37x12ZZHA1Lk7zoT5pm2lMjFuqhX/89L7dqX4CcMacKK+6ZCs5TmEGb/+wKw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" }, - "react": { - "optional": true + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" }, - "react-dom": { - "optional": true + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" }, - "search-insights": { - "optional": true + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" } }, - "node_modules/@docsearch/react/node_modules/@algolia/client-analytics": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.12.0.tgz", - "integrity": "sha512-EpTsSv6IW8maCfXCDIptgT7+mQJj7pImEkcNUnxR8yUKAHzTogTXv9yGm2WXOZFVuwstd2i0sImhQ1Vz8RH/hA==", + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz", + "integrity": "sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" }, "engines": { - "node": ">= 14.0.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/@docsearch/react/node_modules/@algolia/client-personalization": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.12.0.tgz", - "integrity": "sha512-bUV9HtfkTBgpoVhxFrMkmVPG03ZN1Rtn51kiaEtukucdk3ggjR9Qu1YUfRSU2lFgxr9qJc8lTxwfvhjCeJRcqw==", + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">= 14.0.0" + "node": ">=4" } }, - "node_modules/@docsearch/react/node_modules/@algolia/recommend": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.12.0.tgz", - "integrity": "sha512-0jmZyKvYnB/Bj5c7WKsKedOUjnr0UtXm0LVFUdQrxXfqOqvWv9n6Vpr65UjdYG4Q49kRQxhlwtal9WJYrYymXg==", + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.6.tgz", + "integrity": "sha512-EcvXfC60cTIumzpsxWuvVjb7rsJEHPvqn3jeMEBUaE3JSc4FRuP7mEQ+1eicxWmIrs3FtzMH9gR3sgA5TH+ebQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@algolia/client-common": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">= 14.0.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/@docsearch/react/node_modules/algoliasearch": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.12.0.tgz", - "integrity": "sha512-psGBRYdGgik8I6m28iAB8xpubvjEt7UQU+w5MAJUA2324WHiGoHap5BPkkjB14rMaXeRts6pmOsrVIglGyOVwg==", - "dependencies": { - "@algolia/client-abtesting": "5.12.0", - "@algolia/client-analytics": "5.12.0", - "@algolia/client-common": "5.12.0", - "@algolia/client-insights": "5.12.0", - "@algolia/client-personalization": "5.12.0", - "@algolia/client-query-suggestions": "5.12.0", - "@algolia/client-search": "5.12.0", - "@algolia/ingestion": "1.12.0", - "@algolia/monitoring": "1.12.0", - "@algolia/recommend": "5.12.0", - "@algolia/requester-browser-xhr": "5.12.0", - "@algolia/requester-fetch": "5.12.0", - "@algolia/requester-node-http": "5.12.0" + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.6.tgz", + "integrity": "sha512-jVKdJn4+JkASYGhyPO+Wa5WXSx1+oUgaXb3JsjJn/BlrtFh5zjocCY7pwWi0nuP24V1fY7glQsxEYcYNy0dMFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">= 14.0.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/@docusaurus/babel": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.6.0.tgz", - "integrity": "sha512-7CsoQFiadoq7AHSUIQNkI/lGfg9AQ2ZBzsf9BqfZGXkHwWDy6twuohEaG0PgQv1npSRSAB2dioVxhRSErnqKNA==", + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", + "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@babel/core": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.25.9", - "@babel/preset-env": "^7.25.9", - "@babel/preset-react": "^7.25.9", - "@babel/preset-typescript": "^7.25.9", - "@babel/runtime": "^7.25.9", - "@babel/runtime-corejs3": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@docusaurus/logger": "3.6.0", - "@docusaurus/utils": "3.6.0", - "babel-plugin-dynamic-import-node": "^2.3.3", - "fs-extra": "^11.1.1", - "tslib": "^2.6.0" + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=18.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/@docusaurus/bundler": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.6.0.tgz", - "integrity": "sha512-o5T9HXkPKH0OQAifTxEXaebcO8kaz3tU1+wlIShZ2DKJHlsyWX3N4rToWBHroWnV/ZCT2XN3kLRzXASqrnb9Tw==", + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.5.tgz", + "integrity": "sha512-mi8R6dVfA2nDoKM3wcEi64I8vOYEgQVtVKCfmLHXupeLpACfGAided5ddMt5f+CnEodNu4DifuVwb0I6fQDGGQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.6.0", - "@docusaurus/cssnano-preset": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "autoprefixer": "^10.4.14", - "babel-loader": "^9.2.1", - "clean-css": "^5.3.2", - "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.8.1", - "css-minimizer-webpack-plugin": "^5.0.1", - "cssnano": "^6.1.2", - "file-loader": "^6.2.0", - "html-minifier-terser": "^7.2.0", - "mini-css-extract-plugin": "^2.9.1", - "null-loader": "^4.0.1", - "postcss": "^8.4.26", - "postcss-loader": "^7.3.3", - "react-dev-utils": "^12.0.1", - "terser-webpack-plugin": "^5.3.9", - "tslib": "^2.6.0", - "url-loader": "^4.1.1", - "webpack": "^5.95.0", - "webpackbar": "^6.0.1" + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" }, "engines": { - "node": ">=18.0" + "node": ">=18" }, "peerDependencies": { - "@docusaurus/faster": "3.5.2" - }, - "peerDependenciesMeta": { - "@docusaurus/faster": { - "optional": true - } + "postcss": "^8.4" } }, - "node_modules/@docusaurus/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.6.0.tgz", - "integrity": "sha512-lvRgMoKJJSRDt9+HhAqFcICV4kp/mw1cJJrLxIw4Q2XZnFGM1XUuwcbuaqWmGog+NcOLZaPCcCtZbn60EMCtjQ==", - "dependencies": { - "@docusaurus/babel": "3.6.0", - "@docusaurus/bundler": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cli-table3": "^0.6.3", - "combine-promises": "^1.1.0", - "commander": "^5.1.0", - "core-js": "^3.31.1", - "del": "^6.1.1", - "detect-port": "^1.5.1", - "escape-html": "^1.0.3", - "eta": "^2.2.0", - "eval": "^0.1.8", - "fs-extra": "^11.1.1", + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.6.tgz", + "integrity": "sha512-0ke7fmXfc8H+kysZz246yjirAH6JFhyX9GTlyRnM0exHO80XcA9zeJpy5pOp5zo/AZiC/q5Pf+Hw7Pd6/uAoYA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.6.tgz", + "integrity": "sha512-Itrbx6SLUzsZ6Mz3VuOlxhbfuyLTogG5DwEF1V8dAi24iMuvQPIHd7Ti+pNDp7j6WixndJGZaoNR0f9VSzwuTg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.6.tgz", + "integrity": "sha512-927Pqy3a1uBP7U8sTfaNdZVB0mNXzIrJO/GZ8us9219q9n06gOqCdfZ0E6d1P66Fm0fYHvxfDbfcUuwAn5UwhQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", + "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", + "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz", + "integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", + "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz", + "integrity": "sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.5.tgz", + "integrity": "sha512-sdh5i5GToZOIAiwhdntRWv77QDtsxP2r2gXW/WbLSCoLr00KTq/yiF1qlQ5XX2+lmiFa8rATKMcbwl3oXDMNew==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz", + "integrity": "sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz", + "integrity": "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.6.tgz", + "integrity": "sha512-Hptoa0uX+XsNacFBCIQKTUBrFKDiplHan42X73EklG6XmQLG7/aIvxoNhvZ7PvOWMt67Pw3bIlUY2nD6p5vL8A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", + "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.1.tgz", + "integrity": "sha512-Ab/tF8/RXktQlFwVhiC70UNfpFQRhtE5fQQoP2pO+KCPGLsLdWFiOuHgSRtBOqEshCVAzR4H6o38nhvRZq8deA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.6.tgz", + "integrity": "sha512-yxP618Xb+ji1I624jILaYM62uEmZcmbdmFoZHoaThw896sq0vU39kqTTF+ZNic9XyPtPMvq0vyvbgmHaszq8xg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.0.tgz", + "integrity": "sha512-SLcc20Nujx/kqbSwDmj6oaXgpy3UjFhBy1sfcqPgDkHfOIfUtUVH7OXO+j7BU4v/At5s61N5ZX6shvgPwluhsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.5.tgz", + "integrity": "sha512-G6SJ6hZJkhxo6UZojVlLo14MohH4J5J7z8CRBrxxUYy9JuZiIqUo5TBYyDGcE0PLdzpg63a7mHSJz3VD+gMwqw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", + "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.5.tgz", + "integrity": "sha512-/YQThYkt5MLvAmVu7zxjhceCYlKrYddK6LEmK5I4ojlS6BmO9u2yO4+xjXzu2+NPYmHSTtP4NFSamBCMmJ1NJA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^2.1.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.0.tgz", + "integrity": "sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==" + }, + "node_modules/@docsearch/react": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.0.tgz", + "integrity": "sha512-WnFK720+iwTVt94CxY3u+FgX6exb3BfN5kE9xUY6uuAH/9W/UFboBZFLlrw/zxFRHoHZCOXRtOylsXF+6LHI+Q==", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.0", + "algoliasearch": "^5.12.0" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-analytics": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.15.0.tgz", + "integrity": "sha512-lho0gTFsQDIdCwyUKTtMuf9nCLwq9jOGlLGIeQGKDxXF7HbiAysFIu5QW/iQr1LzMgDyM9NH7K98KY+BiIFriQ==", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-personalization": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.15.0.tgz", + "integrity": "sha512-LfaZqLUWxdYFq44QrasCDED5bSYOswpQjSiIL7Q5fYlefAAUO95PzBPKCfUhSwhb4rKxigHfDkd81AvEicIEoA==", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/recommend": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.15.0.tgz", + "integrity": "sha512-5eupMwSqMLDObgSMF0XG958zR6GJP3f7jHDQ3/WlzCM9/YIJiWIUoJFGsko9GYsA5xbLDHE/PhWtq4chcCdaGQ==", + "dependencies": { + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/algoliasearch": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.15.0.tgz", + "integrity": "sha512-Yf3Swz1s63hjvBVZ/9f2P1Uu48GjmjCN+Esxb6MAONMGtZB1fRX8/S1AhUTtsuTlcGovbYLxpHgc7wEzstDZBw==", + "dependencies": { + "@algolia/client-abtesting": "5.15.0", + "@algolia/client-analytics": "5.15.0", + "@algolia/client-common": "5.15.0", + "@algolia/client-insights": "5.15.0", + "@algolia/client-personalization": "5.15.0", + "@algolia/client-query-suggestions": "5.15.0", + "@algolia/client-search": "5.15.0", + "@algolia/ingestion": "1.15.0", + "@algolia/monitoring": "1.15.0", + "@algolia/recommend": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.6.2.tgz", + "integrity": "sha512-v8N8TWGXDsb5sxQC3Rcqb1CZr0LlU1OgqqVBUchN6cpIUr7EJuVJs5eHcIu5Ag8mwO/hWN3f7FE9uaHTMapAbg==", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/runtime-corejs3": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.6.2", + "@docusaurus/utils": "3.6.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.6.2.tgz", + "integrity": "sha512-YkEifEVs4lV931SrHBB4n6WqRowMw+aM/QPH3z8aU+5t1dWa+1p2OPqARS+tSbh3la9ns+L1zIfSbd8RHi2/PQ==", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.6.2", + "@docusaurus/cssnano-preset": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.2", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.1", + "null-loader": "^4.0.1", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "postcss-preset-env": "^10.1.0", + "react-dev-utils": "^12.0.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^6.0.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.6.2.tgz", + "integrity": "sha512-irMts/mGLZv8dWcy0WUtbY/U6b5qIfHgQd1/kXMyAxUJo99fL0wFSqhMI+tcxjk0HYy427MXerLMqFJj+Arg1w==", + "dependencies": { + "@docusaurus/babel": "3.6.2", + "@docusaurus/bundler": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "fs-extra": "^11.1.1", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.6.0", "leven": "^3.1.0", @@ -2254,9 +3310,9 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.0.tgz", - "integrity": "sha512-h3jlOXqqzNSoU+C4CZLNpFtD+v2xr1UBf4idZpwMgqid9r6lb5GS7tWKnQnauio6OipacbHbDXEX3JyT1PlDkg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.2.tgz", + "integrity": "sha512-mBkVa4QMHRwCFCVLYdBlOZuAT1iVVsS7GGSgliSVAeTOagP/AbtlBsCVrBs+keEuDuRF1w/6QEcqDoZe9fa5pw==", "dependencies": { "cssnano-preset-advanced": "^6.1.2", "postcss": "^8.4.38", @@ -2268,9 +3324,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.6.0.tgz", - "integrity": "sha512-BcQhoXilXW0607cH/kO6P5Gt5KxCGfoJ+QDKNf3yO2S09/RsITlW+0QljXPbI3DklTrHrhRDmgGk1yX4nUhWTA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.6.2.tgz", + "integrity": "sha512-1p4IQhhgLyIfsey4UAdAIW69aUE1Ei6O91Nsw30ryZeDWSG5dh4o3zaRGOLxfAX69Ac/yDm6YCwJOafUxL6Vxg==", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.6.0" @@ -2280,13 +3336,13 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.6.0.tgz", - "integrity": "sha512-GhRzL1Af/AdSSrGesSPOU/iP/aXadTGmVKuysCxZDrQR2RtBtubQZ9aw+KvdFVV7R4K/CsbgD6J5oqrXlEPk3Q==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.6.2.tgz", + "integrity": "sha512-7fbRmNgF3CR96Ja82Ya0/Cdu1OL9UJ/22llNMY8lr5gAbw718Y5ryXMVRIYn0JNLTiSxzgtvW4DIsUWEB8NMpw==", "dependencies": { - "@docusaurus/logger": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "@docusaurus/logger": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", @@ -2318,11 +3374,11 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.0.tgz", - "integrity": "sha512-szTrIN/6/fuk0xkf3XbRfdTFJzRQ8d1s3sQj5++58wltrT7v3yn1149oc9ryYjMpRcbsarGloQwMu7ofPe4XPg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.2.tgz", + "integrity": "sha512-NrJkL2rLTCjHtWOqUvWzwqvJrsKLj0gVJeV6q5yeKdKKgItietcTf2fTRkM9LHKSUN8CBDXxwHABeQvTahvmXQ==", "dependencies": { - "@docusaurus/types": "3.6.0", + "@docusaurus/types": "3.6.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2336,18 +3392,18 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.0.tgz", - "integrity": "sha512-o4aT1/E0Ldpzs/hQff5uyoSriAhS/yqBhqSn+fvSw465AaqRsva6O7CZSYleuBq6x2bewyE3QJq2PcTiHhAd8g==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.2.tgz", + "integrity": "sha512-6bJxr6Or4NslEVH3BJuPH30kUWiqUjDRdGPhvxpHmt9W/RY2/6u72WICG3bW3dLFxJ/2uDLBU92lHnatpvo7Ew==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "cheerio": "1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^11.1.1", @@ -2369,19 +3425,19 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.0.tgz", - "integrity": "sha512-c5gZOxocJKO/Zev2MEZInli+b+VNswDGuKHE6QtFgidhAJonwjh2kwj967RvWFaMMk62HlLJLZ+IGK2XsVy4Aw==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/module-type-aliases": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.2.tgz", + "integrity": "sha512-e6WW1g10RIXXLN/rrtqTi/FyJ1Hj3X9Mmgz4V11/0pDCxIGGI8m4ocbAglUlLtgvbLD5viNLefl/NwbOW3JXiQ==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/module-type-aliases": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", @@ -2400,15 +3456,15 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.0.tgz", - "integrity": "sha512-RKHhJrfkadHc7+tt1cP48NWifOrhkSRMPdXNYytzhoQrXlP6Ph+3tfQ4/n+nT0S3Y9+wwRxYqRqA380ZLt+QtQ==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.2.tgz", + "integrity": "sha512-fo4NyGkw10lYHyHaTxE6TZLYnxNtCfRHeZkNK1N9pBYqe7TT2dBUNAEeVW2U3ed9m6YuB7JKSQsa++GGmcP+6g==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" @@ -2422,13 +3478,13 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.6.0.tgz", - "integrity": "sha512-o8T1Rl94COLdSlKvjYLQpRJQRU8WWZ8EX1B0yV0dQLNN8reyH7MQW+6z1ig4sQFfH3pnjPWVGHfuEjcib5m7Eg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.6.2.tgz", + "integrity": "sha512-T/eS3VvHElpeV5S8uwp7Si4ujEynmgFtJLvA2CSa5pzQuOF1EEghF9nekAIj0cWtDHsqNUDZNr8hK1brivFXSg==", "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", + "@docusaurus/core": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", "fs-extra": "^11.1.1", "react-json-view-lite": "^1.2.0", "tslib": "^2.6.0" @@ -2442,13 +3498,13 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.0.tgz", - "integrity": "sha512-kgRFbfpi6Hshj75YUztKyEMtI/kw0trPRwoTN4g+W1NK99R/vh8phTvhBTIMnDbetU79795LkwfG0rZ/ce6zWQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.2.tgz", + "integrity": "sha512-B7ihrr3wz8e4XqW+dIAtq844u3Z83u5CeiL1xrCqzFH+vDCjUZHTamS3zKXNcgi6YVVe6hUQXPG15ltaqQaVPQ==", "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "@docusaurus/core": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "tslib": "^2.6.0" }, "engines": { @@ -2460,13 +3516,13 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.0.tgz", - "integrity": "sha512-nqu4IfjaO4UX+dojHL2BxHRS+sKj31CIMWYo49huQ3wTET0Oc3u/WGTaKd3ShTPDhkgiRhTOSTPUwJWrU55nHg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.2.tgz", + "integrity": "sha512-V8ijI6qddAAkJ0vd8sjZ7S/apRTLJn9dAwvj/rSMd93witGdKINemL+9TyfLkhcXKTxyqRT8zKdu8ewjPXqKHg==", "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "@docusaurus/core": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "@types/gtag.js": "^0.0.12", "tslib": "^2.6.0" }, @@ -2479,13 +3535,13 @@ } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.0.tgz", - "integrity": "sha512-OU6c5xI0nOVbEc9eImGvvsgNWe4vGm97t/W3aLHjWsHyNk3uwFNBQMHRvBUwAi9k/K3kyC5E7DWnc67REhdLOw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.2.tgz", + "integrity": "sha512-fnWQ5FdN9f8c8VTgjaQ98208Y+d/JjHhD506rWIIL9rt1cJOf29XElxvOeKpMJadfkgY5KLZSAiHkGt+4qgN4g==", "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "@docusaurus/core": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "tslib": "^2.6.0" }, "engines": { @@ -2497,16 +3553,16 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.0.tgz", - "integrity": "sha512-YB5XMdf9FjLhgbHY/cDbYhVxsgcpPIjxY9769HUgFOB7GVzItTLOR71W035R1BiR2CA5QAn3XOSg36WLRxlhQQ==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.2.tgz", + "integrity": "sha512-qcAQAP1Ot0dZpeRoJ0L/Zck5FVDkll2IleVZQLzxeRVDZIw1P9/TK7/Aw1w2pmH7dmw/Cwk/cLSVRvLAmp9k7A==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" @@ -2520,23 +3576,23 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.6.0.tgz", - "integrity": "sha512-kpGNdQzr/Dpm7o3b1iaQrz4DMDx3WIeBbl4V4P4maa2zAQkTdlaP4CMgA5oKrRrpqPLnQFsUM/b+qf2glhl2Tw==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/plugin-content-blog": "3.6.0", - "@docusaurus/plugin-content-docs": "3.6.0", - "@docusaurus/plugin-content-pages": "3.6.0", - "@docusaurus/plugin-debug": "3.6.0", - "@docusaurus/plugin-google-analytics": "3.6.0", - "@docusaurus/plugin-google-gtag": "3.6.0", - "@docusaurus/plugin-google-tag-manager": "3.6.0", - "@docusaurus/plugin-sitemap": "3.6.0", - "@docusaurus/theme-classic": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/theme-search-algolia": "3.6.0", - "@docusaurus/types": "3.6.0" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.6.2.tgz", + "integrity": "sha512-r2n5eHdhiNSrJGsrrYcw+WsyStmXxe0ZG3RdA9LVyK5+jBHM8blrUWJEDugnzCNbyhUzhdtcmgCC9fhdAvKuQw==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/plugin-content-blog": "3.6.2", + "@docusaurus/plugin-content-docs": "3.6.2", + "@docusaurus/plugin-content-pages": "3.6.2", + "@docusaurus/plugin-debug": "3.6.2", + "@docusaurus/plugin-google-analytics": "3.6.2", + "@docusaurus/plugin-google-gtag": "3.6.2", + "@docusaurus/plugin-google-tag-manager": "3.6.2", + "@docusaurus/plugin-sitemap": "3.6.2", + "@docusaurus/theme-classic": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/theme-search-algolia": "3.6.2", + "@docusaurus/types": "3.6.2" }, "engines": { "node": ">=18.0" @@ -2547,23 +3603,23 @@ } }, "node_modules/@docusaurus/theme-classic": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.6.0.tgz", - "integrity": "sha512-sAXNfwPL6uRD+BuHuKXZfAXud7SS7IK/JdrPuzyQxdO1gJKzI5GFfe1ED1QoJDNWJWJ01JHE5rSnwYLEADc2rQ==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/module-type-aliases": "3.6.0", - "@docusaurus/plugin-content-blog": "3.6.0", - "@docusaurus/plugin-content-docs": "3.6.0", - "@docusaurus/plugin-content-pages": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/theme-translations": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.6.2.tgz", + "integrity": "sha512-bCdOPqPNezhLx+hgNVO2Cf+8/1AHa9uHDOqTx/CKAx2I0J/jV9G+6JiMtpSRKGNfBoLT1O+56/7+WtkOf54xTw==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/module-type-aliases": "3.6.2", + "@docusaurus/plugin-content-blog": "3.6.2", + "@docusaurus/plugin-content-docs": "3.6.2", + "@docusaurus/plugin-content-pages": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/theme-translations": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "copy-text-to-clipboard": "^3.2.0", @@ -2587,14 +3643,14 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.6.0.tgz", - "integrity": "sha512-frjlYE5sRs+GuPs4XXlp9aMLI2O4H5FPpznDAXBrCm+8EpWRiIb443ePMxM3IyMCQ5bwFlki0PI9C+r4apstnw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.6.2.tgz", + "integrity": "sha512-lfgsL064KEHpCkgGUc0OYoUPCpYfzggp6Hof8sz59UuKiLvb/Z7raewE9/NfocrJ2HZI17rLgMX3SQlRDh/5gg==", "dependencies": { - "@docusaurus/mdx-loader": "3.6.0", - "@docusaurus/module-type-aliases": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", + "@docusaurus/mdx-loader": "3.6.2", + "@docusaurus/module-type-aliases": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2614,15 +3670,15 @@ } }, "node_modules/@docusaurus/theme-mermaid": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.0.tgz", - "integrity": "sha512-5t7zzBnnJa4BBcGo9bEfTM48DxD/+CVbFkfiRnFXheWjMrMm5a+IP10igEQ4zyDC+QgatbzLAxkj4GRYpYTauA==", - "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/module-type-aliases": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/types": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.2.tgz", + "integrity": "sha512-Ui+rBtqMPKj3RCOxNlY04i1tEjNg+fZg4URTvkHmYR07hcKaJw+vkw+wlaYjd0HFZk+3Er9vUAcwsCWuea4cVQ==", + "dependencies": { + "@docusaurus/core": "3.6.2", + "@docusaurus/module-type-aliases": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "mermaid": ">=10.4", "tslib": "^2.6.0" }, @@ -2635,18 +3691,18 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.0.tgz", - "integrity": "sha512-4IwRUkxjrisR8LXBHeE4d2btraWdMficbgiVL3UHvJURmyvgzMBZQP8KrK8rjdXeu8SuRxSmeV6NSVomRvdbEg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.2.tgz", + "integrity": "sha512-SFLS+Rq8Cg2yepnHucA9sRpIR97yHvZWlCgMzBLunV3KHbB6hD2h5HPhFV39wYHYCjJUAOH1lX9poJ1qKYuSvg==", "dependencies": { "@docsearch/react": "^3.5.2", - "@docusaurus/core": "3.6.0", - "@docusaurus/logger": "3.6.0", - "@docusaurus/plugin-content-docs": "3.6.0", - "@docusaurus/theme-common": "3.6.0", - "@docusaurus/theme-translations": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-validation": "3.6.0", + "@docusaurus/core": "3.6.2", + "@docusaurus/logger": "3.6.2", + "@docusaurus/plugin-content-docs": "3.6.2", + "@docusaurus/theme-common": "3.6.2", + "@docusaurus/theme-translations": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-validation": "3.6.2", "algoliasearch": "^4.18.0", "algoliasearch-helper": "^3.13.3", "clsx": "^2.0.0", @@ -2665,9 +3721,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.6.0.tgz", - "integrity": "sha512-L555X8lWE3fv8VaF0Bc1VnAgi10UvRKFcvADHiYR7Gj37ItaWP5i7xLHsSw7fi/SHTXe5wfIeCFNqUYHyCOHAQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.6.2.tgz", + "integrity": "sha512-LIWrYoDUsOTKmb0c7IQzawiPUTAaczBs5IOx6srxOWoTHVUMLzJCkl5Y6whfuRrnul8G05qv2vk238bN5Ko62g==", "dependencies": { "fs-extra": "^11.1.1", "tslib": "^2.6.0" @@ -2677,15 +3733,15 @@ } }, "node_modules/@docusaurus/tsconfig": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.6.0.tgz", - "integrity": "sha512-1nHsSMlNgEifnvsL4ql9wx7I1xXhrrNZl65IKD11pdo/749oI9fMcvm47dDwgS57x1WEteIAxJjzidffa5J9TQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.6.2.tgz", + "integrity": "sha512-TWLkyYHBYhIJNcXCEc3D1M9R8UFV4IZ82rGef5U9mE1ZrcgDUlZxYaYdoSuHrPrzPRIl3orjmpscO2FAk2gdZw==", "dev": true }, "node_modules/@docusaurus/types": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.6.0.tgz", - "integrity": "sha512-jADLgoZGWhAzThr+mRiyuFD4OUzt6jHnb7NRArRKorgxckqUBaPyFOau9hhbcSTHtU6ceyeWjN7FDt7uG2Hplw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.6.2.tgz", + "integrity": "sha512-117Wsk6xXrWEAsCYCXS3TGJv5tkdIZDcd7T/V0UJvKYmY0gyVPPcEQChy8yTdjbIkbB2q4fa7Jpox72Qv86mqQ==", "dependencies": { "@mdx-js/mdx": "^3.0.0", "@types/history": "^4.7.11", @@ -2703,12 +3759,13 @@ } }, "node_modules/@docusaurus/utils": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.6.0.tgz", - "integrity": "sha512-VKczAutI4mptiAw/WcYEu5WeVhQ6Q1zdIUl64SGw9K++9lziH+Kt10Ee8l2dMpRkiUk6zzK20kMNlX2WCUwXYQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.6.2.tgz", + "integrity": "sha512-oxnpUcFZGE3uPCDoXr8GJriB3VWM9sFjPedFidX3Fsz87l1NZNc1wtbKPfQ7GYFDMYo2IGlAv5+47Me9RkM6lg==", "dependencies": { - "@docusaurus/logger": "3.6.0", - "@docusaurus/utils-common": "3.6.0", + "@docusaurus/logger": "3.6.2", + "@docusaurus/types": "3.6.2", + "@docusaurus/utils-common": "3.6.2", "@svgr/webpack": "^8.1.0", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", @@ -2730,43 +3787,28 @@ }, "engines": { "node": ">=18.0" - }, - "peerDependencies": { - "@docusaurus/types": "*" - }, - "peerDependenciesMeta": { - "@docusaurus/types": { - "optional": true - } } }, "node_modules/@docusaurus/utils-common": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.6.0.tgz", - "integrity": "sha512-diUDNfbw33GaZMmKwdTckT2IBfVouXLXRD+zphH9ywswuaEIKqixvuf5g41H7MBBrlMsxhna3uTMoB4B/OPDcA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.6.2.tgz", + "integrity": "sha512-dr5wK+OyU2QAWxG7S5siD2bPgS7+ZeqWHfgLNHZ5yalaZf8TbeNNLqydfngukAY56BGZN0NbMkX6jGIr7ZF0sA==", "dependencies": { + "@docusaurus/types": "3.6.2", "tslib": "^2.6.0" }, "engines": { "node": ">=18.0" - }, - "peerDependencies": { - "@docusaurus/types": "*" - }, - "peerDependenciesMeta": { - "@docusaurus/types": { - "optional": true - } } }, "node_modules/@docusaurus/utils-validation": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.6.0.tgz", - "integrity": "sha512-CRHiKKJEKA0GFlfOf71JWHl7PtwOyX0+Zg9ep9NFEZv6Lcx3RJ9nhl7p8HRjPL6deyYceavM//BsfW4pCI4BtA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.6.2.tgz", + "integrity": "sha512-Y3EwblDz72KOcobb5t2zlhHSmrfE8EaHusPJ96Kx2JYtNXL2omqCoOb6FpaXWhES75wvjUpkFLYfiNqAqEov8g==", "dependencies": { - "@docusaurus/logger": "3.6.0", - "@docusaurus/utils": "3.6.0", - "@docusaurus/utils-common": "3.6.0", + "@docusaurus/logger": "3.6.2", + "@docusaurus/utils": "3.6.2", + "@docusaurus/utils-common": "3.6.2", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", @@ -5175,6 +6217,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/css-declaration-sorter": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", @@ -5186,6 +6264,65 @@ "postcss": "^8.0.9" } }, + "node_modules/css-has-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.1.tgz", + "integrity": "sha512-EOcoyJt+OsuKfCADgLT7gADZI5jMzIe/AeI6MeAYKiFBDmNmM7kk46DtSfMj5AohUJisqVzopBpnQTlvbyaBWg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/css-in-js-utils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", @@ -5271,6 +6408,27 @@ } } }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -5317,6 +6475,21 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cssdb": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.1.tgz", + "integrity": "sha512-KwEPys7lNsC8OjASI8RrmwOYYDcm0JOW9zQhcV83ejYcQkirTEyeAGui8aO2F5PiS6SLpxuTzl6qlMElIdsgIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -12210,49 +13383,177 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.6.tgz", + "integrity": "sha512-wLXvm8RmLs14Z2nVpB4CWlnvaWPRcOZFltJSlcbYwSJ1EDZKsKDhPKIMecCnuU054KSmlmubkqczmm6qBPCBhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "github", + "url": "https://github.com/sponsors/csstools" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "opencollective", + "url": "https://opencollective.com/csstools" } ], "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.11", + "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": ">=18" }, "peerDependencies": { - "postcss": "^8.2.2" + "postcss": "^8.4" } }, "node_modules/postcss-colormin": { @@ -12287,6 +13588,136 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-custom-media": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz", + "integrity": "sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz", + "integrity": "sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz", + "integrity": "sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-discard-comments": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", @@ -12316,33 +13747,213 @@ "engines": { "node": "^14 || ^16 || >=18.0" }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", - "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", + "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": ">=18" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4" } }, - "node_modules/postcss-discard-unused": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", - "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "node_modules/postcss-lab-function": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.6.tgz", + "integrity": "sha512-HPwvsoK7C949vBZ+eMyvH2cQeMr3UREoHvbtra76/UhDuiViZH6pir+z71UaJQohd7VDSVUdR6TkWYKExEc9aQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.16" + "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": ">=18" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4" } }, "node_modules/postcss-loader": { @@ -12366,6 +13977,30 @@ "webpack": "^5.0.0" } }, + "node_modules/postcss-logical": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", + "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, "node_modules/postcss-merge-idents": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", @@ -12485,12 +14120,12 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", + "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -12500,12 +14135,24 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -12514,6 +14161,18 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-values": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", @@ -12528,6 +14187,86 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nesting": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", + "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", + "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-normalize-charset": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", @@ -12652,6 +14391,27 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, "node_modules/postcss-ordered-values": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", @@ -12667,6 +14427,184 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.1.tgz", + "integrity": "sha512-wqqsnBFD6VIwcHHRbhjTOcOi4qRVlB26RwSr0ordPj7OubRRxdWebv/aLjKLRR8zkZrbxZyuus03nOIgC5elMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-cascade-layers": "^5.0.1", + "@csstools/postcss-color-function": "^4.0.6", + "@csstools/postcss-color-mix-function": "^3.0.6", + "@csstools/postcss-content-alt-text": "^2.0.4", + "@csstools/postcss-exponential-functions": "^2.0.5", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.6", + "@csstools/postcss-gradients-interpolation-method": "^5.0.6", + "@csstools/postcss-hwb-function": "^4.0.6", + "@csstools/postcss-ic-unit": "^4.0.0", + "@csstools/postcss-initial": "^2.0.0", + "@csstools/postcss-is-pseudo-class": "^5.0.1", + "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.3", + "@csstools/postcss-media-minmax": "^2.0.5", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.0", + "@csstools/postcss-oklab-function": "^4.0.6", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-random-function": "^1.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.6", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.0", + "@csstools/postcss-stepped-value-functions": "^4.0.5", + "@csstools/postcss-text-decoration-shorthand": "^4.0.1", + "@csstools/postcss-trigonometric-functions": "^4.0.5", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.1", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.2.1", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.6", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.5", + "postcss-custom-properties": "^14.0.4", + "postcss-custom-selectors": "^8.0.4", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.0", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.6", + "postcss-logical": "^8.0.0", + "postcss-nesting": "^13.0.1", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-reduce-idents": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", @@ -12710,6 +14648,50 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -13066,9 +15048,9 @@ } }, "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", "engines": { "node": ">= 12.13.0" } @@ -13930,9 +15912,9 @@ } }, "node_modules/search-insights": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz", - "integrity": "sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g==", + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", "peer": true }, "node_modules/section-matter": { @@ -14500,9 +16482,9 @@ } }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==" }, "node_modules/string_decoder": { "version": "1.3.0", diff --git a/docs/package.json b/docs/package.json index 599c15b29df5..d20a9faf8ada 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,10 +15,10 @@ "typecheck": "tsc" }, "dependencies": { - "@docusaurus/core": "^3.6.0", - "@docusaurus/plugin-content-pages": "^3.6.0", - "@docusaurus/preset-classic": "^3.6.0", - "@docusaurus/theme-mermaid": "^3.6.0", + "@docusaurus/core": "^3.6.2", + "@docusaurus/plugin-content-pages": "^3.6.2", + "@docusaurus/preset-classic": "^3.6.2", + "@docusaurus/theme-mermaid": "^3.6.2", "@mdx-js/react": "^3.1.0", "clsx": "^2.0.0", "prism-react-renderer": "^2.4.0", @@ -29,7 +29,7 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.5.1", - "@docusaurus/tsconfig": "^3.6.0", + "@docusaurus/tsconfig": "^3.6.2", "@docusaurus/types": "^3.5.1", "typescript": "~5.6.3" }, diff --git a/docs/yarn.lock b/docs/yarn.lock index 0ec8d2f49906..a4f770f428bc 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -1208,6 +1208,328 @@ resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@csstools/cascade-layer-name-parser@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz#64d128529397aa1e1c986f685713363b262b81b1" + integrity sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA== + +"@csstools/color-helpers@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.1.tgz#829f1c76f5800b79c51c709e2f36821b728e0e10" + integrity sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA== + +"@csstools/css-calc@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.0.tgz#3f28b8f8f736b8f78abbc75eebd55c756207e773" + integrity sha512-X69PmFOrjTZfN5ijxtI8hZ9kRADFSLrmmQ6hgDJ272Il049WGKpDY64KhrFm/7rbWve0z81QepawzjkKlqkNGw== + +"@csstools/css-color-parser@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.6.tgz#e646838f6aab4618aeea7ba0c4921a254e180276" + integrity sha512-S/IjXqTHdpI4EtzGoNCHfqraXF37x12ZZHA1Lk7zoT5pm2lMjFuqhX/89L7dqX4CcMacKK+6ZCs5TmEGb/+wKw== + dependencies: + "@csstools/color-helpers" "^5.0.1" + "@csstools/css-calc" "^2.1.0" + +"@csstools/css-parser-algorithms@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" + integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== + +"@csstools/css-tokenizer@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2" + integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== + +"@csstools/media-query-list-parser@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz#e80e17eba1693fceafb8d6f2cfc68c0e7a9ab78a" + integrity sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A== + +"@csstools/postcss-cascade-layers@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz#9640313e64b5e39133de7e38a5aa7f40dc259597" + integrity sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ== + dependencies: + "@csstools/selector-specificity" "^5.0.0" + postcss-selector-parser "^7.0.0" + +"@csstools/postcss-color-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-4.0.6.tgz#dabd1e516ccd4c7bd5803e37075a503b5f7f0ac4" + integrity sha512-EcvXfC60cTIumzpsxWuvVjb7rsJEHPvqn3jeMEBUaE3JSc4FRuP7mEQ+1eicxWmIrs3FtzMH9gR3sgA5TH+ebQ== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-color-mix-function@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.6.tgz#d971832ec30b3b60363bceddfeb4b90c7cc0f4b8" + integrity sha512-jVKdJn4+JkASYGhyPO+Wa5WXSx1+oUgaXb3JsjJn/BlrtFh5zjocCY7pwWi0nuP24V1fY7glQsxEYcYNy0dMFg== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-content-alt-text@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz#76f4687fb15ed45bc1139bb71e5775779762897a" + integrity sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw== + dependencies: + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-exponential-functions@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.5.tgz#0c39f75df3357ee1e444b0aa0ede4e12aafea0e9" + integrity sha512-mi8R6dVfA2nDoKM3wcEi64I8vOYEgQVtVKCfmLHXupeLpACfGAided5ddMt5f+CnEodNu4DifuVwb0I6fQDGGQ== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-font-format-keywords@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz#6730836eb0153ff4f3840416cc2322f129c086e6" + integrity sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw== + dependencies: + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-gamut-mapping@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.6.tgz#04ec6a50fdbca2a30dec56e6bb780c79621e47a7" + integrity sha512-0ke7fmXfc8H+kysZz246yjirAH6JFhyX9GTlyRnM0exHO80XcA9zeJpy5pOp5zo/AZiC/q5Pf+Hw7Pd6/uAoYA== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-gradients-interpolation-method@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.6.tgz#67fa61ada95e4534687fa76cd2d15ac74386560e" + integrity sha512-Itrbx6SLUzsZ6Mz3VuOlxhbfuyLTogG5DwEF1V8dAi24iMuvQPIHd7Ti+pNDp7j6WixndJGZaoNR0f9VSzwuTg== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-hwb-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.6.tgz#c40f557a54ed45e75c601a9ba7a08d315f64dbd7" + integrity sha512-927Pqy3a1uBP7U8sTfaNdZVB0mNXzIrJO/GZ8us9219q9n06gOqCdfZ0E6d1P66Fm0fYHvxfDbfcUuwAn5UwhQ== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-ic-unit@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz#b60ec06500717c337447c39ae7fe7952eeb9d48f" + integrity sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-initial@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz#a86f5fc59ab9f16f1422dade4c58bd941af5df22" + integrity sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA== + +"@csstools/postcss-is-pseudo-class@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz#12041448fedf01090dd4626022c28b7f7623f58e" + integrity sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ== + dependencies: + "@csstools/selector-specificity" "^5.0.0" + postcss-selector-parser "^7.0.0" + +"@csstools/postcss-light-dark-function@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz#807c170cd28eebb0c00e64dfc6ab0bf418f19209" + integrity sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw== + dependencies: + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-logical-float-and-clear@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz#62617564182cf86ab5d4e7485433ad91e4c58571" + integrity sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ== + +"@csstools/postcss-logical-overflow@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz#c6de7c5f04e3d4233731a847f6c62819bcbcfa1d" + integrity sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA== + +"@csstools/postcss-logical-overscroll-behavior@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz#43c03eaecdf34055ef53bfab691db6dc97a53d37" + integrity sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w== + +"@csstools/postcss-logical-resize@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz#4df0eeb1a61d7bd85395e56a5cce350b5dbfdca6" + integrity sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-logical-viewport-units@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz#f6cc63520ca2a6eb76b9cd946070c38dda66d733" + integrity sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw== + dependencies: + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-media-minmax@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.5.tgz#66970aa8d8057f84b88aff21f385194fbe03eb11" + integrity sha512-sdh5i5GToZOIAiwhdntRWv77QDtsxP2r2gXW/WbLSCoLr00KTq/yiF1qlQ5XX2+lmiFa8rATKMcbwl3oXDMNew== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" + +"@csstools/postcss-media-queries-aspect-ratio-number-values@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz#d71102172c74baf3f892fac88cf1ea46a961600d" + integrity sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ== + dependencies: + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" + +"@csstools/postcss-nested-calc@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz#754e10edc6958d664c11cde917f44ba144141c62" + integrity sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A== + dependencies: + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-normalize-display-values@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz#ecdde2daf4e192e5da0c6fd933b6d8aff32f2a36" + integrity sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-oklab-function@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.6.tgz#17e8dfb6422dfd8d77256def5d5be8335ea7af34" + integrity sha512-Hptoa0uX+XsNacFBCIQKTUBrFKDiplHan42X73EklG6XmQLG7/aIvxoNhvZ7PvOWMt67Pw3bIlUY2nD6p5vL8A== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-progressive-custom-properties@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz#ecdb85bcdb1852d73970a214a376684a91f82bdc" + integrity sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-random-function@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-random-function/-/postcss-random-function-1.0.1.tgz#73a0b62b5dbbc03c25a28f085235eb61b09a2fb0" + integrity sha512-Ab/tF8/RXktQlFwVhiC70UNfpFQRhtE5fQQoP2pO+KCPGLsLdWFiOuHgSRtBOqEshCVAzR4H6o38nhvRZq8deA== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-relative-color-syntax@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.6.tgz#4b8bc219b34b16f5abdbbcf09ac13e65bff6ef16" + integrity sha512-yxP618Xb+ji1I624jILaYM62uEmZcmbdmFoZHoaThw896sq0vU39kqTTF+ZNic9XyPtPMvq0vyvbgmHaszq8xg== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +"@csstools/postcss-scope-pseudo-class@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz#9fe60e9d6d91d58fb5fc6c768a40f6e47e89a235" + integrity sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q== + dependencies: + postcss-selector-parser "^7.0.0" + +"@csstools/postcss-sign-functions@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.0.tgz#a524fae1374b0e167729f612ca875d7b1b334262" + integrity sha512-SLcc20Nujx/kqbSwDmj6oaXgpy3UjFhBy1sfcqPgDkHfOIfUtUVH7OXO+j7BU4v/At5s61N5ZX6shvgPwluhsA== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-stepped-value-functions@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.5.tgz#4d68633d502fbe2b6ef3898e368e3540488a0d8a" + integrity sha512-G6SJ6hZJkhxo6UZojVlLo14MohH4J5J7z8CRBrxxUYy9JuZiIqUo5TBYyDGcE0PLdzpg63a7mHSJz3VD+gMwqw== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-text-decoration-shorthand@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz#251fab0939d50c6fd73bb2b830b2574188efa087" + integrity sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw== + dependencies: + "@csstools/color-helpers" "^5.0.1" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-trigonometric-functions@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.5.tgz#267b95a8bd45536e0360596b6da660a9eb6aac83" + integrity sha512-/YQThYkt5MLvAmVu7zxjhceCYlKrYddK6LEmK5I4ojlS6BmO9u2yO4+xjXzu2+NPYmHSTtP4NFSamBCMmJ1NJA== + dependencies: + "@csstools/css-calc" "^2.1.0" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + +"@csstools/postcss-unset-value@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz#7caa981a34196d06a737754864baf77d64de4bba" + integrity sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA== + +"@csstools/selector-resolve-nested@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz#704a9b637975680e025e069a4c58b3beb3e2752a" + integrity sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ== + +"@csstools/selector-specificity@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz#037817b574262134cabd68fc4ec1a454f168407b" + integrity sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw== + +"@csstools/utilities@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-2.0.0.tgz#f7ff0fee38c9ffb5646d47b6906e0bc8868bde60" + integrity sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ== + "@discoveryjs/json-ext@0.5.7": version "0.5.7" resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" @@ -1228,10 +1550,10 @@ "@docsearch/css" "3.6.1" algoliasearch "^4.19.1" -"@docusaurus/babel@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.6.0.tgz#735a003207925bd782dd08ffa5d8b3503c1f8d72" - integrity sha512-7CsoQFiadoq7AHSUIQNkI/lGfg9AQ2ZBzsf9BqfZGXkHwWDy6twuohEaG0PgQv1npSRSAB2dioVxhRSErnqKNA== +"@docusaurus/babel@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.6.2.tgz#c63dd2d9d7861189fe51950b3b6550477057bcee" + integrity sha512-v8N8TWGXDsb5sxQC3Rcqb1CZr0LlU1OgqqVBUchN6cpIUr7EJuVJs5eHcIu5Ag8mwO/hWN3f7FE9uaHTMapAbg== dependencies: "@babel/core" "^7.25.9" "@babel/generator" "^7.25.9" @@ -1243,24 +1565,23 @@ "@babel/runtime" "^7.25.9" "@babel/runtime-corejs3" "^7.25.9" "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" + "@docusaurus/logger" "3.6.2" + "@docusaurus/utils" "3.6.2" babel-plugin-dynamic-import-node "^2.3.3" fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/bundler@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.6.0.tgz#bdd060ba4d009211348e4e973a3bf4861cf0996b" - integrity sha512-o5T9HXkPKH0OQAifTxEXaebcO8kaz3tU1+wlIShZ2DKJHlsyWX3N4rToWBHroWnV/ZCT2XN3kLRzXASqrnb9Tw== +"@docusaurus/bundler@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.6.2.tgz#5bdd46862b40f1eea93f14714b858d07c2dd8c2f" + integrity sha512-YkEifEVs4lV931SrHBB4n6WqRowMw+aM/QPH3z8aU+5t1dWa+1p2OPqARS+tSbh3la9ns+L1zIfSbd8RHi2/PQ== dependencies: "@babel/core" "^7.25.9" - "@docusaurus/babel" "3.6.0" - "@docusaurus/cssnano-preset" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - autoprefixer "^10.4.14" + "@docusaurus/babel" "3.6.2" + "@docusaurus/cssnano-preset" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" babel-loader "^9.2.1" clean-css "^5.3.2" copy-webpack-plugin "^11.0.0" @@ -1273,6 +1594,7 @@ null-loader "^4.0.1" postcss "^8.4.26" postcss-loader "^7.3.3" + postcss-preset-env "^10.1.0" react-dev-utils "^12.0.1" terser-webpack-plugin "^5.3.9" tslib "^2.6.0" @@ -1280,18 +1602,18 @@ webpack "^5.95.0" webpackbar "^6.0.1" -"@docusaurus/core@3.6.0", "@docusaurus/core@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.0.tgz#b23fc7e253a49cc3e5ac9e091354f497cc0b101b" - integrity sha512-lvRgMoKJJSRDt9+HhAqFcICV4kp/mw1cJJrLxIw4Q2XZnFGM1XUuwcbuaqWmGog+NcOLZaPCcCtZbn60EMCtjQ== - dependencies: - "@docusaurus/babel" "3.6.0" - "@docusaurus/bundler" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/core@3.6.2", "@docusaurus/core@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.2.tgz#78628790f255555bb4c81e5952d16ea1412c4548" + integrity sha512-irMts/mGLZv8dWcy0WUtbY/U6b5qIfHgQd1/kXMyAxUJo99fL0wFSqhMI+tcxjk0HYy427MXerLMqFJj+Arg1w== + dependencies: + "@docusaurus/babel" "3.6.2" + "@docusaurus/bundler" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" boxen "^6.2.1" chalk "^4.1.2" chokidar "^3.5.3" @@ -1329,32 +1651,32 @@ webpack-dev-server "^4.15.2" webpack-merge "^6.0.1" -"@docusaurus/cssnano-preset@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.0.tgz#02378e53e9568ed5fc8871d4fc158ea96fd7421c" - integrity sha512-h3jlOXqqzNSoU+C4CZLNpFtD+v2xr1UBf4idZpwMgqid9r6lb5GS7tWKnQnauio6OipacbHbDXEX3JyT1PlDkg== +"@docusaurus/cssnano-preset@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.2.tgz#007e7150b099ea2e9e874dd48a809614c628a335" + integrity sha512-mBkVa4QMHRwCFCVLYdBlOZuAT1iVVsS7GGSgliSVAeTOagP/AbtlBsCVrBs+keEuDuRF1w/6QEcqDoZe9fa5pw== dependencies: cssnano-preset-advanced "^6.1.2" postcss "^8.4.38" postcss-sort-media-queries "^5.2.0" tslib "^2.6.0" -"@docusaurus/logger@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.6.0.tgz#c7349c2636087f55f573a60a3c7f69b87d59974d" - integrity sha512-BcQhoXilXW0607cH/kO6P5Gt5KxCGfoJ+QDKNf3yO2S09/RsITlW+0QljXPbI3DklTrHrhRDmgGk1yX4nUhWTA== +"@docusaurus/logger@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.6.2.tgz#4f73f82b33e1d432f3940fc208b3c0646ca5549c" + integrity sha512-1p4IQhhgLyIfsey4UAdAIW69aUE1Ei6O91Nsw30ryZeDWSG5dh4o3zaRGOLxfAX69Ac/yDm6YCwJOafUxL6Vxg== dependencies: chalk "^4.1.2" tslib "^2.6.0" -"@docusaurus/mdx-loader@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.6.0.tgz#f8ba7af9d59473a7182f6a9307e0432f8dce905b" - integrity sha512-GhRzL1Af/AdSSrGesSPOU/iP/aXadTGmVKuysCxZDrQR2RtBtubQZ9aw+KvdFVV7R4K/CsbgD6J5oqrXlEPk3Q== +"@docusaurus/mdx-loader@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.6.2.tgz#d240974b0e754d5a5d8eb3f9d0a00a2055fabc68" + integrity sha512-7fbRmNgF3CR96Ja82Ya0/Cdu1OL9UJ/22llNMY8lr5gAbw718Y5ryXMVRIYn0JNLTiSxzgtvW4DIsUWEB8NMpw== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/logger" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" "@mdx-js/mdx" "^3.0.0" "@slorber/remark-comment" "^1.0.0" escape-html "^1.0.3" @@ -1377,12 +1699,12 @@ vfile "^6.0.1" webpack "^5.88.1" -"@docusaurus/module-type-aliases@3.6.0", "@docusaurus/module-type-aliases@^3.5.1": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.0.tgz#44083c34a53db1dde06364b4e7f2d144fa2d5394" - integrity sha512-szTrIN/6/fuk0xkf3XbRfdTFJzRQ8d1s3sQj5++58wltrT7v3yn1149oc9ryYjMpRcbsarGloQwMu7ofPe4XPg== +"@docusaurus/module-type-aliases@3.6.2", "@docusaurus/module-type-aliases@^3.5.1": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.2.tgz#7432618696668acc9a7cfb47de66c6987cd57680" + integrity sha512-NrJkL2rLTCjHtWOqUvWzwqvJrsKLj0gVJeV6q5yeKdKKgItietcTf2fTRkM9LHKSUN8CBDXxwHABeQvTahvmXQ== dependencies: - "@docusaurus/types" "3.6.0" + "@docusaurus/types" "3.6.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1390,19 +1712,19 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@6.0.0" -"@docusaurus/plugin-content-blog@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.0.tgz#9128175b4c3ce885d9090183d74c60813844ea8d" - integrity sha512-o4aT1/E0Ldpzs/hQff5uyoSriAhS/yqBhqSn+fvSw465AaqRsva6O7CZSYleuBq6x2bewyE3QJq2PcTiHhAd8g== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/plugin-content-blog@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.2.tgz#b197dd920e380bf1394995215ba7fee8019baa82" + integrity sha512-6bJxr6Or4NslEVH3BJuPH30kUWiqUjDRdGPhvxpHmt9W/RY2/6u72WICG3bW3dLFxJ/2uDLBU92lHnatpvo7Ew== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" cheerio "1.0.0-rc.12" feed "^4.2.2" fs-extra "^11.1.1" @@ -1414,20 +1736,20 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-docs@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.0.tgz#15cae4bf81da0b0ddce09d53b10b7209116ea9c2" - integrity sha512-c5gZOxocJKO/Zev2MEZInli+b+VNswDGuKHE6QtFgidhAJonwjh2kwj967RvWFaMMk62HlLJLZ+IGK2XsVy4Aw== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/plugin-content-docs@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.2.tgz#3a8b4b162a2688e5855c04ed6c4ec0b6951619a0" + integrity sha512-e6WW1g10RIXXLN/rrtqTi/FyJ1Hj3X9Mmgz4V11/0pDCxIGGI8m4ocbAglUlLtgvbLD5viNLefl/NwbOW3JXiQ== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/module-type-aliases" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" "@types/react-router-config" "^5.0.7" combine-promises "^1.1.0" fs-extra "^11.1.1" @@ -1437,115 +1759,115 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-pages@3.6.0", "@docusaurus/plugin-content-pages@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.0.tgz#5dd284bf063baaba1e0305c90b1dd0d5acc7e466" - integrity sha512-RKHhJrfkadHc7+tt1cP48NWifOrhkSRMPdXNYytzhoQrXlP6Ph+3tfQ4/n+nT0S3Y9+wwRxYqRqA380ZLt+QtQ== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/plugin-content-pages@3.6.2", "@docusaurus/plugin-content-pages@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.2.tgz#49b1a033d41841f7a8bcbbe67511609b402cc80f" + integrity sha512-fo4NyGkw10lYHyHaTxE6TZLYnxNtCfRHeZkNK1N9pBYqe7TT2dBUNAEeVW2U3ed9m6YuB7JKSQsa++GGmcP+6g== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" fs-extra "^11.1.1" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/plugin-debug@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.6.0.tgz#0a6da9ba31a0acb176ae2762b4d6b96b1906c826" - integrity sha512-o8T1Rl94COLdSlKvjYLQpRJQRU8WWZ8EX1B0yV0dQLNN8reyH7MQW+6z1ig4sQFfH3pnjPWVGHfuEjcib5m7Eg== +"@docusaurus/plugin-debug@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.6.2.tgz#6983f64954fe69a51b65b2d9431bdf0b5ccf1884" + integrity sha512-T/eS3VvHElpeV5S8uwp7Si4ujEynmgFtJLvA2CSa5pzQuOF1EEghF9nekAIj0cWtDHsqNUDZNr8hK1brivFXSg== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" + "@docusaurus/core" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" fs-extra "^11.1.1" react-json-view-lite "^1.2.0" tslib "^2.6.0" -"@docusaurus/plugin-google-analytics@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.0.tgz#9e8245eef1bee95e44ef2af92ce3e844a8e93e64" - integrity sha512-kgRFbfpi6Hshj75YUztKyEMtI/kw0trPRwoTN4g+W1NK99R/vh8phTvhBTIMnDbetU79795LkwfG0rZ/ce6zWQ== +"@docusaurus/plugin-google-analytics@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.2.tgz#4266b4b2273998e87fa733d932d5b464c2a10b21" + integrity sha512-B7ihrr3wz8e4XqW+dIAtq844u3Z83u5CeiL1xrCqzFH+vDCjUZHTamS3zKXNcgi6YVVe6hUQXPG15ltaqQaVPQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" tslib "^2.6.0" -"@docusaurus/plugin-google-gtag@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.0.tgz#bed8381fe3ab357d56a565f657e38d8ea6272703" - integrity sha512-nqu4IfjaO4UX+dojHL2BxHRS+sKj31CIMWYo49huQ3wTET0Oc3u/WGTaKd3ShTPDhkgiRhTOSTPUwJWrU55nHg== +"@docusaurus/plugin-google-gtag@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.2.tgz#23f70f7a05e61cfb9d9d7ee18dbff3ef2b129f2c" + integrity sha512-V8ijI6qddAAkJ0vd8sjZ7S/apRTLJn9dAwvj/rSMd93witGdKINemL+9TyfLkhcXKTxyqRT8zKdu8ewjPXqKHg== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" "@types/gtag.js" "^0.0.12" tslib "^2.6.0" -"@docusaurus/plugin-google-tag-manager@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.0.tgz#326382de05888ea4317837be736eabd635adbc71" - integrity sha512-OU6c5xI0nOVbEc9eImGvvsgNWe4vGm97t/W3aLHjWsHyNk3uwFNBQMHRvBUwAi9k/K3kyC5E7DWnc67REhdLOw== +"@docusaurus/plugin-google-tag-manager@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.2.tgz#36ab95fcd5c1bf96fd18c0cf9b208bb428b81242" + integrity sha512-fnWQ5FdN9f8c8VTgjaQ98208Y+d/JjHhD506rWIIL9rt1cJOf29XElxvOeKpMJadfkgY5KLZSAiHkGt+4qgN4g== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" tslib "^2.6.0" -"@docusaurus/plugin-sitemap@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.0.tgz#c7c93f75f03391ca9071da48563fc4faa84966bc" - integrity sha512-YB5XMdf9FjLhgbHY/cDbYhVxsgcpPIjxY9769HUgFOB7GVzItTLOR71W035R1BiR2CA5QAn3XOSg36WLRxlhQQ== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/plugin-sitemap@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.2.tgz#c8ff7cf82bd5d943a13bb8d0ae690080a025029e" + integrity sha512-qcAQAP1Ot0dZpeRoJ0L/Zck5FVDkll2IleVZQLzxeRVDZIw1P9/TK7/Aw1w2pmH7dmw/Cwk/cLSVRvLAmp9k7A== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" fs-extra "^11.1.1" sitemap "^7.1.1" tslib "^2.6.0" -"@docusaurus/preset-classic@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.6.0.tgz#71561f366a266be571022764eb8b9e5618f573eb" - integrity sha512-kpGNdQzr/Dpm7o3b1iaQrz4DMDx3WIeBbl4V4P4maa2zAQkTdlaP4CMgA5oKrRrpqPLnQFsUM/b+qf2glhl2Tw== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/plugin-content-blog" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/plugin-content-pages" "3.6.0" - "@docusaurus/plugin-debug" "3.6.0" - "@docusaurus/plugin-google-analytics" "3.6.0" - "@docusaurus/plugin-google-gtag" "3.6.0" - "@docusaurus/plugin-google-tag-manager" "3.6.0" - "@docusaurus/plugin-sitemap" "3.6.0" - "@docusaurus/theme-classic" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-search-algolia" "3.6.0" - "@docusaurus/types" "3.6.0" - -"@docusaurus/theme-classic@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.6.0.tgz#8f34b65c85f5082deb3633a893974d2eee309121" - integrity sha512-sAXNfwPL6uRD+BuHuKXZfAXud7SS7IK/JdrPuzyQxdO1gJKzI5GFfe1ED1QoJDNWJWJ01JHE5rSnwYLEADc2rQ== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/plugin-content-blog" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/plugin-content-pages" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/preset-classic@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.6.2.tgz#5ec801fa317123ba8458af3105eca8eac78a49bc" + integrity sha512-r2n5eHdhiNSrJGsrrYcw+WsyStmXxe0ZG3RdA9LVyK5+jBHM8blrUWJEDugnzCNbyhUzhdtcmgCC9fhdAvKuQw== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/plugin-content-blog" "3.6.2" + "@docusaurus/plugin-content-docs" "3.6.2" + "@docusaurus/plugin-content-pages" "3.6.2" + "@docusaurus/plugin-debug" "3.6.2" + "@docusaurus/plugin-google-analytics" "3.6.2" + "@docusaurus/plugin-google-gtag" "3.6.2" + "@docusaurus/plugin-google-tag-manager" "3.6.2" + "@docusaurus/plugin-sitemap" "3.6.2" + "@docusaurus/theme-classic" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/theme-search-algolia" "3.6.2" + "@docusaurus/types" "3.6.2" + +"@docusaurus/theme-classic@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.6.2.tgz#4c2770d3609176dd2462dfb0cb4d0b3d3010404b" + integrity sha512-bCdOPqPNezhLx+hgNVO2Cf+8/1AHa9uHDOqTx/CKAx2I0J/jV9G+6JiMtpSRKGNfBoLT1O+56/7+WtkOf54xTw== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/module-type-aliases" "3.6.2" + "@docusaurus/plugin-content-blog" "3.6.2" + "@docusaurus/plugin-content-docs" "3.6.2" + "@docusaurus/plugin-content-pages" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/theme-translations" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" "@mdx-js/react" "^3.0.0" clsx "^2.0.0" copy-text-to-clipboard "^3.2.0" @@ -1560,15 +1882,15 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-common@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.6.0.tgz#9a061d278df76da0f70a9465cd0b7299c14d03d3" - integrity sha512-frjlYE5sRs+GuPs4XXlp9aMLI2O4H5FPpznDAXBrCm+8EpWRiIb443ePMxM3IyMCQ5bwFlki0PI9C+r4apstnw== +"@docusaurus/theme-common@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.6.2.tgz#a520d9053b6ea0fa913d42898d35f73ed5ca3b9b" + integrity sha512-lfgsL064KEHpCkgGUc0OYoUPCpYfzggp6Hof8sz59UuKiLvb/Z7raewE9/NfocrJ2HZI17rLgMX3SQlRDh/5gg== dependencies: - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/mdx-loader" "3.6.2" + "@docusaurus/module-type-aliases" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1578,32 +1900,32 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-mermaid@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.0.tgz#0a79b76950aee8e2856a3e39f1c1050eb237c1c9" - integrity sha512-5t7zzBnnJa4BBcGo9bEfTM48DxD/+CVbFkfiRnFXheWjMrMm5a+IP10igEQ4zyDC+QgatbzLAxkj4GRYpYTauA== - dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" +"@docusaurus/theme-mermaid@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.2.tgz#f7ad64ae5b9510ddbf77bc4264ada059c8e815b1" + integrity sha512-Ui+rBtqMPKj3RCOxNlY04i1tEjNg+fZg4URTvkHmYR07hcKaJw+vkw+wlaYjd0HFZk+3Er9vUAcwsCWuea4cVQ== + dependencies: + "@docusaurus/core" "3.6.2" + "@docusaurus/module-type-aliases" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" mermaid ">=10.4" tslib "^2.6.0" -"@docusaurus/theme-search-algolia@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.0.tgz#47dcfca68f50163abce411dd9b181855a9ec9c83" - integrity sha512-4IwRUkxjrisR8LXBHeE4d2btraWdMficbgiVL3UHvJURmyvgzMBZQP8KrK8rjdXeu8SuRxSmeV6NSVomRvdbEg== +"@docusaurus/theme-search-algolia@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.2.tgz#b03b7d35a385004d089d000be764abdfb3fa5721" + integrity sha512-SFLS+Rq8Cg2yepnHucA9sRpIR97yHvZWlCgMzBLunV3KHbB6hD2h5HPhFV39wYHYCjJUAOH1lX9poJ1qKYuSvg== dependencies: "@docsearch/react" "^3.5.2" - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.2" + "@docusaurus/logger" "3.6.2" + "@docusaurus/plugin-content-docs" "3.6.2" + "@docusaurus/theme-common" "3.6.2" + "@docusaurus/theme-translations" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-validation" "3.6.2" algoliasearch "^4.18.0" algoliasearch-helper "^3.13.3" clsx "^2.0.0" @@ -1613,23 +1935,23 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-translations@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.6.0.tgz#93994e931f340c1712c81ac80dbab5750c24634f" - integrity sha512-L555X8lWE3fv8VaF0Bc1VnAgi10UvRKFcvADHiYR7Gj37ItaWP5i7xLHsSw7fi/SHTXe5wfIeCFNqUYHyCOHAQ== +"@docusaurus/theme-translations@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.6.2.tgz#ff6d2588aa9bf9fb1e07465def067529d5668665" + integrity sha512-LIWrYoDUsOTKmb0c7IQzawiPUTAaczBs5IOx6srxOWoTHVUMLzJCkl5Y6whfuRrnul8G05qv2vk238bN5Ko62g== dependencies: fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/tsconfig@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/tsconfig/-/tsconfig-3.6.0.tgz#4be9d0469e5f3683cd6e2d33bc8e963d9878f751" - integrity sha512-1nHsSMlNgEifnvsL4ql9wx7I1xXhrrNZl65IKD11pdo/749oI9fMcvm47dDwgS57x1WEteIAxJjzidffa5J9TQ== +"@docusaurus/tsconfig@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/tsconfig/-/tsconfig-3.6.2.tgz#a6d3fec19ae45a67da678b54c019b0e3839b6711" + integrity sha512-TWLkyYHBYhIJNcXCEc3D1M9R8UFV4IZ82rGef5U9mE1ZrcgDUlZxYaYdoSuHrPrzPRIl3orjmpscO2FAk2gdZw== -"@docusaurus/types@3.6.0", "@docusaurus/types@^3.5.1": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.6.0.tgz#8fa82332a7c7b8093b5c55e1115f5854ce484978" - integrity sha512-jADLgoZGWhAzThr+mRiyuFD4OUzt6jHnb7NRArRKorgxckqUBaPyFOau9hhbcSTHtU6ceyeWjN7FDt7uG2Hplw== +"@docusaurus/types@3.6.2", "@docusaurus/types@^3.5.1": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.6.2.tgz#bd69c4c99b535b67f01276dc186622e0b1fc1305" + integrity sha512-117Wsk6xXrWEAsCYCXS3TGJv5tkdIZDcd7T/V0UJvKYmY0gyVPPcEQChy8yTdjbIkbB2q4fa7Jpox72Qv86mqQ== dependencies: "@mdx-js/mdx" "^3.0.0" "@types/history" "^4.7.11" @@ -1641,34 +1963,36 @@ webpack "^5.95.0" webpack-merge "^5.9.0" -"@docusaurus/utils-common@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.6.0.tgz#11855ea503132bbcaba6ca4d351293ff10a75d34" - integrity sha512-diUDNfbw33GaZMmKwdTckT2IBfVouXLXRD+zphH9ywswuaEIKqixvuf5g41H7MBBrlMsxhna3uTMoB4B/OPDcA== +"@docusaurus/utils-common@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.6.2.tgz#3367572d72090b7f17e721af7f020f8e39931662" + integrity sha512-dr5wK+OyU2QAWxG7S5siD2bPgS7+ZeqWHfgLNHZ5yalaZf8TbeNNLqydfngukAY56BGZN0NbMkX6jGIr7ZF0sA== dependencies: + "@docusaurus/types" "3.6.2" tslib "^2.6.0" -"@docusaurus/utils-validation@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.6.0.tgz#5557ca14fa64ac29e6f70e61006be721395ecde5" - integrity sha512-CRHiKKJEKA0GFlfOf71JWHl7PtwOyX0+Zg9ep9NFEZv6Lcx3RJ9nhl7p8HRjPL6deyYceavM//BsfW4pCI4BtA== +"@docusaurus/utils-validation@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.6.2.tgz#62b97a0d72694c85fa63928c494dd238a84c991f" + integrity sha512-Y3EwblDz72KOcobb5t2zlhHSmrfE8EaHusPJ96Kx2JYtNXL2omqCoOb6FpaXWhES75wvjUpkFLYfiNqAqEov8g== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/logger" "3.6.2" + "@docusaurus/utils" "3.6.2" + "@docusaurus/utils-common" "3.6.2" fs-extra "^11.2.0" joi "^17.9.2" js-yaml "^4.1.0" lodash "^4.17.21" tslib "^2.6.0" -"@docusaurus/utils@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.6.0.tgz#192785da6fd62dfd83d6f1879c3aa45547f5df23" - integrity sha512-VKczAutI4mptiAw/WcYEu5WeVhQ6Q1zdIUl64SGw9K++9lziH+Kt10Ee8l2dMpRkiUk6zzK20kMNlX2WCUwXYQ== +"@docusaurus/utils@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.6.2.tgz#727299c2051eee04c1b431bc6ccd55fd4e5a0d52" + integrity sha512-oxnpUcFZGE3uPCDoXr8GJriB3VWM9sFjPedFidX3Fsz87l1NZNc1wtbKPfQ7GYFDMYo2IGlAv5+47Me9RkM6lg== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/logger" "3.6.2" + "@docusaurus/types" "3.6.2" + "@docusaurus/utils-common" "3.6.2" "@svgr/webpack" "^8.1.0" escape-string-regexp "^4.0.0" file-loader "^6.2.0" @@ -2937,7 +3261,7 @@ at-least-node@^1.0.0: resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -autoprefixer@^10.4.14, autoprefixer@^10.4.19: +autoprefixer@^10.4.19: version "10.4.20" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz" integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g== @@ -3097,7 +3421,7 @@ browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.22.2, browserslist@^4 node-releases "^2.0.18" update-browserslist-db "^1.1.0" -browserslist@^4.24.0, browserslist@^4.24.2: +browserslist@^4.23.1, browserslist@^4.24.0, browserslist@^4.24.2: version "4.24.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== @@ -3622,11 +3946,27 @@ crypto-random-string@^4.0.0: dependencies: type-fest "^1.0.1" +css-blank-pseudo@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz#32020bff20a209a53ad71b8675852b49e8d57e46" + integrity sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag== + dependencies: + postcss-selector-parser "^7.0.0" + css-declaration-sorter@^7.2.0: version "7.2.0" resolved "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz" integrity sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow== +css-has-pseudo@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-7.0.1.tgz#adbb51821e51f7a7c1d2df4d12827870cc311137" + integrity sha512-EOcoyJt+OsuKfCADgLT7gADZI5jMzIe/AeI6MeAYKiFBDmNmM7kk46DtSfMj5AohUJisqVzopBpnQTlvbyaBWg== + dependencies: + "@csstools/selector-specificity" "^5.0.0" + postcss-selector-parser "^7.0.0" + postcss-value-parser "^4.2.0" + css-in-js-utils@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz" @@ -3660,6 +4000,11 @@ css-minimizer-webpack-plugin@^5.0.1: schema-utils "^4.0.1" serialize-javascript "^6.0.1" +css-prefers-color-scheme@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz#ba001b99b8105b8896ca26fc38309ddb2278bd3c" + integrity sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ== + css-select@^4.1.3: version "4.3.0" resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" @@ -3711,6 +4056,11 @@ css-what@^6.0.1, css-what@^6.1.0: resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== +cssdb@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-8.2.1.tgz#62a5d9a41e2c86f1d7c35981098fc5ce47c5766c" + integrity sha512-KwEPys7lNsC8OjASI8RrmwOYYDcm0JOW9zQhcV83ejYcQkirTEyeAGui8aO2F5PiS6SLpxuTzl6qlMElIdsgIg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" @@ -7336,6 +7686,13 @@ points-on-path@^0.2.1: path-data-parser "0.1.0" points-on-curve "0.2.0" +postcss-attribute-case-insensitive@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz#0c4500e3bcb2141848e89382c05b5a31c23033a3" + integrity sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw== + dependencies: + postcss-selector-parser "^7.0.0" + postcss-calc@^9.0.1: version "9.0.1" resolved "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz" @@ -7344,6 +7701,40 @@ postcss-calc@^9.0.1: postcss-selector-parser "^6.0.11" postcss-value-parser "^4.2.0" +postcss-clamp@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.1.0.tgz#7263e95abadd8c2ba1bd911b0b5a5c9c93e02363" + integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-functional-notation@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.6.tgz#d74c1e2294b72287eb9af079c04b7ddeff7ec5b3" + integrity sha512-wLXvm8RmLs14Z2nVpB4CWlnvaWPRcOZFltJSlcbYwSJ1EDZKsKDhPKIMecCnuU054KSmlmubkqczmm6qBPCBhA== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + +postcss-color-hex-alpha@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz#5dd3eba1f8facb4ea306cba6e3f7712e876b0c76" + integrity sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w== + dependencies: + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-color-rebeccapurple@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz#5ada28406ac47e0796dff4056b0a9d5a6ecead98" + integrity sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ== + dependencies: + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + postcss-colormin@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz" @@ -7362,6 +7753,44 @@ postcss-convert-values@^6.1.0: browserslist "^4.23.0" postcss-value-parser "^4.2.0" +postcss-custom-media@^11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz#2fcd88a9b1d4da41c67dac6f2def903063a3377d" + integrity sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ== + dependencies: + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/media-query-list-parser" "^4.0.2" + +postcss-custom-properties@^14.0.4: + version "14.0.4" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz#de9c663285a98833a946d7003a34369d3ce373a9" + integrity sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A== + dependencies: + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-custom-selectors@^8.0.4: + version "8.0.4" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz#95ef8268fdbbbd84f34cf84a4517c9d99d419c5a" + integrity sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg== + dependencies: + "@csstools/cascade-layer-name-parser" "^2.0.4" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + postcss-selector-parser "^7.0.0" + +postcss-dir-pseudo-class@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz#80d9e842c9ae9d29f6bf5fd3cf9972891d6cc0ca" + integrity sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA== + dependencies: + postcss-selector-parser "^7.0.0" + postcss-discard-comments@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz" @@ -7389,6 +7818,58 @@ postcss-discard-unused@^6.0.5: dependencies: postcss-selector-parser "^6.0.16" +postcss-double-position-gradients@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz#eddd424ec754bb543d057d4d2180b1848095d4d2" + integrity sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-focus-visible@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz#1f7904904368a2d1180b220595d77b6f8a957868" + integrity sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA== + dependencies: + postcss-selector-parser "^7.0.0" + +postcss-focus-within@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz#ac01ce80d3f2e8b2b3eac4ff84f8e15cd0057bc7" + integrity sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw== + dependencies: + postcss-selector-parser "^7.0.0" + +postcss-font-variant@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66" + integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== + +postcss-gap-properties@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz#d5ff0bdf923c06686499ed2b12e125fe64054fed" + integrity sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw== + +postcss-image-set-function@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz#538e94e16716be47f9df0573b56bbaca86e1da53" + integrity sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA== + dependencies: + "@csstools/utilities" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-lab-function@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-7.0.6.tgz#3121800fc7939ed1d9a1e87abeb33c407151252c" + integrity sha512-HPwvsoK7C949vBZ+eMyvH2cQeMr3UREoHvbtra76/UhDuiViZH6pir+z71UaJQohd7VDSVUdR6TkWYKExEc9aQ== + dependencies: + "@csstools/css-color-parser" "^3.0.6" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/utilities" "^2.0.0" + postcss-loader@^7.3.3: version "7.3.4" resolved "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz" @@ -7398,6 +7879,13 @@ postcss-loader@^7.3.3: jiti "^1.20.0" semver "^7.5.4" +postcss-logical@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-8.0.0.tgz#0db0b90c2dc53b485a8074a4b7a906297544f58d" + integrity sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg== + dependencies: + postcss-value-parser "^4.2.0" + postcss-merge-idents@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz" @@ -7484,6 +7972,15 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" +postcss-nesting@^13.0.1: + version "13.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-13.0.1.tgz#c405796d7245a3e4c267a9956cacfe9670b5d43e" + integrity sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ== + dependencies: + "@csstools/selector-resolve-nested" "^3.0.0" + "@csstools/selector-specificity" "^5.0.0" + postcss-selector-parser "^7.0.0" + postcss-normalize-charset@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz" @@ -7546,6 +8043,11 @@ postcss-normalize-whitespace@^6.0.2: dependencies: postcss-value-parser "^4.2.0" +postcss-opacity-percentage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz#0b0db5ed5db5670e067044b8030b89c216e1eb0a" + integrity sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ== + postcss-ordered-values@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz" @@ -7554,6 +8056,101 @@ postcss-ordered-values@^6.0.2: cssnano-utils "^4.0.2" postcss-value-parser "^4.2.0" +postcss-overflow-shorthand@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz#f5252b4a2ee16c68cd8a9029edb5370c4a9808af" + integrity sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-page-break@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f" + integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== + +postcss-place@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-10.0.0.tgz#ba36ee4786ca401377ced17a39d9050ed772e5a9" + integrity sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-preset-env@^10.1.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-10.1.1.tgz#6ee631272353fb1c4a9711943e9b80a178ffce44" + integrity sha512-wqqsnBFD6VIwcHHRbhjTOcOi4qRVlB26RwSr0ordPj7OubRRxdWebv/aLjKLRR8zkZrbxZyuus03nOIgC5elMQ== + dependencies: + "@csstools/postcss-cascade-layers" "^5.0.1" + "@csstools/postcss-color-function" "^4.0.6" + "@csstools/postcss-color-mix-function" "^3.0.6" + "@csstools/postcss-content-alt-text" "^2.0.4" + "@csstools/postcss-exponential-functions" "^2.0.5" + "@csstools/postcss-font-format-keywords" "^4.0.0" + "@csstools/postcss-gamut-mapping" "^2.0.6" + "@csstools/postcss-gradients-interpolation-method" "^5.0.6" + "@csstools/postcss-hwb-function" "^4.0.6" + "@csstools/postcss-ic-unit" "^4.0.0" + "@csstools/postcss-initial" "^2.0.0" + "@csstools/postcss-is-pseudo-class" "^5.0.1" + "@csstools/postcss-light-dark-function" "^2.0.7" + "@csstools/postcss-logical-float-and-clear" "^3.0.0" + "@csstools/postcss-logical-overflow" "^2.0.0" + "@csstools/postcss-logical-overscroll-behavior" "^2.0.0" + "@csstools/postcss-logical-resize" "^3.0.0" + "@csstools/postcss-logical-viewport-units" "^3.0.3" + "@csstools/postcss-media-minmax" "^2.0.5" + "@csstools/postcss-media-queries-aspect-ratio-number-values" "^3.0.4" + "@csstools/postcss-nested-calc" "^4.0.0" + "@csstools/postcss-normalize-display-values" "^4.0.0" + "@csstools/postcss-oklab-function" "^4.0.6" + "@csstools/postcss-progressive-custom-properties" "^4.0.0" + "@csstools/postcss-random-function" "^1.0.1" + "@csstools/postcss-relative-color-syntax" "^3.0.6" + "@csstools/postcss-scope-pseudo-class" "^4.0.1" + "@csstools/postcss-sign-functions" "^1.1.0" + "@csstools/postcss-stepped-value-functions" "^4.0.5" + "@csstools/postcss-text-decoration-shorthand" "^4.0.1" + "@csstools/postcss-trigonometric-functions" "^4.0.5" + "@csstools/postcss-unset-value" "^4.0.0" + autoprefixer "^10.4.19" + browserslist "^4.23.1" + css-blank-pseudo "^7.0.1" + css-has-pseudo "^7.0.1" + css-prefers-color-scheme "^10.0.0" + cssdb "^8.2.1" + postcss-attribute-case-insensitive "^7.0.1" + postcss-clamp "^4.1.0" + postcss-color-functional-notation "^7.0.6" + postcss-color-hex-alpha "^10.0.0" + postcss-color-rebeccapurple "^10.0.0" + postcss-custom-media "^11.0.5" + postcss-custom-properties "^14.0.4" + postcss-custom-selectors "^8.0.4" + postcss-dir-pseudo-class "^9.0.1" + postcss-double-position-gradients "^6.0.0" + postcss-focus-visible "^10.0.1" + postcss-focus-within "^9.0.1" + postcss-font-variant "^5.0.0" + postcss-gap-properties "^6.0.0" + postcss-image-set-function "^7.0.0" + postcss-lab-function "^7.0.6" + postcss-logical "^8.0.0" + postcss-nesting "^13.0.1" + postcss-opacity-percentage "^3.0.0" + postcss-overflow-shorthand "^6.0.0" + postcss-page-break "^3.0.4" + postcss-place "^10.0.0" + postcss-pseudo-class-any-link "^10.0.1" + postcss-replace-overflow-wrap "^4.0.0" + postcss-selector-not "^8.0.1" + +postcss-pseudo-class-any-link@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz#06455431171bf44b84d79ebaeee9fd1c05946544" + integrity sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q== + dependencies: + postcss-selector-parser "^7.0.0" + postcss-reduce-idents@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz" @@ -7576,6 +8173,18 @@ postcss-reduce-transforms@^6.0.2: dependencies: postcss-value-parser "^4.2.0" +postcss-replace-overflow-wrap@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" + integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== + +postcss-selector-not@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz#f2df9c6ac9f95e9fe4416ca41a957eda16130172" + integrity sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA== + dependencies: + postcss-selector-parser "^7.0.0" + postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.16, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: version "6.0.16" resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz" @@ -7584,6 +8193,14 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.16, postcss-select cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss-selector-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz#41bd8b56f177c093ca49435f65731befe25d6b9c" + integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-sort-media-queries@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz" From cde7ce49be4945940135b76a3e8cf4058c809f62 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Wed, 20 Nov 2024 10:42:02 -0500 Subject: [PATCH 22/34] fix up lockup when long actions are run (#5144) --- openhands/runtime/action_execution_server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openhands/runtime/action_execution_server.py b/openhands/runtime/action_execution_server.py index aeb0d4c7a407..1251aa346838 100644 --- a/openhands/runtime/action_execution_server.py +++ b/openhands/runtime/action_execution_server.py @@ -52,7 +52,7 @@ from openhands.runtime.utils.files import insert_lines, read_lines from openhands.runtime.utils.runtime_init import init_user_and_working_directory from openhands.runtime.utils.system import check_port_available -from openhands.utils.async_utils import wait_all +from openhands.utils.async_utils import call_sync_from_async, wait_all class ActionRequest(BaseModel): @@ -170,7 +170,8 @@ async def run_action(self, action) -> Observation: async def run( self, action: CmdRunAction ) -> CmdOutputObservation | ErrorObservation: - return self.bash_session.run(action) + obs = await call_sync_from_async(self.bash_session.run, action) + return obs async def run_ipython(self, action: IPythonRunCellAction) -> Observation: if 'jupyter' in self.plugins: From 5c836985241f2bce9fb3ad005fe83d4556e740d2 Mon Sep 17 00:00:00 2001 From: young010101 <93481273+young010101@users.noreply.github.com> Date: Thu, 21 Nov 2024 03:07:06 +0800 Subject: [PATCH 23/34] Docs/fix logging param name (#5146) --- openhands/core/config/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openhands/core/config/utils.py b/openhands/core/config/utils.py index 86794e8aac2f..f664dfcfd656 100644 --- a/openhands/core/config/utils.py +++ b/openhands/core/config/utils.py @@ -384,7 +384,7 @@ def load_app_config( """Load the configuration from the specified config file and environment variables. Args: - set_logger_levels: Whether to set the global variables for logging levels. + set_logging_levels: Whether to set the global variables for logging levels. config_file: Path to the config file. Defaults to 'config.toml' in the current directory. """ config = AppConfig() From 3a65b7b07d712a1ff9181b7a0830d4897fa78965 Mon Sep 17 00:00:00 2001 From: young010101 <93481273+young010101@users.noreply.github.com> Date: Thu, 21 Nov 2024 04:06:02 +0800 Subject: [PATCH 24/34] =?UTF-8?q?docs:=20add=20missing=20toml=5Ffile=20par?= =?UTF-8?q?ameter=20description=20in=20get=5Fllm=5Fconfig=5Fa=E2=80=A6=20(?= =?UTF-8?q?#5147)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openhands/core/config/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openhands/core/config/utils.py b/openhands/core/config/utils.py index f664dfcfd656..437754ef22ae 100644 --- a/openhands/core/config/utils.py +++ b/openhands/core/config/utils.py @@ -241,6 +241,7 @@ def get_llm_config_arg( Args: llm_config_arg: The group of llm settings to get from the config.toml file. + toml_file: Path to the configuration file to read from. Defaults to 'config.toml'. Returns: LLMConfig: The LLMConfig object with the settings from the config file. From 07b96cc8c9507f963c9e971fdf8cceecc960fd71 Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Wed, 20 Nov 2024 15:19:51 -0500 Subject: [PATCH 25/34] docs: Add documentation on how to add new tools to codeact_agent (#5150) Co-authored-by: openhands --- openhands/agenthub/codeact_agent/README.md | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/openhands/agenthub/codeact_agent/README.md b/openhands/agenthub/codeact_agent/README.md index 357a723b650c..45ccb42ba085 100644 --- a/openhands/agenthub/codeact_agent/README.md +++ b/openhands/agenthub/codeact_agent/README.md @@ -10,3 +10,57 @@ The conceptual idea is illustrated below. At each turn, the agent can: - Execute any valid `Python` code with [an interactive Python interpreter](https://ipython.org/). This is simulated through `bash` command, see plugin system below for more details. ![image](https://github.com/All-Hands-AI/OpenHands/assets/38853559/92b622e3-72ad-4a61-8f41-8c040b6d5fb3) + +## Adding New Tools + +The CodeAct agent uses a function calling interface to define tools that the agent can use. Tools are defined in `function_calling.py` using the `ChatCompletionToolParam` class from `litellm`. Each tool consists of: + +1. A description string that explains what the tool does and how to use it +2. A tool definition using `ChatCompletionToolParam` that specifies: + - The tool's name + - The tool's parameters and their types + - Required vs optional parameters + +Here's an example of how a tool is defined: + +```python +MyTool = ChatCompletionToolParam( + type='function', + function=ChatCompletionToolParamFunctionChunk( + name='my_tool', + description='Description of what the tool does and how to use it', + parameters={ + 'type': 'object', + 'properties': { + 'param1': { + 'type': 'string', + 'description': 'Description of parameter 1', + }, + 'param2': { + 'type': 'integer', + 'description': 'Description of parameter 2', + }, + }, + 'required': ['param1'], # List required parameters here + }, + ), +) +``` + +To add a new tool: + +1. Define your tool in `function_calling.py` following the pattern above +2. Add your tool to the `get_tools()` function in `function_calling.py` +3. Implement the corresponding action handler in the agent to process the tool's invocation + +The agent currently supports several built-in tools: +- `execute_bash`: Execute bash commands +- `execute_ipython_cell`: Run Python code in IPython +- `browser`: Interact with a web browser +- `str_replace_editor`: Edit files using string replacement +- `edit_file`: Edit files using LLM-based editing + +Tools can be enabled/disabled through configuration parameters: +- `codeact_enable_browsing`: Enable browser interaction +- `codeact_enable_jupyter`: Enable IPython code execution +- `codeact_enable_llm_editor`: Enable LLM-based file editing (if disabled, uses string replacement editor instead) From e211152f93bbbaefdb317ad5f11c2f01bbbf9a5e Mon Sep 17 00:00:00 2001 From: OpenHands Date: Wed, 20 Nov 2024 21:36:47 -0500 Subject: [PATCH 26/34] Fix issue #5159: [Bug]: lint-fix workflow terminates prematurely due to exit code 1 (#5160) --- .github/workflows/lint-fix.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint-fix.yml b/.github/workflows/lint-fix.yml index b877de6bb4d2..9fa97eaaf2f1 100644 --- a/.github/workflows/lint-fix.yml +++ b/.github/workflows/lint-fix.yml @@ -44,11 +44,8 @@ jobs: run: pip install pre-commit==3.7.0 - name: Fix python lint issues run: | - pre-commit run trailing-whitespace --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml - pre-commit run end-of-file-fixer --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml - pre-commit run pyproject-fmt --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml - pre-commit run ruff --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml - pre-commit run ruff-format --files openhands/**/* evaluation/**/* tests/**/* --config ./dev_config/python/.pre-commit-config.yaml + # Run all pre-commit hooks and continue even if they modify files (exit code 1) + pre-commit run --config ./dev_config/python/.pre-commit-config.yaml --files openhands/**/* evaluation/**/* tests/**/* || true # Commit and push changes if any - name: Check for changes From 27f136b8021b0fdd5a377d6f886c9c436748414c Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Wed, 20 Nov 2024 22:40:30 -0500 Subject: [PATCH 27/34] mitigate memory leak (#5152) --- openhands/server/session/session.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openhands/server/session/session.py b/openhands/server/session/session.py index c65ae73a30ab..c64e17020aa4 100644 --- a/openhands/server/session/session.py +++ b/openhands/server/session/session.py @@ -57,6 +57,9 @@ def close(self): self.websocket = None finally: self.agent_session.close() + del ( + self.agent_session + ) # FIXME: this should not be necessary but it mitigates a memory leak async def loop_recv(self): try: From 746722e1b518890e831bcd08d4b15bc51f11b075 Mon Sep 17 00:00:00 2001 From: young010101 <93481273+young010101@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:41:51 +0800 Subject: [PATCH 28/34] style: remove extra newline in LLM wrapper function (#5149) --- openhands/llm/llm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openhands/llm/llm.py b/openhands/llm/llm.py index 0590945995c1..6faf2c6605f4 100644 --- a/openhands/llm/llm.py +++ b/openhands/llm/llm.py @@ -164,7 +164,6 @@ def __init__( ) def wrapper(*args, **kwargs): """Wrapper for the litellm completion function. Logs the input and output of the completion function.""" - from openhands.core.utils import json messages: list[dict[str, Any]] | dict[str, Any] = [] From 94a8f58ece37fc8a5af4190e0841334b9efadbe5 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Wed, 20 Nov 2024 22:42:13 -0500 Subject: [PATCH 29/34] fix up logging in listen.py (#5145) --- openhands/server/listen.py | 64 ++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/openhands/server/listen.py b/openhands/server/listen.py index f5463a517306..c8b258b46ead 100644 --- a/openhands/server/listen.py +++ b/openhands/server/listen.py @@ -62,7 +62,7 @@ from openhands.events.serialization import event_to_dict from openhands.events.stream import AsyncEventStreamWrapper from openhands.llm import bedrock -from openhands.runtime.base import Runtime +from openhands.runtime.base import Runtime, RuntimeUnavailableError from openhands.server.auth.auth import get_sid_from_token, sign_token from openhands.server.middleware import ( InMemoryRateLimiter, @@ -517,7 +517,14 @@ async def list_files(request: Request, path: str | None = None): ) runtime: Runtime = request.state.conversation.runtime - file_list = await call_sync_from_async(runtime.list_files, path) + try: + file_list = await call_sync_from_async(runtime.list_files, path) + except RuntimeUnavailableError as e: + logger.error(f'Error listing files: {e}', exc_info=True) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={'error': f'Error listing files: {e}'}, + ) if path: file_list = [os.path.join(path, f) for f in file_list] @@ -537,7 +544,14 @@ async def filter_for_gitignore(file_list, base_path): file_list = [entry for entry in file_list if not spec.match_file(entry)] return file_list - file_list = await filter_for_gitignore(file_list, '') + try: + file_list = await filter_for_gitignore(file_list, '') + except RuntimeUnavailableError as e: + logger.error(f'Error filtering files: {e}', exc_info=True) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={'error': f'Error filtering files: {e}'}, + ) return file_list @@ -566,7 +580,14 @@ async def select_file(file: str, request: Request): file = os.path.join(runtime.config.workspace_mount_path_in_sandbox, file) read_action = FileReadAction(file) - observation = await call_sync_from_async(runtime.run_action, read_action) + try: + observation = await call_sync_from_async(runtime.run_action, read_action) + except RuntimeUnavailableError as e: + logger.error(f'Error opening file {file}: {e}', exc_info=True) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={'error': f'Error opening file: {e}'}, + ) if isinstance(observation, FileReadObservation): content = observation.content @@ -662,9 +683,20 @@ async def upload_file(request: Request, files: list[UploadFile]): tmp_file.flush() runtime: Runtime = request.state.conversation.runtime - runtime.copy_to( - tmp_file_path, runtime.config.workspace_mount_path_in_sandbox - ) + try: + await call_sync_from_async( + runtime.copy_to, + tmp_file_path, + runtime.config.workspace_mount_path_in_sandbox, + ) + except RuntimeUnavailableError as e: + logger.error( + f'Error saving file {safe_filename}: {e}', exc_info=True + ) + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={'error': f'Error saving file: {e}'}, + ) uploaded_files.append(safe_filename) response_content = { @@ -795,7 +827,14 @@ async def save_file(request: Request): runtime.config.workspace_mount_path_in_sandbox, file_path ) write_action = FileWriteAction(file_path, content) - observation = await call_sync_from_async(runtime.run_action, write_action) + try: + observation = await call_sync_from_async(runtime.run_action, write_action) + except RuntimeUnavailableError as e: + logger.error(f'Error saving file: {e}', exc_info=True) + return JSONResponse( + status_code=500, + content={'error': f'Error saving file: {e}'}, + ) if isinstance(observation, FileWriteObservation): return JSONResponse( @@ -846,7 +885,14 @@ async def zip_current_workspace(request: Request, background_tasks: BackgroundTa logger.debug('Zipping workspace') runtime: Runtime = request.state.conversation.runtime path = runtime.config.workspace_mount_path_in_sandbox - zip_file = await call_sync_from_async(runtime.copy_from, path) + try: + zip_file = await call_sync_from_async(runtime.copy_from, path) + except RuntimeUnavailableError as e: + logger.error(f'Error zipping workspace: {e}', exc_info=True) + return JSONResponse( + status_code=500, + content={'error': f'Error zipping workspace: {e}'}, + ) response = FileResponse( path=zip_file, filename='workspace.zip', From f4a2df859f6e1bfdfaccad202c1ff698a5f23e4d Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Wed, 20 Nov 2024 22:46:08 -0500 Subject: [PATCH 30/34] [Bug][Resolver] Enable caching for reusable workflow (#5165) --- .github/workflows/openhands-resolver.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/openhands-resolver.yml b/.github/workflows/openhands-resolver.yml index b517f4c46e27..a2b82232eaaf 100644 --- a/.github/workflows/openhands-resolver.yml +++ b/.github/workflows/openhands-resolver.yml @@ -80,11 +80,11 @@ jobs: github.event.label.name == 'fix-me-experimental' || ( (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') && - startsWith(github.event.comment.body, inputs.macro || '@openhands-agent-exp') + startsWith(github.event.comment.body, '@openhands-agent-exp') ) || ( github.event_name == 'pull_request_review' && - startsWith(github.event.review.body, inputs.macro || '@openhands-agent-exp') + startsWith(github.event.review.body, '@openhands-agent-exp') ) ) uses: actions/cache@v3 From ebce77ab5677ff209895bc09e636da415129a471 Mon Sep 17 00:00:00 2001 From: OpenHands Date: Wed, 20 Nov 2024 23:03:22 -0500 Subject: [PATCH 31/34] Fix issue #5155: [Resolver] Could we get a .md of tips for the .openhands_instructions file? (#5163) Co-authored-by: Graham Neubig --- docs/modules/usage/how-to/github-action.md | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/modules/usage/how-to/github-action.md b/docs/modules/usage/how-to/github-action.md index 3b55ab4952a7..4864736e3cac 100644 --- a/docs/modules/usage/how-to/github-action.md +++ b/docs/modules/usage/how-to/github-action.md @@ -43,3 +43,53 @@ To customize the default macro (`@openhands-agent`): 1. [Create a repository variable](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#creating-configuration-variables-for-a-repository) named `OPENHANDS_MACRO` 2. Assign the variable a custom value + +## Writing Effective .openhands_instructions Files + +The `.openhands_instructions` file is a file that you can put in the root directory of your repository to guide OpenHands in understanding and working with your repository effectively. Here are key tips for writing high-quality instructions: + +### Core Principles + +1. **Concise but Informative**: Provide a clear, focused overview of the repository that emphasizes the most common actions OpenHands will need to perform. + +2. **Repository Structure**: Explain the key directories and their purposes, especially highlighting where different types of code (e.g., frontend, backend) are located. + +3. **Development Workflows**: Document the essential commands for: + - Building and setting up the project + - Running tests + - Linting and code quality checks + - Any environment-specific requirements + +4. **Testing Guidelines**: Specify: + - Where tests are located + - How to run specific test suites + - Any testing conventions or requirements + +### Example Structure + +```markdown +# Repository Overview +[Brief description of the project] + +## General Setup +- Main build command +- Development environment setup +- Pre-commit checks + +## Backend +- Location and structure +- Testing instructions +- Environment requirements + +## Frontend +- Setup prerequisites +- Build and test commands +- Environment variables + +## Additional Guidelines +- Code style requirements +- Special considerations +- Common workflows +``` + +For a real-world example, refer to the [OpenHands repository's .openhands_instructions](https://github.com/All-Hands-AI/OpenHands/blob/main/.openhands_instructions). From 12ed523c014f1d54ec9b3b5057c524423f2d1a59 Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Wed, 20 Nov 2024 23:07:21 -0500 Subject: [PATCH 32/34] docs: Add note about organizational token policies (#5161) Co-authored-by: openhands --- openhands/resolver/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openhands/resolver/README.md b/openhands/resolver/README.md index d91699fe0c20..2042280ae940 100644 --- a/openhands/resolver/README.md +++ b/openhands/resolver/README.md @@ -15,6 +15,8 @@ Follow these steps to use this workflow in your own repository: 1. [Create a personal access token](https://github.com/settings/tokens?type=beta) with read/write scope for "contents", "issues", "pull requests", and "workflows" + Note: If you're working with an organizational repository, you may need to configure the organization's personal access token policy first. See [Setting a personal access token policy for your organization](https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization) for details. + 2. Create an API key for the [Claude API](https://www.anthropic.com/api) (recommended) or another supported LLM service 3. Copy `examples/openhands-resolver.yml` to your repository's `.github/workflows/` directory @@ -83,11 +85,14 @@ pip install openhands-ai 3. Set up environment variables: ```bash + # GitHub credentials + export GITHUB_TOKEN="your-github-token" export GITHUB_USERNAME="your-github-username" # Optional, defaults to token owner # LLM configuration + export LLM_MODEL="anthropic/claude-3-5-sonnet-20241022" # Recommended export LLM_API_KEY="your-llm-api-key" export LLM_BASE_URL="your-api-url" # Optional, for API proxies From 7e382977325684ee82a33a559e0ce40f5f572d48 Mon Sep 17 00:00:00 2001 From: Cheng Yang <93481273+young010101@users.noreply.github.com> Date: Thu, 21 Nov 2024 19:39:32 +0800 Subject: [PATCH 33/34] fix: correct relative links in agenthub README.md (#5170) --- openhands/agenthub/README.md | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/openhands/agenthub/README.md b/openhands/agenthub/README.md index 05de596f1ff4..4cb588bfec2a 100644 --- a/openhands/agenthub/README.md +++ b/openhands/agenthub/README.md @@ -7,10 +7,10 @@ Contributors from different backgrounds and interests can choose to contribute t ## Constructing an Agent -The abstraction for an agent can be found [here](../openhands/controller/agent.py). +The abstraction for an agent can be found [here](../controller/agent.py). Agents are run inside of a loop. At each iteration, `agent.step()` is called with a -[State](../openhands/controller/state/state.py) input, and the agent must output an [Action](../openhands/events/action). +[State](../controller/state/state.py) input, and the agent must output an [Action](../events/action). Every agent also has a `self.llm` which it can use to interact with the LLM configured by the user. See the [LiteLLM docs for `self.llm.completion`](https://docs.litellm.ai/docs/completion). @@ -46,17 +46,17 @@ The agent can add and modify subtasks through the `AddTaskAction` and `ModifyTas Here is a list of available Actions, which can be returned by `agent.step()`: -- [`CmdRunAction`](../openhands/events/action/commands.py) - Runs a command inside a sandboxed terminal -- [`IPythonRunCellAction`](../openhands/events/action/commands.py) - Execute a block of Python code interactively (in Jupyter notebook) and receives `CmdOutputObservation`. Requires setting up `jupyter` [plugin](../openhands/runtime/plugins) as a requirement. -- [`FileReadAction`](../openhands/events/action/files.py) - Reads the content of a file -- [`FileWriteAction`](../openhands/events/action/files.py) - Writes new content to a file -- [`BrowseURLAction`](../openhands/events/action/browse.py) - Gets the content of a URL -- [`AddTaskAction`](../openhands/events/action/tasks.py) - Adds a subtask to the plan -- [`ModifyTaskAction`](../openhands/events/action/tasks.py) - Changes the state of a subtask. -- [`AgentFinishAction`](../openhands/events/action/agent.py) - Stops the control loop, allowing the user/delegator agent to enter a new task -- [`AgentRejectAction`](../openhands/events/action/agent.py) - Stops the control loop, allowing the user/delegator agent to enter a new task -- [`AgentFinishAction`](../openhands/events/action/agent.py) - Stops the control loop, allowing the user to enter a new task -- [`MessageAction`](../openhands/events/action/message.py) - Represents a message from an agent or the user +- [`CmdRunAction`](../events/action/commands.py) - Runs a command inside a sandboxed terminal +- [`IPythonRunCellAction`](../events/action/commands.py) - Execute a block of Python code interactively (in Jupyter notebook) and receives `CmdOutputObservation`. Requires setting up `jupyter` [plugin](../runtime/plugins) as a requirement. +- [`FileReadAction`](../events/action/files.py) - Reads the content of a file +- [`FileWriteAction`](../events/action/files.py) - Writes new content to a file +- [`BrowseURLAction`](../events/action/browse.py) - Gets the content of a URL +- [`AddTaskAction`](../events/action/tasks.py) - Adds a subtask to the plan +- [`ModifyTaskAction`](../events/action/tasks.py) - Changes the state of a subtask. +- [`AgentFinishAction`](../events/action/agent.py) - Stops the control loop, allowing the user/delegator agent to enter a new task +- [`AgentRejectAction`](../events/action/agent.py) - Stops the control loop, allowing the user/delegator agent to enter a new task +- [`AgentFinishAction`](../events/action/agent.py) - Stops the control loop, allowing the user to enter a new task +- [`MessageAction`](../events/action/message.py) - Represents a message from an agent or the user To serialize and deserialize an action, you can use: - `action.to_dict()` to serialize the action to a dictionary to be sent to the UI, including a user-friendly string representation of the message @@ -70,12 +70,12 @@ But they may also appear as a result of asynchronous events (e.g. a message from Here is a list of available Observations: -- [`CmdOutputObservation`](../openhands/events/observation/commands.py) -- [`BrowserOutputObservation`](../openhands/events/observation/browse.py) -- [`FileReadObservation`](../openhands/events/observation/files.py) -- [`FileWriteObservation`](../openhands/events/observation/files.py) -- [`ErrorObservation`](../openhands/events/observation/error.py) -- [`SuccessObservation`](../openhands/events/observation/success.py) +- [`CmdOutputObservation`](../events/observation/commands.py) +- [`BrowserOutputObservation`](../events/observation/browse.py) +- [`FileReadObservation`](../events/observation/files.py) +- [`FileWriteObservation`](../events/observation/files.py) +- [`ErrorObservation`](../events/observation/error.py) +- [`SuccessObservation`](../events/observation/success.py) You can use `observation.to_dict()` and `observation_from_dict` to serialize and deserialize observations. From 68e52a9c62f4cc6d48d33c5f1179aa4c1008b5a8 Mon Sep 17 00:00:00 2001 From: Cheng Yang <93481273+young010101@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:00:46 +0800 Subject: [PATCH 34/34] feat: add return type hints to LLM class methods (#5173) --- openhands/llm/llm.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openhands/llm/llm.py b/openhands/llm/llm.py index 6faf2c6605f4..0f9f6376c79c 100644 --- a/openhands/llm/llm.py +++ b/openhands/llm/llm.py @@ -369,16 +369,16 @@ def init_model_info(self): ): self.config.max_output_tokens = self.model_info['max_tokens'] - def vision_is_active(self): + def vision_is_active(self) -> bool: with warnings.catch_warnings(): warnings.simplefilter('ignore') return not self.config.disable_vision and self._supports_vision() - def _supports_vision(self): + def _supports_vision(self) -> bool: """Acquire from litellm if model is vision capable. Returns: - bool: True if model is vision capable. If model is not supported by litellm, it will return False. + bool: True if model is vision capable. Return False if model not supported by litellm. """ # litellm.supports_vision currently returns False for 'openai/gpt-...' or 'anthropic/claude-...' (with prefixes) # but model_info will have the correct value for some reason. @@ -476,7 +476,7 @@ def _post_completion(self, response: ModelResponse) -> None: if stats: logger.debug(stats) - def get_token_count(self, messages): + def get_token_count(self, messages) -> int: """Get the number of tokens in a list of messages. Args: @@ -491,7 +491,7 @@ def get_token_count(self, messages): # TODO: this is to limit logspam in case token count is not supported return 0 - def _is_local(self): + def _is_local(self) -> bool: """Determines if the system is using a locally running LLM. Returns: @@ -506,7 +506,7 @@ def _is_local(self): return True return False - def _completion_cost(self, response): + def _completion_cost(self, response) -> float: """Calculate the cost of a completion response based on the model. Local models are treated as free. Add the current cost into total cost in metrics. @@ -555,7 +555,7 @@ def __str__(self): def __repr__(self): return str(self) - def reset(self): + def reset(self) -> None: self.metrics.reset() def format_messages_for_llm(self, messages: Message | list[Message]) -> list[dict]: