diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 5757f05ab1e..e655ac6ac4a 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -2,11 +2,17 @@ name: Bug Report
description: Clearly report a bug with detailed repro steps
labels: ["bug"]
body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thanks for your report!** Please check existing issues first:
+ 👉 https://github.com/RooVetGit/Roo-Code/issues
+
- type: input
id: version
attributes:
label: App Version
- description: Specify exactly which version you're using (e.g., v3.3.1)
+ description: What version of Roo Code are you using? (e.g., v3.3.1)
validations:
required: true
@@ -14,22 +20,28 @@ body:
id: provider
attributes:
label: API Provider
- description: Choose the API provider involved
- multiple: false
options:
- - OpenRouter
- Anthropic
- - Google Gemini
+ - AWS Bedrock
+ - Chutes AI
- DeepSeek
- - OpenAI
- - OpenAI Compatible
- - GCP Vertex AI
- - Amazon Bedrock
- - Requesty
- Glama
- - VS Code LM API
+ - Google Gemini
+ - Google Vertex AI
+ - Groq
+ - Human Relay Provider
+ - LiteLLM
- LM Studio
+ - Mistral AI
- Ollama
+ - OpenAI
+ - OpenAI Compatible
+ - OpenRouter
+ - Requesty
+ - Unbound
+ - VS Code Language Model API
+ - xAI (Grok)
+ - Not Applicable / Other
validations:
required: true
@@ -37,44 +49,38 @@ body:
id: model
attributes:
label: Model Used
- description: Clearly specify the exact model (e.g., Claude 3.7 Sonnet)
- validations:
- required: true
-
- - type: textarea
- id: what-happened
- attributes:
- label: Actual vs. Expected Behavior
- description: Clearly state what actually happened and what you expected instead.
- placeholder: Provide precise details of the issue here.
+ description: Exact model name (e.g., Claude 3.7 Sonnet). Use N/A if irrelevant.
validations:
required: true
- type: textarea
id: steps
attributes:
- label: Detailed Steps to Reproduce
+ label: 🔁 Steps to Reproduce
description: |
- List the exact steps someone must follow to reproduce this bug:
- 1. Starting conditions (software state, settings, environment)
- 2. Precise actions taken (every click, selection, input)
- 3. Clearly observe and report outcomes
- value: |
- 1.
- 2.
- 3.
+ Help us see what you saw. Give clear, numbered steps:
+
+ 1. Setup (OS, extension version, settings)
+ 2. Exact actions (clicks, input, files, commands)
+ 3. What happened after each step
+
+ Think like you're writing a recipe. Without this, we can't reproduce the issue.
validations:
required: true
- type: textarea
- id: logs
+ id: what-happened
attributes:
- label: Relevant API Request Output
- description: Paste relevant API logs or outputs here (formatted automatically as code)
- render: shell
+ label: 💥 Outcome Summary (Optional)
+ description: |
+ Recap what went wrong in one or two lines. Use this if the bug is weird, unexpected, or needs extra context.
+
+ Example: "Expected code to run, but got an empty response and no error."
+ placeholder: Expected ___, but got ___.
- type: textarea
- id: additional-context
+ id: logs
attributes:
- label: Additional Context
- description: Include extra details, screenshots, or related issues.
+ label: 📄 Relevant Logs or Errors
+ description: Paste API logs, terminal output, or errors here. Use triple backticks (```) for code formatting.
+ render: shell
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000000..ac84be3b78e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,76 @@
+name: Detailed Feature Proposal
+description: Propose a specific, actionable feature or enhancement for implementation
+labels: ["proposal", "enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Thank you for proposing a detailed feature for Roo Code!**
+
+ This template is for submitting specific, actionable proposals that you or others intend to implement after discussion and approval. It's a key part of our [Issue-First Approach](../../CONTRIBUTING.md).
+
+ - **For general ideas or less defined suggestions**, please use [GitHub Discussions](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) first.
+ - **Before submitting**, please search existing [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues) and [Discussions](https://github.com/RooVetGit/Roo-Code/discussions) to avoid duplicates.
+
+ For guidance or to discuss your idea, join the [Roo Code Discord](https://discord.gg/roocode) and DM **Hannes Rudolph** (`hrudolph`).
+
+ A maintainer (especially @hannesrudolph) will review this proposal. **Do not start implementation until this proposal is approved and assigned.**
+ - type: textarea
+ id: problem-description
+ attributes:
+ label: What problem does this proposed feature solve?
+ description: Clearly describe the problem, use case, or opportunity this feature addresses. Why is this change needed?
+ placeholder: e.g., "Users currently cannot..." or "It would be beneficial if..."
+ validations:
+ required: true
+
+ - type: textarea
+ id: proposed-solution
+ attributes:
+ label: Describe the proposed solution in detail
+ description: Provide a clear and comprehensive description of the feature or enhancement. How should it work? What are the key functionalities?
+ placeholder: Include details on user interaction, expected behavior, and potential impact.
+ validations:
+ required: true
+
+ - type: textarea
+ id: technical-details
+ attributes:
+ label: Technical considerations or implementation details (optional)
+ description: If you have thoughts on how this could be implemented, or specific technical aspects to consider, please share them.
+ placeholder: e.g., "This might involve changes to X component..." or "We should consider Y library..."
+
+ - type: textarea
+ id: alternatives-considered
+ attributes:
+ label: Describe alternatives considered (if any)
+ description: What other ways could this problem be solved or this functionality be achieved? Why is your proposed solution preferred?
+ placeholder: Briefly outline any alternative approaches and why they were not chosen.
+
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Additional Context & Mockups
+ description: Add any other context, mockups, screenshots, or links that help illustrate the proposal.
+
+ - type: checkboxes
+ id: checklist
+ attributes:
+ label: Proposal Checklist
+ description: Please confirm the following before submitting.
+ options:
+ - label: I have searched existing Issues and Discussions to ensure this proposal is not a duplicate.
+ required: true
+ - label: This proposal is for a specific, actionable change intended for implementation (not a general idea).
+ required: true
+ - label: I understand that this proposal requires review and approval before any development work begins.
+ required: true
+
+ - type: checkboxes
+ id: willingness-to-contribute
+ attributes:
+ label: Are you interested in implementing this feature if approved?
+ description: (This is optional and does not affect the proposal's consideration)
+ options:
+ - label: Yes, I would like to contribute to implementing this feature.
+ required: false
\ No newline at end of file
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index de7e461cb9c..e013eea2774 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,35 +1,83 @@
-## Context
+
+
+### Related GitHub Issue
-
+
-## Implementation
+Closes: #
+
+### Description
-Some description of HOW you achieved it. Perhaps give a high level description of the program flow. Did you need to refactor something? What tradeoffs did you take? Are there things in here which you’d particularly like people to pay close attention to?
+### Test Procedure
+
-## Screenshots
+### Type of Change
-| before | after |
-| ------ | ----- |
-| | |
+
-## How to Test
+- [ ] 🐛 **Bug Fix**: Non-breaking change that fixes an issue.
+- [ ] ✨ **New Feature**: Non-breaking change that adds functionality.
+- [ ] 💥 **Breaking Change**: Fix or feature that would cause existing functionality to not work as expected.
+- [ ] ♻️ **Refactor**: Code change that neither fixes a bug nor adds a feature.
+- [ ] 💅 **Style**: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
+- [ ] 📚 **Documentation**: Updates to documentation files.
+- [ ] ⚙️ **Build/CI**: Changes to the build process or CI configuration.
+- [ ] 🧹 **Chore**: Other changes that don't modify `src` or test files.
-
+
+- [ ] **Issue Linked**: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
+- [ ] **Scope**: My changes are focused on the linked issue (one major feature/fix per PR).
+- [ ] **Self-Review**: I have performed a thorough self-review of my code.
+- [ ] **Code Quality**:
+ - [ ] My code adheres to the project's style guidelines.
+ - [ ] There are no new linting errors or warnings (`npm run lint`).
+ - [ ] All debug code (e.g., `console.log`) has been removed.
+- [ ] **Testing**:
+ - [ ] New and/or updated tests have been added to cover my changes.
+ - [ ] All tests pass locally (`npm test`).
+ - [ ] The application builds successfully with my changes.
+- [ ] **Branch Hygiene**: My branch is up-to-date (rebased) with the `main` branch.
+- [ ] **Documentation Impact**: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
+- [ ] **Changeset**: A changeset has been created using `npm run changeset` if this PR includes user-facing changes or dependency updates.
+- [ ] **Contribution Guidelines**: I have read and agree to the [Contributor Guidelines](../CONTRIBUTING.md).
-A straightforward scenario of how to test your changes will help reviewers that are not familiar with the part of the code that you are changing but want to see it in action. This section can include a description or step-by-step instructions of how to get to the state of v2 that your change affects.
+### Screenshots / Videos
-A "How To Test" section can look something like this:
+
-- Sign in with a user with tracks
-- Activate `show_awesome_cat_gifs` feature (add `?feature.show_awesome_cat_gifs=1` to your URL)
-- You should see a GIF with cats dancing
+### Documentation Updates
+
-## Get in Touch
+### Additional Notes
-
+
diff --git a/.github/workflows/build-vsix.yml b/.github/workflows/build-vsix.yml
new file mode 100644
index 00000000000..ab6bd95129c
--- /dev/null
+++ b/.github/workflows/build-vsix.yml
@@ -0,0 +1,45 @@
+name: Build VSIX
+
+on:
+ pull_request:
+ types: [labeled]
+ branches: [ main ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ if: github.event.label.name == 'build'
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: 'package.json'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Install all dependencies
+ run: npm run install:all
+
+ - name: Build Extension
+ run: npm run build
+
+ - name: Upload VSIX artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: extension-vsix
+ path: bin/*.vsix
+
+ - name: Comment PR with artifact link
+ if: github.event_name == 'pull_request'
+ uses: peter-evans/create-or-update-comment@v4
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ body: |
+ Build successful! 🚀
+ You can download the VSIX extension [here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
diff --git a/.github/workflows/code-qa.yml b/.github/workflows/code-qa.yml
index 7e027d0fc9a..667d0b6bf80 100644
--- a/.github/workflows/code-qa.yml
+++ b/.github/workflows/code-qa.yml
@@ -78,8 +78,10 @@ jobs:
run: npm run install:all
- name: Compile (to build and copy WASM files)
run: npm run compile
- - name: Run unit tests
+ - name: Run jest unit tests
run: npx jest --silent
+ - name: Run vitest unit tests
+ run: npx vitest run --silent
test-webview:
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/marketplace-publish.yml b/.github/workflows/marketplace-publish.yml
index 0080b10687b..834f38caf3f 100644
--- a/.github/workflows/marketplace-publish.yml
+++ b/.github/workflows/marketplace-publish.yml
@@ -29,9 +29,7 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Install Dependencies
- run: |
- npm install -g vsce ovsx
- npm run install:all
+ run: npm run install:all
- name: Create .env file
run: echo "POSTHOG_API_KEY=${{ secrets.POSTHOG_API_KEY }}" >> .env
- name: Package Extension
diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml
index 18e978a07e6..2fadbb83d9d 100644
--- a/.github/workflows/update-contributors.yml
+++ b/.github/workflows/update-contributors.yml
@@ -14,10 +14,10 @@ jobs:
pull-requests: write # Needed for creating PRs
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
diff --git a/.gitignore b/.gitignore
index 12777329698..3a541f1b094 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ out
out-*
node_modules
coverage/
+mock/
.DS_Store
diff --git a/.roo/rules-translate/001-general-rules.md b/.roo/rules-translate/001-general-rules.md
index 61d232bbf70..bdb18bea641 100644
--- a/.roo/rules-translate/001-general-rules.md
+++ b/.roo/rules-translate/001-general-rules.md
@@ -1,6 +1,6 @@
# 1. SUPPORTED LANGUAGES AND LOCATION
-- Localize all strings into the following locale files: ca, de, en, es, fr, hi, it, ja, ko, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW
+- Localize all strings into the following locale files: ca, de, en, es, fr, hi, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW
- The VSCode extension has two main areas that require localization:
- Core Extension: src/i18n/locales/ (extension backend)
- WebView UI: webview-ui/src/i18n/locales/ (user interface)
diff --git a/.roo/rules/rules.md b/.roo/rules/rules.md
index 4351fc4b81f..bf3f863a0b3 100644
--- a/.roo/rules/rules.md
+++ b/.roo/rules/rules.md
@@ -16,4 +16,4 @@
# Adding a New Setting
-To add a new setting that persists its state, follow the steps in cline_docs/settings.md
+To add a new setting that persists its state, follow the steps in docs/settings.md
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 47112d72281..850dcc07983 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -41,7 +41,17 @@
"type": "npm",
"script": "watch:esbuild",
"group": "build",
- "problemMatcher": "$esbuild-watch",
+ "problemMatcher": {
+ "owner": "esbuild",
+ "pattern": {
+ "regexp": "^$"
+ },
+ "background": {
+ "activeOnStart": true,
+ "beginsPattern": "\\[watch\\] build started",
+ "endsPattern": "\\[watch\\] build finished"
+ }
+ },
"isBackground": true,
"presentation": {
"group": "watch",
diff --git a/.vscodeignore b/.vscodeignore
index 1bc718e577e..1cc3c46cd43 100644
--- a/.vscodeignore
+++ b/.vscodeignore
@@ -33,7 +33,7 @@ jest.*
.pearai-agent-ignore
.pearai-agent-modes
benchmark/**
-cline_docs/**
+docs/**
e2e/**
evals/**
locales/**
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d2b44282d69..da8fdbeb21d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,116 @@
# Roo Code Changelog
+## [3.17.2] - 2025-05-15
+
+- Revert "Switch to the new Roo message parser" (appears to cause a tool parsing bug)
+- Lock the versions of vsce and ovsx
+
+## [3.17.1] - 2025-05-15
+
+- Fix the display of the command to execute during approval
+- Fix incorrect reserved tokens calculation on OpenRouter (thanks @daniel-lxs!)
+
+## [3.17.0] - 2025-05-14
+
+- Enable Gemini implicit caching
+- Add "when to use" section to mode definitions to enable better orchestration
+- Add experimental feature to intelligently condense the task context instead of truncating it
+- Fix one of the causes of the gray screen issue (thanks @xyOz-dev!)
+- Focus improvements for better UI interactions (thanks Cline!)
+- Switch to the new Roo message parser for improved performance (thanks Cline!)
+- Enable source maps for improved debugging (thanks @KJ7LNW!)
+- Update OpenRouter provider to use provider-specific model info (thanks @daniel-lxs!)
+- Fix Requesty cost/token reporting (thanks @dtrugman!)
+- Improve command execution UI
+- Add more in-app links to relevant documentation
+- Update the new task tool description and the ask mode custom instructions in the system prompt
+- Add IPC types to roo-code.d.ts
+- Add build VSIX workflow to pull requests (thanks @SmartManoj!)
+- Improve apply_diff tool to intelligently deduce line numbers (thanks @samhvw8!)
+- Fix command validation for shell array indexing (thanks @KJ7LNW!)
+- Handle diagnostics that point at a directory URI (thanks @daniel-lxs!)
+- Fix "Current ask promise was ignored" error (thanks @zxdvd!)
+
+## [3.16.6] - 2025-05-12
+
+- Restore "Improve provider profile management in the external API"
+- Fix to subtask sequencing (thanks @wkordalski!)
+- Fix webview terminal output processing error (thanks @KJ7LNW!)
+- Fix textarea empty string fallback logic (thanks @elianiva!)
+
+## [3.16.5] - 2025-05-10
+
+- Revert "Improve provider profile management in the external API" until we track down a bug with defaults
+
+## [3.16.4] - 2025-05-09
+
+- Improve provider profile management in the external API
+- Enforce provider selection in OpenRouter by using 'only' parameter and disabling fallbacks (thanks @shariqriazz!)
+- Fix display issues with long profile names (thanks @cannuri!)
+- Prevent terminal focus theft on paste after command execution (thanks @MuriloFP!)
+- Save OpenAI compatible custom headers correctly
+- Fix race condition when updating prompts (thanks @elianiva!)
+- Fix display issues in high contrast themes (thanks @zhangtony239!)
+- Fix not being able to use specific providers on Openrouter (thanks @daniel-lxs!)
+- Show properly formatted multi-line commands in preview (thanks @KJ7LNW!)
+- Handle unsupported language errors gracefully in read_file tool (thanks @KJ7LNW!)
+- Enhance focus styles in select-dropdown and fix docs URL (thanks @zhangtony239!)
+- Properly handle mode name overflow in UI (thanks @elianiva!)
+- Fix project MCP always allow issue (thanks @aheizi!)
+
+## [3.16.3] - 2025-05-08
+
+- Revert Tailwind migration while we fix a few spots
+- Add Elixir file extension support in language parser (thanks @pfitz!)
+
+## [3.16.2] - 2025-05-07
+
+- Clarify XML tool use formatting instructions
+- Error handling code cleanup (thanks @monkeyDluffy6017!)
+
+## [3.16.1] - 2025-05-07
+
+- Add LiteLLM provider support
+- Improve stability by detecting and preventing tool loops
+- Add Dutch localization (thanks @Githubguy132010!)
+- Add editor name to telemetry for better analytics
+- Migrate to Tailwind CSS for improved UI consistency
+- Fix footer button wrapping in About section on narrow screens (thanks @ecmasx!)
+- Update evals defaults
+- Update dependencies to latest versions
+
+## [3.16.0] - 2025-05-06
+
+- Add vertical tab navigation to the settings (thanks @dlab-anton)
+- Add Groq and Chutes API providers (thanks @shariqriazz)
+- Clickable code references in code block (thanks @KJ7LNW)
+- Improve accessibility of ato-approve toggles (thanks @Deon588)
+- Requesty provider fixes (thanks @dtrugman)
+- Fix migration and persistence of per-mode API profiles (thanks @alasano)
+- Fix usage of `path.basename` in the extension webview (thanks @samhvw8)
+- Fix display issue of the programming language dropdown in the code block component (thanks @zhangtony239)
+- MCP server errors are now captured and shown in a new "Errors" tab (thanks @robertheadley)
+- Error logging will no longer break MCP functionality if the server is properly connected (thanks @ksze)
+- You can now toggle the `terminal.integrated.inheritEnv` VSCode setting directly for the Roo Code settings (thanks @KJ7LNW)
+- Add `gemini-2.5-pro-preview-05-06` to the Vertex and Gemini providers (thanks @zetaloop)
+- Ensure evals exercises are up-to-date before running evals (thanks @shariqriazz)
+- Lots of general UI improvements (thanks @elianiva)
+- Organize provider settings into separate components
+- Improved icons and translations for the code block component
+- Add support for tests that use ESM libraries
+- Move environment detail generation to a separate module
+- Enable prompt caching by default for supported Gemini models
+
+## [3.15.5] - 2025-05-05
+
+- Update @google/genai to 0.12 (includes some streaming completion bug fixes)
+- Rendering performance improvements for code blocks in chat (thanks @KJ7LNW)
+
+## [3.15.4] - 2025-05-04
+
+- Fix a nasty bug that would cause Roo Code to hang, particularly in orchestrator mode
+- Improve Gemini caching efficiency
+
## [3.15.3] - 2025-05-02
- Terminal: Fix empty command bug
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index bb04e1abc23..06190290ebb 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+**English** • [Català](locales/ca/CODE_OF_CONDUCT.md) • [Deutsch](locales/de/CODE_OF_CONDUCT.md) • [Español](locales/es/CODE_OF_CONDUCT.md) • [Français](locales/fr/CODE_OF_CONDUCT.md) • [हिंदी](locales/hi/CODE_OF_CONDUCT.md) • [Italiano](locales/it/CODE_OF_CONDUCT.md) • [Nederlands](locales/nl/CODE_OF_CONDUCT.md) • [Русский](locales/ru/CODE_OF_CONDUCT.md)
+
+[日本語](locales/ja/CODE_OF_CONDUCT.md) • [한국어](locales/ko/CODE_OF_CONDUCT.md) • [Polski](locales/pl/CODE_OF_CONDUCT.md) • [Português (BR)](locales/pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](locales/tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](locales/vi/CODE_OF_CONDUCT.md) • [简体中文](locales/zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](locales/zh-TW/CODE_OF_CONDUCT.md)
+
# Contributor Covenant Code of Conduct
## Our Pledge
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c41ebf6de39..bbbd15590f3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,177 +1,129 @@
-# PearAI Contributing
-Go [here](https://github.com/trypear/pearai-master/blob/main/README.md) for the most up-to-date setup and contributing information to get started contributing to PearAI.
+**English** • [Català](locales/ca/CONTRIBUTING.md) • [Deutsch](locales/de/CONTRIBUTING.md) • [Español](locales/es/CONTRIBUTING.md) • [Français](locales/fr/CONTRIBUTING.md) • [हिंदी](locales/hi/CONTRIBUTING.md) • [Italiano](locales/it/CONTRIBUTING.md) • [Nederlands](locales/nl/CONTRIBUTING.md) • [Русский](locales/ru/CONTRIBUTING.md)
-______________
-## Roo Code Contribution Guide
+[日本語](locales/ja/CONTRIBUTING.md) • [한국어](locales/ko/CONTRIBUTING.md) • [Polski](locales/pl/CONTRIBUTING.md) • [Português (BR)](locales/pt-BR/CONTRIBUTING.md) • [Türkçe](locales/tr/CONTRIBUTING.md) • [Tiếng Việt](locales/vi/CONTRIBUTING.md) • [简体中文](locales/zh-CN/CONTRIBUTING.md) • [繁體中文](locales/zh-TW/CONTRIBUTING.md)
-We're thrilled you're interested in contributing to Roo Code. Whether you're fixing a bug, adding a feature, or improving our docs, every contribution makes Roo Code smarter! To keep our community vibrant and welcoming, all members must adhere to our [Code of Conduct](CODE_OF_CONDUCT.md).
+# Contributing to Roo Code
-## Join Our Community
+Roo Code is a community-driven project, and we deeply value every contribution. To streamline collaboration, we operate on an [Issue-First](#issue-first-approach) basis, meaning all [Pull Requests (PRs)](#submitting-a-pull-request) must first be linked to a GitHub Issue. Please review this guide carefully.
-We strongly encourage all contributors to join our [Discord community](https://discord.gg/roocode)! Being part of our Discord server helps you:
+## Table of Contents
-- Get real-time help and guidance on your contributions
-- Connect with other contributors and core team members
-- Stay updated on project developments and priorities
-- Participate in discussions that shape Roo Code's future
-- Find collaboration opportunities with other developers
+- [Before You Contribute](#before-you-contribute)
+- [Finding & Planning Your Contribution](#finding--planning-your-contribution)
+- [Development & Submission Process](#development--submission-process)
+- [Legal](#legal)
-## Reporting Bugs or Issues
+## Before You Contribute
-Bug reports help make Roo Code better for everyone! Before creating a new issue, please [search existing ones](https://github.com/RooVetGit/Roo-Code/issues) to avoid duplicates. When you're ready to report a bug, head over to our [issues page](https://github.com/RooVetGit/Roo-Code/issues/new/choose) where you'll find a template to help you with filling out the relevant information.
+### 1. Code of Conduct
-
- 🔐 Important: If you discover a security vulnerability, please use the Github security tool to report it privately.
-
+All contributors must adhere to our [Code of Conduct](./CODE_OF_CONDUCT.md).
-## Deciding What to Work On
+### 2. Project Roadmap
-Looking for a good first contribution? Check out issues in the "Issue [Unassigned]" section of our [Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1) Github Project. These are specifically curated for new contributors and areas where we'd love some help!
+Our roadmap guides the project's direction. Align your contributions with these key goals:
-We also welcome contributions to our [documentation](https://docs.roocode.com/)! Whether it's fixing typos, improving existing guides, or creating new educational content - we'd love to build a community-driven repository of resources that helps everyone get the most out of Roo Code. You can click "Edit this page" on any page to quickly get to the right spot in Github to edit the file, or you can dive directly into https://github.com/RooVetGit/Roo-Code-Docs.
+### Reliability First
-If you're planning to work on a bigger feature, please create a [feature request](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) first so we can discuss whether it aligns with Roo Code's vision. You may also want to check our [Project Roadmap](#project-roadmap) below to see if your idea fits with our strategic direction.
+- Ensure diff editing and command execution are consistently reliable.
+- Reduce friction points that deter regular usage.
+- Guarantee smooth operation across all locales and platforms.
+- Expand robust support for a wide variety of AI providers and models.
-## Project Roadmap
+### Enhanced User Experience
-Roo Code has a clear development roadmap that guides our priorities and future direction. Understanding our roadmap can help you:
+- Streamline the UI/UX for clarity and intuitiveness.
+- Continuously improve the workflow to meet the high expectations developers have for daily-use tools.
-- Align your contributions with project goals
-- Identify areas where your expertise would be most valuable
-- Understand the context behind certain design decisions
-- Find inspiration for new features that support our vision
+### Leading on Agent Performance
-Our current roadmap focuses on six key pillars:
+- Establish comprehensive evaluation benchmarks (evals) to measure real-world productivity.
+- Make it easy for everyone to easily run and interpret these evals.
+- Ship improvements that demonstrate clear increases in eval scores.
-### Provider Support
+Mention alignment with these areas in your PRs.
-We aim to support as many providers well as we can:
+### 3. Join the Roo Code Community
-- More versatile "OpenAI Compatible" support
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Enhanced support for Ollama and LM Studio
+- **Primary:** Join our [Discord](https://discord.gg/roocode) and DM **Hannes Rudolph (`hrudolph`)**.
+- **Alternative:** Experienced contributors can engage directly via [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Model Support
+## Finding & Planning Your Contribution
-We want Roo to work as well on as many models as possible, including local models:
+### Types of Contributions
-- Local model support through custom system prompting and workflows
-- Benchmarking evals and test cases
+- **Bug Fixes:** Addressing code issues.
+- **New Features:** Adding functionality.
+- **Documentation:** Improving guides and clarity.
-### System Support
+### Issue-First Approach
-We want Roo to run well on everyone's computer:
+All contributions must begin with a GitHub Issue.
-- Cross platform terminal integration
-- Strong and consistent support for Mac, Windows, and Linux
+- **Check existing issues**: Search [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Create an issue**: Use appropriate templates:
+ - **Bugs:** "Bug Report" template.
+ - **Features:** "Detailed Feature Proposal" template. Approval required before starting.
+- **Claim issues**: Comment and await official assignment.
-### Documentation
+**PRs without approved issues may be closed.**
-We want comprehensive, accessible documentation for all users and contributors:
+### Deciding What to Work On
-- Expanded user guides and tutorials
-- Clear API documentation
-- Better contributor guidance
-- Multilingual documentation resources
-- Interactive examples and code samples
+- Check the [GitHub Project](https://github.com/orgs/RooVetGit/projects/1) for unassigned "Good First Issues."
+- For docs, visit [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-### Stability
+### Reporting Bugs
-We want to significantly decrease the number of bugs and increase automated testing:
+- Check for existing reports first.
+- Create new bugs using the ["Bug Report" template](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Security issues**: Report privately via [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-- Debug logging switch
-- "Machine/Task Information" copy button for sending in with bug/support requests
+## Development & Submission Process
-### Internationalization
+### Development Setup
-We want Roo to speak everyone's language:
+1. **Fork & Clone:**
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
-
-We especially welcome contributions that advance our roadmap goals. If you're working on something that aligns with these pillars, please mention it in your PR description.
-
-## Development Setup
-
-1. **Clone** the repo:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **Install dependencies**:
-
-```sh
-npm run install:all
+git clone https://github.com/YOUR_USERNAME/Roo-Code.git
```
-3. **Start the webview (Vite/React app with HMR)**:
+2. **Install Dependencies:**
-```sh
-npm run dev
```
-
-4. **Debug**:
- Press `F5` (or **Run** → **Start Debugging**) in VSCode to open a new session with Roo Code loaded.
-
-Changes to the webview will appear immediately. Changes to the core extension will require a restart of the extension host.
-
-Alternatively you can build a .vsix and install it directly in VSCode:
-
-```sh
-npm run build
-```
-
-A `.vsix` file will appear in the `bin/` directory which can be installed with:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Writing and Submitting Code
-
-Anyone can contribute code to Roo Code, but we ask that you follow these guidelines to ensure your contributions can be smoothly integrated:
-
-1. **Keep Pull Requests Focused**
-
- - Limit PRs to a single feature or bug fix
- - Split larger changes into smaller, related PRs
- - Break changes into logical commits that can be reviewed independently
-
-2. **Code Quality**
+3. **Debugging:** Open with VS Code (`F5`).
- - All PRs must pass CI checks which include both linting and formatting
- - Address any ESLint warnings or errors before submitting
- - Respond to all feedback from Ellipsis, our automated code review tool
- - Follow TypeScript best practices and maintain type safety
+### Writing Code Guidelines
-3. **Testing**
+- One focused PR per feature or fix.
+- Follow ESLint and TypeScript best practices.
+- Write clear, descriptive commits referencing issues (e.g., `Fixes #123`).
+- Provide thorough testing (`npm test`).
+- Rebase onto the latest `main` branch before submission.
- - Add tests for new features
- - Run `npm test` to ensure all tests pass
- - Update existing tests if your changes affect them
- - Include both unit tests and integration tests where appropriate
+### Submitting a Pull Request
-4. **Commit Guidelines**
+- Begin as a **Draft PR** if seeking early feedback.
+- Clearly describe your changes following the Pull Request Template.
+- Provide screenshots/videos for UI changes.
+- Indicate if documentation updates are necessary.
- - Write clear, descriptive commit messages
- - Reference relevant issues in commits using #issue-number
+### Pull Request Policy
-5. **Before Submitting**
+- Must reference pre-approved, assigned issues.
+- PRs without adherence to the policy may be closed.
+- PRs should pass CI tests, align with the roadmap, and have clear documentation.
- - Rebase your branch on the latest main
- - Ensure your branch builds successfully
- - Double-check all tests are passing
- - Review your changes for any debugging code or console logs
+### Review Process
-6. **Pull Request Description**
- - Clearly describe what your changes do
- - Include steps to test the changes
- - List any breaking changes
- - Add screenshots for UI changes
+- **Daily Triage:** Quick checks by maintainers.
+- **Weekly In-depth Review:** Comprehensive assessment.
+- **Iterate promptly** based on feedback.
-## Contribution Agreement
+## Legal
-By submitting a pull request, you agree that your contributions will be licensed under the same license as the project ([Apache 2.0](LICENSE)).
+By contributing, you agree your contributions will be licensed under the Apache 2.0 License, consistent with Roo Code's licensing.
diff --git a/cline_docs/bedrock/bedrock-cache-strategy-documentation.md b/docs/bedrock/bedrock-cache-strategy-documentation.md
similarity index 100%
rename from cline_docs/bedrock/bedrock-cache-strategy-documentation.md
rename to docs/bedrock/bedrock-cache-strategy-documentation.md
diff --git a/cline_docs/bedrock/model-identification.md b/docs/bedrock/model-identification.md
similarity index 100%
rename from cline_docs/bedrock/model-identification.md
rename to docs/bedrock/model-identification.md
diff --git a/cline_docs/settings.md b/docs/settings.md
similarity index 100%
rename from cline_docs/settings.md
rename to docs/settings.md
diff --git a/e2e/.vscode-test.mjs b/e2e/.vscode-test.mjs
index ccc8b495ea9..c83f12c4bb6 100644
--- a/e2e/.vscode-test.mjs
+++ b/e2e/.vscode-test.mjs
@@ -2,18 +2,15 @@
* See: https://code.visualstudio.com/api/working-with-extensions/testing-extension
*/
-import { defineConfig } from '@vscode/test-cli';
+import { defineConfig } from "@vscode/test-cli"
export default defineConfig({
- label: 'integrationTest',
- files: 'out/suite/**/*.test.js',
- workspaceFolder: '.',
+ label: "integrationTest",
+ files: "out/suite/**/*.test.js",
+ workspaceFolder: ".",
mocha: {
- ui: 'tdd',
+ ui: "tdd",
timeout: 60000,
},
- launchArgs: [
- '--enable-proposed-api=RooVeterinaryInc.roo-cline',
- '--disable-extensions'
- ]
-});
+ launchArgs: ["--enable-proposed-api=RooVeterinaryInc.roo-cline", "--disable-extensions"],
+})
diff --git a/e2e/package-lock.json b/e2e/package-lock.json
index 278df120c28..e7f75013fdc 100644
--- a/e2e/package-lock.json
+++ b/e2e/package-lock.json
@@ -9,10 +9,10 @@
"version": "0.1.0",
"devDependencies": {
"@types/mocha": "^10.0.10",
- "@vscode/test-cli": "^0.0.9",
+ "@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.4.0",
"mocha": "^11.1.0",
- "typescript": "^5.4.5"
+ "typescript": "5.8.3"
}
},
"node_modules/@bcoe/v8-coverage": {
@@ -104,9 +104,9 @@
"license": "MIT"
},
"node_modules/@vscode/test-cli": {
- "version": "0.0.9",
- "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.9.tgz",
- "integrity": "sha512-vsl5/ueE3Jf0f6XzB0ECHHMsd5A0Yu6StElb8a+XsubZW7kHNAOw4Y3TSSuDzKEpLnJ92nbMy1Zl+KLGCE6NaA==",
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.10.tgz",
+ "integrity": "sha512-B0mMH4ia+MOOtwNiLi79XhA+MLmUItIC8FckEuKrVAVriIuSWjt7vv4+bF8qVFiNFe4QRfzPaIZk39FZGWEwHA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -318,16 +318,16 @@
}
},
"node_modules/@vscode/test-electron": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz",
- "integrity": "sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz",
+ "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==",
"dev": true,
"license": "MIT",
"dependencies": {
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.5",
"jszip": "^3.10.1",
- "ora": "^7.0.1",
+ "ora": "^8.1.0",
"semver": "^7.6.2"
},
"engines": {
@@ -411,27 +411,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -445,33 +424,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bl": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
- "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer": "^6.0.3",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -502,31 +454,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
"node_modules/c8": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz",
@@ -622,16 +549,16 @@
}
},
"node_modules/cli-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
- "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "restore-cursor": "^4.0.0"
+ "restore-cursor": "^5.0.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -965,6 +892,19 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+ "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -1061,27 +1001,6 @@
"node": ">= 14"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "BSD-3-Clause"
- },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@@ -1374,14 +1293,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "node_modules/mimic-function": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
@@ -1411,15 +1333,14 @@
}
},
"node_modules/mocha": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
- "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
+ "version": "11.2.2",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.2.2.tgz",
+ "integrity": "sha512-VlSBxrPYHK4YNOEbFdkCxHQbZMoNzBkoPprqtZRW6311EUF/DlSxoycE2e/2NtRk4WKkIXzyrXDTrlikJMWgbw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ansi-colors": "^4.1.3",
"browser-stdout": "^1.3.1",
- "chokidar": "^3.5.3",
+ "chokidar": "^4.0.1",
"debug": "^4.3.5",
"diff": "^5.2.0",
"escape-string-regexp": "^4.0.0",
@@ -1430,6 +1351,7 @@
"log-symbols": "^4.1.0",
"minimatch": "^5.1.6",
"ms": "^2.1.3",
+ "picocolors": "^1.1.1",
"serialize-javascript": "^6.0.2",
"strip-json-comments": "^3.1.1",
"supports-color": "^8.1.1",
@@ -1446,6 +1368,22 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/mocha/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/mocha/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
@@ -1459,6 +1397,20 @@
"node": ">=10"
}
},
+ "node_modules/mocha/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -1503,40 +1455,40 @@
}
},
"node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "mimic-fn": "^2.1.0"
+ "mimic-function": "^5.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz",
- "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==",
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+ "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
- "cli-cursor": "^4.0.0",
- "cli-spinners": "^2.9.0",
+ "cli-cursor": "^5.0.0",
+ "cli-spinners": "^2.9.2",
"is-interactive": "^2.0.0",
- "is-unicode-supported": "^1.3.0",
- "log-symbols": "^5.1.0",
- "stdin-discarder": "^0.1.0",
- "string-width": "^6.1.0",
+ "is-unicode-supported": "^2.0.0",
+ "log-symbols": "^6.0.0",
+ "stdin-discarder": "^0.2.2",
+ "string-width": "^7.2.0",
"strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -1563,28 +1515,41 @@
"license": "MIT"
},
"node_modules/ora/node_modules/is-unicode-supported": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
- "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ora/node_modules/log-symbols": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz",
- "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+ "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^5.0.0",
- "is-unicode-supported": "^1.1.0"
+ "chalk": "^5.3.0",
+ "is-unicode-supported": "^1.3.0"
},
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+ "dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -1593,18 +1558,18 @@
}
},
"node_modules/ora/node_modules/string-width": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz",
- "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "eastasianwidth": "^0.2.0",
- "emoji-regex": "^10.2.1",
- "strip-ansi": "^7.0.1"
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -1703,6 +1668,13 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -1773,29 +1745,22 @@
}
},
"node_modules/restore-cursor": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
- "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/restore-cursor/node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -1870,16 +1835,13 @@
}
},
"node_modules/stdin-discarder": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
- "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+ "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "bl": "^5.0.0"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -2110,9 +2072,9 @@
}
},
"node_modules/typescript": {
- "version": "5.8.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
- "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
diff --git a/e2e/package.json b/e2e/package.json
index c05e39b8760..2eed983aea2 100644
--- a/e2e/package.json
+++ b/e2e/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
- "lint": "ESLINT_USE_FLAT_CONFIG=false eslint src/**/*.ts",
+ "lint": "ESLINT_USE_FLAT_CONFIG=false eslint src/**/*.ts --max-warnings=0",
"check-types": "tsc --noEmit",
"test": "npm run build && npx dotenvx run -f .env.local -- node ./out/runTest.js",
"ci": "npm run vscode-test && npm run test",
@@ -13,9 +13,9 @@
"dependencies": {},
"devDependencies": {
"@types/mocha": "^10.0.10",
- "@vscode/test-cli": "^0.0.9",
+ "@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.4.0",
"mocha": "^11.1.0",
- "typescript": "^5.4.5"
+ "typescript": "5.8.3"
}
}
diff --git a/evals/apps/web/package.json b/evals/apps/web/package.json
index d52770bbb5d..d7b5ca6aed3 100644
--- a/evals/apps/web/package.json
+++ b/evals/apps/web/package.json
@@ -31,7 +31,7 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.0",
"fuzzysort": "^3.1.0",
- "lucide-react": "^0.479.0",
+ "lucide-react": "^0.510.0",
"next": "15.2.2",
"next-themes": "^0.4.6",
"p-map": "^7.0.3",
diff --git a/evals/config/eslint/package.json b/evals/config/eslint/package.json
index 3b84b039de4..b706de1d95a 100644
--- a/evals/config/eslint/package.json
+++ b/evals/config/eslint/package.json
@@ -16,7 +16,6 @@
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-turbo": "^2.4.4",
"globals": "^16.0.0",
- "typescript": "^5",
"typescript-eslint": "^8.26.0"
}
}
diff --git a/evals/package.json b/evals/package.json
index 2e7c21d9770..92c4ab99cd1 100644
--- a/evals/package.json
+++ b/evals/package.json
@@ -20,7 +20,7 @@
"prettier": "^3.5.3",
"tsx": "^4.19.4",
"turbo": "^2.5.2",
- "typescript": "^5.8.3",
+ "typescript": "5.8.3",
"typescript-eslint": "^8.31.1"
}
}
diff --git a/evals/packages/db/package.json b/evals/packages/db/package.json
index ffc298ea01f..bbf3c1cfc79 100644
--- a/evals/packages/db/package.json
+++ b/evals/packages/db/package.json
@@ -21,8 +21,8 @@
},
"dependencies": {
"@evals/types": "workspace:^",
- "@libsql/client": "^0.14.0",
- "drizzle-orm": "^0.40.0",
+ "@libsql/client": "^0.15.0",
+ "drizzle-orm": "^0.43.0",
"drizzle-zod": "^0.7.0",
"p-map": "^7.0.3",
"zod": "^3.24.2"
@@ -30,7 +30,7 @@
"devDependencies": {
"@evals/eslint-config": "workspace:^",
"@evals/typescript-config": "workspace:^",
- "drizzle-kit": "^0.30.5",
+ "drizzle-kit": "^0.31.0",
"execa": "^9.5.2",
"vitest": "^3.0.9"
}
diff --git a/evals/packages/types/src/roo-code-defaults.ts b/evals/packages/types/src/roo-code-defaults.ts
index 442510976bf..9c20f94146d 100644
--- a/evals/packages/types/src/roo-code-defaults.ts
+++ b/evals/packages/types/src/roo-code-defaults.ts
@@ -4,7 +4,7 @@ export const rooCodeDefaults: RooCodeSettings = {
apiProvider: "openrouter",
openRouterUseMiddleOutTransform: false,
- lastShownAnnouncementId: "apr-30-2025-3-15",
+ lastShownAnnouncementId: "may-06-2025-3-16",
pinnedApiConfigs: {},
@@ -42,7 +42,7 @@ export const rooCodeDefaults: RooCodeSettings = {
terminalZshP10k: false,
terminalZdotdir: true,
terminalCompressProgressBar: true,
- terminalShellIntegrationDisabled: true,
+ terminalShellIntegrationDisabled: false,
diffEnabled: true,
fuzzyMatchThreshold: 1,
@@ -53,7 +53,7 @@ export const rooCodeDefaults: RooCodeSettings = {
maxOpenTabsContext: 20,
maxWorkspaceFiles: 200,
showRooIgnoredFiles: true,
- maxReadFileLine: 500,
+ maxReadFileLine: 500, // -1 to enable full file reading.
language: "en",
telemetrySetting: "enabled",
diff --git a/evals/packages/types/src/roo-code.ts b/evals/packages/types/src/roo-code.ts
index 4318603edc5..08dd58e6180 100644
--- a/evals/packages/types/src/roo-code.ts
+++ b/evals/packages/types/src/roo-code.ts
@@ -56,6 +56,7 @@ export const languages = [
"it",
"ja",
"ko",
+ "nl",
"pl",
"pt-BR",
"ru",
@@ -102,7 +103,6 @@ export const modelInfoSchema = z.object({
supportsImages: z.boolean().optional(),
supportsComputerUse: z.boolean().optional(),
supportsPromptCache: z.boolean(),
- isPromptCacheOptional: z.boolean().optional(),
inputPrice: z.number().optional(),
outputPrice: z.number().optional(),
cacheWritesPrice: z.number().optional(),
@@ -128,18 +128,6 @@ export const modelInfoSchema = z.object({
export type ModelInfo = z.infer
-/**
- * ApiConfigMeta
- */
-
-export const apiConfigMetaSchema = z.object({
- id: z.string(),
- name: z.string(),
- apiProvider: providerNamesSchema.optional(),
-})
-
-export type ApiConfigMeta = z.infer
-
/**
* HistoryItem
*/
@@ -310,7 +298,7 @@ export type CommandExecutionStatus = z.infer
*/
const experimentsSchema = z.object({
+ autoCondenseContext: z.boolean(),
powerSteering: z.boolean(),
})
@@ -330,45 +319,75 @@ export type Experiments = z.infer
type _AssertExperiments = AssertEqual>>
/**
- * ProviderSettings
+ * ProviderSettingsEntry
*/
-export const providerSettingsSchema = z.object({
+export const providerSettingsEntrySchema = z.object({
+ id: z.string(),
+ name: z.string(),
apiProvider: providerNamesSchema.optional(),
- // Anthropic
+})
+
+export type ProviderSettingsEntry = z.infer
+
+/**
+ * ProviderSettings
+ */
+
+const genericProviderSettingsSchema = z.object({
+ includeMaxTokens: z.boolean().optional(),
+ reasoningEffort: reasoningEffortsSchema.optional(),
+ diffEnabled: z.boolean().optional(),
+ fuzzyMatchThreshold: z.number().optional(),
+ modelTemperature: z.number().nullish(),
+ rateLimitSeconds: z.number().optional(),
+ // Claude 3.7 Sonnet Thinking
+ modelMaxTokens: z.number().optional(),
+ modelMaxThinkingTokens: z.number().optional(),
+})
+
+const anthropicSchema = z.object({
apiModelId: z.string().optional(),
apiKey: z.string().optional(),
anthropicBaseUrl: z.string().optional(),
anthropicUseAuthToken: z.boolean().optional(),
- // Glama
+})
+
+const glamaSchema = z.object({
glamaModelId: z.string().optional(),
glamaApiKey: z.string().optional(),
- // OpenRouter
+})
+
+const openRouterSchema = z.object({
openRouterApiKey: z.string().optional(),
openRouterModelId: z.string().optional(),
openRouterBaseUrl: z.string().optional(),
openRouterSpecificProvider: z.string().optional(),
openRouterUseMiddleOutTransform: z.boolean().optional(),
- // Amazon Bedrock
+})
+
+const bedrockSchema = z.object({
awsAccessKey: z.string().optional(),
awsSecretKey: z.string().optional(),
awsSessionToken: z.string().optional(),
awsRegion: z.string().optional(),
awsUseCrossRegionInference: z.boolean().optional(),
awsUsePromptCache: z.boolean().optional(),
- awspromptCacheId: z.string().optional(),
awsProfile: z.string().optional(),
awsUseProfile: z.boolean().optional(),
awsCustomArn: z.string().optional(),
- // Google Vertex
+})
+
+const vertexSchema = z.object({
vertexKeyFile: z.string().optional(),
vertexJsonCredentials: z.string().optional(),
vertexProjectId: z.string().optional(),
vertexRegion: z.string().optional(),
- // OpenAI
+})
+
+const openAiSchema = z.object({
openAiBaseUrl: z.string().optional(),
openAiApiKey: z.string().optional(),
- openAiHostHeader: z.string().optional(),
openAiLegacyFormat: z.boolean().optional(),
openAiR1FormatEnabled: z.boolean().optional(),
openAiModelId: z.string().optional(),
@@ -377,10 +396,16 @@ export const providerSettingsSchema = z.object({
azureApiVersion: z.string().optional(),
openAiStreamingEnabled: z.boolean().optional(),
enableReasoningEffort: z.boolean().optional(),
- // Ollama
+ openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration.
+ openAiHeaders: z.record(z.string(), z.string()).optional(),
+})
+
+const ollamaSchema = z.object({
ollamaModelId: z.string().optional(),
ollamaBaseUrl: z.string().optional(),
- // VS Code LM
+})
+
+const vsCodeLmSchema = z.object({
vsCodeLmModelSelector: z
.object({
vendor: z.string().optional(),
@@ -389,43 +414,48 @@ export const providerSettingsSchema = z.object({
id: z.string().optional(),
})
.optional(),
- // LM Studio
+})
+
+const lmStudioSchema = z.object({
lmStudioModelId: z.string().optional(),
lmStudioBaseUrl: z.string().optional(),
lmStudioDraftModelId: z.string().optional(),
lmStudioSpeculativeDecodingEnabled: z.boolean().optional(),
- // Gemini
+})
+
+const geminiSchema = z.object({
geminiApiKey: z.string().optional(),
googleGeminiBaseUrl: z.string().optional(),
- // OpenAI Native
+})
+
+const openAiNativeSchema = z.object({
openAiNativeApiKey: z.string().optional(),
openAiNativeBaseUrl: z.string().optional(),
- // Mistral
+})
+
+const mistralSchema = z.object({
mistralApiKey: z.string().optional(),
mistralCodestralUrl: z.string().optional(),
- // DeepSeek
+})
+
+const deepSeekSchema = z.object({
deepSeekBaseUrl: z.string().optional(),
deepSeekApiKey: z.string().optional(),
- // Unbound
+})
+
+const unboundSchema = z.object({
unboundApiKey: z.string().optional(),
unboundModelId: z.string().optional(),
- // Requesty
+})
+
+const requestySchema = z.object({
requestyApiKey: z.string().optional(),
requestyModelId: z.string().optional(),
- // X.AI (Grok)
- xaiApiKey: z.string().optional(),
- // Claude 3.7 Sonnet Thinking
- modelMaxTokens: z.number().optional(),
- modelMaxThinkingTokens: z.number().optional(),
- // Generic
- includeMaxTokens: z.boolean().optional(),
- reasoningEffort: reasoningEffortsSchema.optional(),
- promptCachingEnabled: z.boolean().optional(),
- diffEnabled: z.boolean().optional(),
- fuzzyMatchThreshold: z.number().optional(),
- modelTemperature: z.number().nullish(),
- rateLimitSeconds: z.number().optional(),
- // Fake AI
+})
+
+const humanRelaySchema = z.object({})
+
+const fakeAiSchema = z.object({
fakeAi: z.unknown().optional(),
// PearAI
pearaiApiKey: z.string().optional(),
@@ -437,6 +467,165 @@ export const providerSettingsSchema = z.object({
.optional(),
})
+const xaiSchema = z.object({
+ xaiApiKey: z.string().optional(),
+})
+
+const groqSchema = z.object({
+ groqApiKey: z.string().optional(),
+})
+
+const chutesSchema = z.object({
+ chutesApiKey: z.string().optional(),
+})
+
+const litellmSchema = z.object({
+ litellmBaseUrl: z.string().optional(),
+ litellmApiKey: z.string().optional(),
+ litellmModelId: z.string().optional(),
+})
+
+const defaultSchema = z.object({
+ apiProvider: z.undefined(),
+})
+
+export const providerSettingsSchemaDiscriminated = z
+ .discriminatedUnion("apiProvider", [
+ anthropicSchema.merge(
+ z.object({
+ apiProvider: z.literal("anthropic"),
+ }),
+ ),
+ glamaSchema.merge(
+ z.object({
+ apiProvider: z.literal("glama"),
+ }),
+ ),
+ openRouterSchema.merge(
+ z.object({
+ apiProvider: z.literal("openrouter"),
+ }),
+ ),
+ bedrockSchema.merge(
+ z.object({
+ apiProvider: z.literal("bedrock"),
+ }),
+ ),
+ vertexSchema.merge(
+ z.object({
+ apiProvider: z.literal("vertex"),
+ }),
+ ),
+ openAiSchema.merge(
+ z.object({
+ apiProvider: z.literal("openai"),
+ }),
+ ),
+ ollamaSchema.merge(
+ z.object({
+ apiProvider: z.literal("ollama"),
+ }),
+ ),
+ vsCodeLmSchema.merge(
+ z.object({
+ apiProvider: z.literal("vscode-lm"),
+ }),
+ ),
+ lmStudioSchema.merge(
+ z.object({
+ apiProvider: z.literal("lmstudio"),
+ }),
+ ),
+ geminiSchema.merge(
+ z.object({
+ apiProvider: z.literal("gemini"),
+ }),
+ ),
+ openAiNativeSchema.merge(
+ z.object({
+ apiProvider: z.literal("openai-native"),
+ }),
+ ),
+ mistralSchema.merge(
+ z.object({
+ apiProvider: z.literal("mistral"),
+ }),
+ ),
+ deepSeekSchema.merge(
+ z.object({
+ apiProvider: z.literal("deepseek"),
+ }),
+ ),
+ unboundSchema.merge(
+ z.object({
+ apiProvider: z.literal("unbound"),
+ }),
+ ),
+ requestySchema.merge(
+ z.object({
+ apiProvider: z.literal("requesty"),
+ }),
+ ),
+ humanRelaySchema.merge(
+ z.object({
+ apiProvider: z.literal("human-relay"),
+ }),
+ ),
+ fakeAiSchema.merge(
+ z.object({
+ apiProvider: z.literal("fake-ai"),
+ }),
+ ),
+ xaiSchema.merge(
+ z.object({
+ apiProvider: z.literal("xai"),
+ }),
+ ),
+ groqSchema.merge(
+ z.object({
+ apiProvider: z.literal("groq"),
+ }),
+ ),
+ chutesSchema.merge(
+ z.object({
+ apiProvider: z.literal("chutes"),
+ }),
+ ),
+ litellmSchema.merge(
+ z.object({
+ apiProvider: z.literal("litellm"),
+ }),
+ ),
+ defaultSchema,
+ ])
+ .and(genericProviderSettingsSchema)
+
+export const providerSettingsSchema = z.object({
+ apiProvider: providerNamesSchema.optional(),
+ ...anthropicSchema.shape,
+ ...glamaSchema.shape,
+ ...openRouterSchema.shape,
+ ...bedrockSchema.shape,
+ ...vertexSchema.shape,
+ ...openAiSchema.shape,
+ ...ollamaSchema.shape,
+ ...vsCodeLmSchema.shape,
+ ...lmStudioSchema.shape,
+ ...geminiSchema.shape,
+ ...openAiNativeSchema.shape,
+ ...mistralSchema.shape,
+ ...deepSeekSchema.shape,
+ ...unboundSchema.shape,
+ ...requestySchema.shape,
+ ...humanRelaySchema.shape,
+ ...fakeAiSchema.shape,
+ ...xaiSchema.shape,
+ ...groqSchema.shape,
+ ...chutesSchema.shape,
+ ...litellmSchema.shape,
+ ...genericProviderSettingsSchema.shape,
+})
+
export type ProviderSettings = z.infer
type ProviderSettingsRecord = Record, undefined>
@@ -464,7 +653,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
awsRegion: undefined,
awsUseCrossRegionInference: undefined,
awsUsePromptCache: undefined,
- awspromptCacheId: undefined,
awsProfile: undefined,
awsUseProfile: undefined,
awsCustomArn: undefined,
@@ -476,7 +664,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
// OpenAI
openAiBaseUrl: undefined,
openAiApiKey: undefined,
- openAiHostHeader: undefined,
openAiLegacyFormat: undefined,
openAiR1FormatEnabled: undefined,
openAiModelId: undefined,
@@ -485,6 +672,8 @@ const providerSettingsRecord: ProviderSettingsRecord = {
azureApiVersion: undefined,
openAiStreamingEnabled: undefined,
enableReasoningEffort: undefined,
+ openAiHostHeader: undefined, // Keep temporarily for backward compatibility during migration
+ openAiHeaders: undefined,
// Ollama
ollamaModelId: undefined,
ollamaBaseUrl: undefined,
@@ -518,7 +707,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
// Generic
includeMaxTokens: undefined,
reasoningEffort: undefined,
- promptCachingEnabled: undefined,
diffEnabled: undefined,
fuzzyMatchThreshold: undefined,
modelTemperature: undefined,
@@ -530,6 +718,14 @@ const providerSettingsRecord: ProviderSettingsRecord = {
pearaiAgentModels: undefined,
// X.AI (Grok)
xaiApiKey: undefined,
+ // Groq
+ groqApiKey: undefined,
+ // Chutes AI
+ chutesApiKey: undefined,
+ // LiteLLM
+ litellmBaseUrl: undefined,
+ litellmApiKey: undefined,
+ litellmModelId: undefined,
}
export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Keys[]
@@ -540,7 +736,7 @@ export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Key
export const globalSettingsSchema = z.object({
currentApiConfigName: z.string().optional(),
- listApiConfigMeta: z.array(apiConfigMetaSchema).optional(),
+ listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
lastShownAnnouncementId: z.string().optional(),
diff --git a/evals/pnpm-lock.yaml b/evals/pnpm-lock.yaml
index b2acaab60d1..e1a787cc184 100644
--- a/evals/pnpm-lock.yaml
+++ b/evals/pnpm-lock.yaml
@@ -10,16 +10,16 @@ importers:
devDependencies:
'@dotenvx/dotenvx':
specifier: ^1.41.0
- version: 1.41.0
+ version: 1.44.0
'@eslint/js':
specifier: ^9.25.1
- version: 9.25.1
+ version: 9.26.0
eslint:
specifier: ^9.25.1
- version: 9.25.1(jiti@2.4.2)
+ version: 9.26.0(jiti@2.4.2)
globals:
specifier: ^16.0.0
- version: 16.0.0
+ version: 16.1.0
prettier:
specifier: ^3.5.3
version: 3.5.3
@@ -28,13 +28,13 @@ importers:
version: 4.19.4
turbo:
specifier: ^2.5.2
- version: 2.5.2
+ version: 2.5.3
typescript:
- specifier: ^5.8.3
+ specifier: 5.8.3
version: 5.8.3
typescript-eslint:
specifier: ^8.31.1
- version: 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
+ version: 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
apps/cli:
dependencies:
@@ -142,8 +142,8 @@ importers:
specifier: ^3.1.0
version: 3.1.0
lucide-react:
- specifier: ^0.479.0
- version: 0.479.0(react@19.0.0)
+ specifier: ^0.510.0
+ version: 0.510.0(react@19.0.0)
next:
specifier: 15.2.2
version: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -231,16 +231,13 @@ importers:
version: 5.2.0(eslint@9.22.0(jiti@2.4.2))
eslint-plugin-turbo:
specifier: ^2.4.4
- version: 2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.5.2)
+ version: 2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.5.3)
globals:
specifier: ^16.0.0
version: 16.0.0
- typescript:
- specifier: ^5
- version: 5.8.2
typescript-eslint:
specifier: ^8.26.0
- version: 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ version: 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
config/typescript: {}
@@ -250,14 +247,14 @@ importers:
specifier: workspace:^
version: link:../types
'@libsql/client':
- specifier: ^0.14.0
- version: 0.14.0
+ specifier: ^0.15.0
+ version: 0.15.4
drizzle-orm:
- specifier: ^0.40.0
- version: 0.40.1(@libsql/client@0.14.0)(gel@2.0.1)
+ specifier: ^0.43.0
+ version: 0.43.1(@libsql/client@0.15.4)(gel@2.0.1)
drizzle-zod:
specifier: ^0.7.0
- version: 0.7.0(drizzle-orm@0.40.1(@libsql/client@0.14.0)(gel@2.0.1))(zod@3.24.2)
+ version: 0.7.0(drizzle-orm@0.43.1(@libsql/client@0.15.4)(gel@2.0.1))(zod@3.24.2)
p-map:
specifier: ^7.0.3
version: 7.0.3
@@ -272,8 +269,8 @@ importers:
specifier: workspace:^
version: link:../../config/typescript
drizzle-kit:
- specifier: ^0.30.5
- version: 0.30.5
+ specifier: ^0.31.0
+ version: 0.31.1
execa:
specifier: ^9.5.2
version: 9.5.2
@@ -346,8 +343,8 @@ packages:
resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==}
engines: {node: '>=6.9.0'}
- '@dotenvx/dotenvx@1.41.0':
- resolution: {integrity: sha512-lFZOSKLM2/Jm7FXYUIvnciUhMsuEatyxCgau4lnjDD59LaSYiaNLjyjnUL/aYpH1+iaDhD37+mPOzH9kBZlUJQ==}
+ '@dotenvx/dotenvx@1.44.0':
+ resolution: {integrity: sha512-18Aa+7KP/L2Kj9lxmT4EJZnsCq/xGIHgzU26rdzsKMhjpeT3YY+qin/dNAnIaVHPZnee7kXpZL55M9htd30r7Q==}
hasBin: true
'@drizzle-team/brocli@0.10.2':
@@ -370,12 +367,6 @@ packages:
resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==}
deprecated: 'Merged into tsx: https://tsx.is'
- '@esbuild/aix-ppc64@0.19.12':
- resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [aix]
-
'@esbuild/aix-ppc64@0.25.1':
resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==}
engines: {node: '>=18'}
@@ -394,12 +385,6 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.19.12':
- resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
-
'@esbuild/android-arm64@0.25.1':
resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==}
engines: {node: '>=18'}
@@ -418,12 +403,6 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.19.12':
- resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
-
'@esbuild/android-arm@0.25.1':
resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==}
engines: {node: '>=18'}
@@ -442,12 +421,6 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.19.12':
- resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
-
'@esbuild/android-x64@0.25.1':
resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==}
engines: {node: '>=18'}
@@ -466,12 +439,6 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.19.12':
- resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
-
'@esbuild/darwin-arm64@0.25.1':
resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==}
engines: {node: '>=18'}
@@ -490,12 +457,6 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.19.12':
- resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
-
'@esbuild/darwin-x64@0.25.1':
resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==}
engines: {node: '>=18'}
@@ -514,12 +475,6 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.19.12':
- resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
-
'@esbuild/freebsd-arm64@0.25.1':
resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==}
engines: {node: '>=18'}
@@ -538,12 +493,6 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.19.12':
- resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
-
'@esbuild/freebsd-x64@0.25.1':
resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==}
engines: {node: '>=18'}
@@ -562,12 +511,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.19.12':
- resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
-
'@esbuild/linux-arm64@0.25.1':
resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==}
engines: {node: '>=18'}
@@ -586,12 +529,6 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.19.12':
- resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
-
'@esbuild/linux-arm@0.25.1':
resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==}
engines: {node: '>=18'}
@@ -610,12 +547,6 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.19.12':
- resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
-
'@esbuild/linux-ia32@0.25.1':
resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==}
engines: {node: '>=18'}
@@ -634,12 +565,6 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.19.12':
- resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
-
'@esbuild/linux-loong64@0.25.1':
resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==}
engines: {node: '>=18'}
@@ -658,12 +583,6 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.19.12':
- resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
-
'@esbuild/linux-mips64el@0.25.1':
resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==}
engines: {node: '>=18'}
@@ -682,12 +601,6 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.19.12':
- resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
-
'@esbuild/linux-ppc64@0.25.1':
resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==}
engines: {node: '>=18'}
@@ -706,12 +619,6 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.19.12':
- resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
-
'@esbuild/linux-riscv64@0.25.1':
resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==}
engines: {node: '>=18'}
@@ -730,12 +637,6 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.19.12':
- resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
-
'@esbuild/linux-s390x@0.25.1':
resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==}
engines: {node: '>=18'}
@@ -754,12 +655,6 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.19.12':
- resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
-
'@esbuild/linux-x64@0.25.1':
resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==}
engines: {node: '>=18'}
@@ -790,12 +685,6 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.19.12':
- resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
-
'@esbuild/netbsd-x64@0.25.1':
resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==}
engines: {node: '>=18'}
@@ -826,12 +715,6 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.19.12':
- resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
-
'@esbuild/openbsd-x64@0.25.1':
resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==}
engines: {node: '>=18'}
@@ -850,12 +733,6 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.19.12':
- resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
-
'@esbuild/sunos-x64@0.25.1':
resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==}
engines: {node: '>=18'}
@@ -874,12 +751,6 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.19.12':
- resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
-
'@esbuild/win32-arm64@0.25.1':
resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==}
engines: {node: '>=18'}
@@ -898,12 +769,6 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.19.12':
- resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
-
'@esbuild/win32-ia32@0.25.1':
resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==}
engines: {node: '>=18'}
@@ -922,12 +787,6 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.19.12':
- resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
-
'@esbuild/win32-x64@0.25.1':
resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==}
engines: {node: '>=18'}
@@ -952,6 +811,12 @@ packages:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ '@eslint-community/eslint-utils@4.7.0':
+ resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
'@eslint-community/regexpp@4.12.1':
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@@ -968,8 +833,8 @@ packages:
resolution: {integrity: sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/config-helpers@0.2.1':
- resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
+ '@eslint/config-helpers@0.2.2':
+ resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/core@0.12.0':
@@ -992,8 +857,8 @@ packages:
resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@9.25.1':
- resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==}
+ '@eslint/js@9.26.0':
+ resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.6':
@@ -1048,6 +913,10 @@ packages:
resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
engines: {node: '>=18.18'}
+ '@humanwhocodes/retry@0.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
'@img/sharp-darwin-arm64@0.33.5':
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -1156,19 +1025,19 @@ packages:
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
- '@libsql/client@0.14.0':
- resolution: {integrity: sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==}
+ '@libsql/client@0.15.4':
+ resolution: {integrity: sha512-m8a7giWlhLdfKVIZFd3UlBptWTS+H0toSOL09BxbqzBeFHwuVC+5ewyi4LMBxoy2TLNQGE4lO8cwpsTWmu695w==}
- '@libsql/core@0.14.0':
- resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==}
+ '@libsql/core@0.15.4':
+ resolution: {integrity: sha512-NMvh6xnn3vrcd7DNehj0HiJcRWB2a8hHhJUTkOBej3Pf3KB21HOmdOUjXxJ5pGbjWXh4ezQBmHtF5ozFhocXaA==}
- '@libsql/darwin-arm64@0.4.7':
- resolution: {integrity: sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==}
+ '@libsql/darwin-arm64@0.5.8':
+ resolution: {integrity: sha512-dJRfwCHAKOIgysMbB+PBo3ZmCVuGC02fH57kFEFlqbbUv6wnAZV5g7GErQIv4IlC4VPKAS4RL20fjLUgXE+0Xg==}
cpu: [arm64]
os: [darwin]
- '@libsql/darwin-x64@0.4.7':
- resolution: {integrity: sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==}
+ '@libsql/darwin-x64@0.5.8':
+ resolution: {integrity: sha512-ua5ngqJy9o4lyjYDzF8c69YbOAwP2TQXPhDURs8l97b09HHFh5/8gWRNor7vYRpsziwp8TC77DdQ0C84+gP5tg==}
cpu: [x64]
os: [darwin]
@@ -1182,31 +1051,35 @@ packages:
'@libsql/isomorphic-ws@0.1.5':
resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==}
- '@libsql/linux-arm64-gnu@0.4.7':
- resolution: {integrity: sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==}
+ '@libsql/linux-arm64-gnu@0.5.8':
+ resolution: {integrity: sha512-6HHZlPbMu+cmCJafg/dwOcWFMu07hTB5teMKU5ke66kqeWLRBnOs5/DnZGVz6q0k+Z4L4UTRbdrnCklR3GmvFg==}
cpu: [arm64]
os: [linux]
- '@libsql/linux-arm64-musl@0.4.7':
- resolution: {integrity: sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==}
+ '@libsql/linux-arm64-musl@0.5.8':
+ resolution: {integrity: sha512-QGhZadKk3gvrDHa63U7xQrsqET/43E6L7/15oh7I+SINl8meoZAJNTJNYfOUmPM2lPPfNDgr46v4p5ggo6su0A==}
cpu: [arm64]
os: [linux]
- '@libsql/linux-x64-gnu@0.4.7':
- resolution: {integrity: sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==}
+ '@libsql/linux-x64-gnu@0.5.8':
+ resolution: {integrity: sha512-HUWxOvLE5W287O/vaHWFpZMqaaebEBZvcUqJJ/E+IcC9kmKc6GqDW+fJkfPfosrpGyPNbYDj0w9pIcck0l/oeA==}
cpu: [x64]
os: [linux]
- '@libsql/linux-x64-musl@0.4.7':
- resolution: {integrity: sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==}
+ '@libsql/linux-x64-musl@0.5.8':
+ resolution: {integrity: sha512-hfhkPwqzFroU01xUB7ZXFw3bP+jqcGolGLyhEkeh/Rsoune0ucm1KPrU2tqTBqQP4a7lL0nSL1A37nfjIO61Hw==}
cpu: [x64]
os: [linux]
- '@libsql/win32-x64-msvc@0.4.7':
- resolution: {integrity: sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==}
+ '@libsql/win32-x64-msvc@0.5.8':
+ resolution: {integrity: sha512-8hKczus0swLEvXu8N0znWdyFo5QzFnE9mnz7G/sb+eVn+zpPlT6ZdFHZdhQzev9C0to7kvYDj03qESTUIwDiqg==}
cpu: [x64]
os: [win32]
+ '@modelcontextprotocol/sdk@1.11.2':
+ resolution: {integrity: sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==}
+ engines: {node: '>=18'}
+
'@neon-rs/load@0.0.4':
resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==}
@@ -2202,8 +2075,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/eslint-plugin@8.31.1':
- resolution: {integrity: sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==}
+ '@typescript-eslint/eslint-plugin@8.32.1':
+ resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
@@ -2217,8 +2090,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/parser@8.31.1':
- resolution: {integrity: sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==}
+ '@typescript-eslint/parser@8.32.1':
+ resolution: {integrity: sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -2228,8 +2101,8 @@ packages:
resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/scope-manager@8.31.1':
- resolution: {integrity: sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==}
+ '@typescript-eslint/scope-manager@8.32.1':
+ resolution: {integrity: sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.26.1':
@@ -2239,8 +2112,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/type-utils@8.31.1':
- resolution: {integrity: sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==}
+ '@typescript-eslint/type-utils@8.32.1':
+ resolution: {integrity: sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -2250,8 +2123,8 @@ packages:
resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/types@8.31.1':
- resolution: {integrity: sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==}
+ '@typescript-eslint/types@8.32.1':
+ resolution: {integrity: sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.26.1':
@@ -2260,8 +2133,8 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/typescript-estree@8.31.1':
- resolution: {integrity: sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==}
+ '@typescript-eslint/typescript-estree@8.32.1':
+ resolution: {integrity: sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
@@ -2273,8 +2146,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/utils@8.31.1':
- resolution: {integrity: sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==}
+ '@typescript-eslint/utils@8.32.1':
+ resolution: {integrity: sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -2284,8 +2157,8 @@ packages:
resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/visitor-keys@8.31.1':
- resolution: {integrity: sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==}
+ '@typescript-eslint/visitor-keys@8.32.1':
+ resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@vitest/expect@3.0.9':
@@ -2320,6 +2193,10 @@ packages:
'@xobotyi/scrollbar-width@1.9.5':
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -2415,6 +2292,10 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ body-parser@2.2.0:
+ resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==}
+ engines: {node: '>=18'}
+
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@@ -2432,6 +2313,10 @@ packages:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -2537,6 +2422,22 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ content-disposition@1.0.0:
+ resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
copy-to-clipboard@3.3.3:
resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
@@ -2547,6 +2448,10 @@ packages:
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
cosmiconfig@7.0.1:
resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==}
engines: {node: '>=10'}
@@ -2594,6 +2499,15 @@ packages:
supports-color:
optional: true
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
@@ -2612,6 +2526,10 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
@@ -2635,12 +2553,12 @@ packages:
resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==}
engines: {node: '>=12'}
- drizzle-kit@0.30.5:
- resolution: {integrity: sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA==}
+ drizzle-kit@0.31.1:
+ resolution: {integrity: sha512-PUjYKWtzOzPtdtQlTHQG3qfv4Y0XT8+Eas6UbxCmxTj7qgMf+39dDujf1BP1I+qqZtw9uzwTh8jYtkMuCq+B0Q==}
hasBin: true
- drizzle-orm@0.40.1:
- resolution: {integrity: sha512-aPNhtiJiPfm3qxz1czrnIDkfvkSdKGXYeZkpG55NPTVI186LmK2fBLMi4dsHpPHlJrZeQ92D322YFPHADBALew==}
+ drizzle-orm@0.43.1:
+ resolution: {integrity: sha512-dUcDaZtE/zN4RV/xqGrVSMpnEczxd5cIaoDeor7Zst9wOe/HzC/7eAaulywWGYXdDEc9oBPMjayVEDg0ziTLJA==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
'@cloudflare/workers-types': '>=4'
@@ -2650,7 +2568,7 @@ packages:
'@neondatabase/serverless': '>=0.10.0'
'@op-engineering/op-sqlite': '>=2'
'@opentelemetry/api': ^1.4.1
- '@planetscale/database': '>=1'
+ '@planetscale/database': '>=1.13'
'@prisma/client': '*'
'@tidbcloud/serverless': '*'
'@types/better-sqlite3': '*'
@@ -2749,6 +2667,9 @@ packages:
resolution: {integrity: sha512-eJAgf9pdv214Hn98FlUzclRMYWF7WfoLlkS9nWMTm1qcCwn6Ad4EGD9lr9HXMBfSrZhYQujRE+p0adPRkctC6A==}
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
ejs@3.1.8:
resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==}
engines: {node: '>=0.10.0'}
@@ -2757,6 +2678,10 @@ packages:
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
enhanced-resolve@5.18.1:
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
engines: {node: '>=10.13.0'}
@@ -2820,11 +2745,6 @@ packages:
engines: {node: '>=12'}
hasBin: true
- esbuild@0.19.12:
- resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
- engines: {node: '>=12'}
- hasBin: true
-
esbuild@0.25.1:
resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==}
engines: {node: '>=18'}
@@ -2839,6 +2759,9 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
@@ -2897,8 +2820,8 @@ packages:
jiti:
optional: true
- eslint@9.25.1:
- resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==}
+ eslint@9.26.0:
+ resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
peerDependencies:
@@ -2930,6 +2853,10 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
event-pubsub@5.0.3:
resolution: {integrity: sha512-2QiHxshejKgJrYMzSI9MEHrvhmzxBL+eLyiM5IiyjDBySkgwS2+tdtnO3gbx8pEisu/yOFCIhfCb63gCEu0yBQ==}
engines: {node: '>=13.0.0'}
@@ -2937,6 +2864,14 @@ packages:
event-stream@3.3.4:
resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
+ eventsource-parser@3.0.1:
+ resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==}
+ engines: {node: '>=18.0.0'}
+
+ eventsource@3.0.7:
+ resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
+ engines: {node: '>=18.0.0'}
+
execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@@ -2949,6 +2884,16 @@ packages:
resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==}
engines: {node: '>=12.0.0'}
+ express-rate-limit@7.5.0:
+ resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: ^4.11 || 5 || ^5.0.0-beta.1
+
+ express@5.1.0:
+ resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
+ engines: {node: '>= 18'}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -3002,6 +2947,10 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
+ finalhandler@2.1.0:
+ resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==}
+ engines: {node: '>= 0.8'}
+
find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
@@ -3030,6 +2979,14 @@ packages:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
from@0.1.7:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
@@ -3113,6 +3070,10 @@ packages:
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
engines: {node: '>=18'}
+ globals@16.1.0:
+ resolution: {integrity: sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==}
+ engines: {node: '>=18'}
+
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
@@ -3162,6 +3123,10 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@@ -3173,10 +3138,18 @@ packages:
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
+ ignore@7.0.4:
+ resolution: {integrity: sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==}
+ engines: {node: '>= 4'}
+
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
@@ -3199,6 +3172,10 @@ packages:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@@ -3277,6 +3254,9 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -3398,8 +3378,8 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
- libsql@0.4.7:
- resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==}
+ libsql@0.5.8:
+ resolution: {integrity: sha512-+OopMI1wM/NvAJTHf3O3+beHd1YfKLnSVsOGBl3/7UBDZ4ydVadkbBk5Hjjs9d3ALC5rBaftMY59AvwyC8MzPw==}
cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32]
@@ -3537,8 +3517,8 @@ packages:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
- lucide-react@0.479.0:
- resolution: {integrity: sha512-aBhNnveRhorBOK7uA4gDjgaf+YlHMdMhQ/3cupk6exM10hWlEU+2QtWYOfhXhjAsmdb6LeKR+NZnow4UxRRiTQ==}
+ lucide-react@0.510.0:
+ resolution: {integrity: sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -3555,6 +3535,14 @@ packages:
mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -3566,6 +3554,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@3.0.1:
+ resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
+ engines: {node: '>= 0.6'}
+
mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
@@ -3603,6 +3599,10 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
next-themes@0.4.6:
resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
peerDependencies:
@@ -3633,6 +3633,7 @@ packages:
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
+ deprecated: Use your platform's native DOMException instead
node-fetch@3.3.2:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
@@ -3685,6 +3686,10 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -3736,6 +3741,10 @@ packages:
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
engines: {node: '>=18'}
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -3755,6 +3764,10 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ path-to-regexp@8.2.0:
+ resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
+ engines: {node: '>=16'}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -3780,6 +3793,10 @@ packages:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
+ pkce-challenge@5.0.0:
+ resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==}
+ engines: {node: '>=16.20.0'}
+
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
@@ -3818,6 +3835,10 @@ packages:
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
ps-tree@1.2.0:
resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
engines: {node: '>= 0.10'}
@@ -3827,9 +3848,21 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
+ qs@6.14.0:
+ resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+ engines: {node: '>=0.6'}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@3.0.0:
+ resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
+ engines: {node: '>= 0.8'}
+
react-dom@19.0.0:
resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
peerDependencies:
@@ -3943,6 +3976,10 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
rtl-css-js@1.16.1:
resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
@@ -3956,6 +3993,9 @@ packages:
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
safe-push-apply@1.0.0:
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
engines: {node: '>= 0.4'}
@@ -3964,6 +4004,9 @@ packages:
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
engines: {node: '>= 0.4'}
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
scheduler@0.25.0:
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
@@ -3985,6 +4028,19 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ send@1.2.0:
+ resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==}
+ engines: {node: '>= 18'}
+
+ serve-static@2.2.0:
+ resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
+ engines: {node: '>= 18'}
+
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@@ -4001,6 +4057,9 @@ packages:
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
engines: {node: '>= 0.4'}
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
sharp@0.33.5:
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@@ -4085,6 +4144,10 @@ packages:
stacktrace-js@2.0.2:
resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==}
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
std-env@3.8.1:
resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==}
@@ -4230,6 +4293,10 @@ packages:
toggle-selection@1.0.6:
resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
ts-api-utils@2.0.1:
resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
engines: {node: '>=18.12'}
@@ -4253,44 +4320,48 @@ packages:
engines: {node: '>=18.0.0'}
hasBin: true
- turbo-darwin-64@2.5.2:
- resolution: {integrity: sha512-2aIl0Sx230nLk+Cg2qSVxvPOBWCZpwKNuAMKoROTvWKif6VMpkWWiR9XEPoz7sHeLmCOed4GYGMjL1bqAiIS/g==}
+ turbo-darwin-64@2.5.3:
+ resolution: {integrity: sha512-YSItEVBUIvAGPUDpAB9etEmSqZI3T6BHrkBkeSErvICXn3dfqXUfeLx35LfptLDEbrzFUdwYFNmt8QXOwe9yaw==}
cpu: [x64]
os: [darwin]
- turbo-darwin-arm64@2.5.2:
- resolution: {integrity: sha512-MrFYhK/jYu8N6QlqZtqSHi3e4QVxlzqU3ANHTKn3/tThuwTLbNHEvzBPWSj5W7nZcM58dCqi6gYrfRz6bJZyAA==}
+ turbo-darwin-arm64@2.5.3:
+ resolution: {integrity: sha512-5PefrwHd42UiZX7YA9m1LPW6x9YJBDErXmsegCkVp+GjmWrADfEOxpFrGQNonH3ZMj77WZB2PVE5Aw3gA+IOhg==}
cpu: [arm64]
os: [darwin]
- turbo-linux-64@2.5.2:
- resolution: {integrity: sha512-LxNqUE2HmAJQ/8deoLgMUDzKxd5bKxqH0UBogWa+DF+JcXhtze3UTMr6lEr0dEofdsEUYK1zg8FRjglmwlN5YA==}
+ turbo-linux-64@2.5.3:
+ resolution: {integrity: sha512-M9xigFgawn5ofTmRzvjjLj3Lqc05O8VHKuOlWNUlnHPUltFquyEeSkpQNkE/vpPdOR14AzxqHbhhxtfS4qvb1w==}
cpu: [x64]
os: [linux]
- turbo-linux-arm64@2.5.2:
- resolution: {integrity: sha512-0MI1Ao1q8zhd+UUbIEsrM+yLq1BsrcJQRGZkxIsHFlGp7WQQH1oR3laBgfnUCNdCotCMD6w4moc9pUbXdOR3bg==}
+ turbo-linux-arm64@2.5.3:
+ resolution: {integrity: sha512-auJRbYZ8SGJVqvzTikpg1bsRAsiI9Tk0/SDkA5Xgg0GdiHDH/BOzv1ZjDE2mjmlrO/obr19Dw+39OlMhwLffrw==}
cpu: [arm64]
os: [linux]
- turbo-windows-64@2.5.2:
- resolution: {integrity: sha512-hOLcbgZzE5ttACHHyc1ajmWYq4zKT42IC3G6XqgiXxMbS+4eyVYTL+7UvCZBd3Kca1u4TLQdLQjeO76zyDJc2A==}
+ turbo-windows-64@2.5.3:
+ resolution: {integrity: sha512-arLQYohuHtIEKkmQSCU9vtrKUg+/1TTstWB9VYRSsz+khvg81eX6LYHtXJfH/dK7Ho6ck+JaEh5G+QrE1jEmCQ==}
cpu: [x64]
os: [win32]
- turbo-windows-arm64@2.5.2:
- resolution: {integrity: sha512-fMU41ABhSLa18H8V3Z7BMCGynQ8x+wj9WyBMvWm1jeyRKgkvUYJsO2vkIsy8m0vrwnIeVXKOIn6eSe1ddlBVqw==}
+ turbo-windows-arm64@2.5.3:
+ resolution: {integrity: sha512-3JPn66HAynJ0gtr6H+hjY4VHpu1RPKcEwGATvGUTmLmYSYBQieVlnGDRMMoYN066YfyPqnNGCfhYbXfH92Cm0g==}
cpu: [arm64]
os: [win32]
- turbo@2.5.2:
- resolution: {integrity: sha512-Qo5lfuStr6LQh3sPQl7kIi243bGU4aHGDQJUf6ylAdGwks30jJFloc9NYHP7Y373+gGU9OS0faA4Mb5Sy8X9Xw==}
+ turbo@2.5.3:
+ resolution: {integrity: sha512-iHuaNcq5GZZnr3XDZNuu2LSyCzAOPwDuo5Qt+q64DfsTP1i3T2bKfxJhni2ZQxsvAoxRbuUK5QetJki4qc5aYA==}
hasBin: true
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
@@ -4314,18 +4385,13 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- typescript-eslint@8.31.1:
- resolution: {integrity: sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==}
+ typescript-eslint@8.32.1:
+ resolution: {integrity: sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- typescript@5.8.2:
- resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
- engines: {node: '>=14.17'}
- hasBin: true
-
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
@@ -4342,6 +4408,10 @@ packages:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
untildify@4.0.0:
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
engines: {node: '>=8'}
@@ -4372,6 +4442,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
vaul@1.1.2:
resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==}
peerDependencies:
@@ -4547,9 +4621,17 @@ packages:
resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==}
engines: {node: '>=18'}
+ zod-to-json-schema@3.24.5:
+ resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
+ peerDependencies:
+ zod: ^3.24.1
+
zod@3.24.2:
resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
+ zod@3.24.4:
+ resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==}
+
snapshots:
'@alloc/quick-lru@5.2.0': {}
@@ -4566,7 +4648,7 @@ snapshots:
dependencies:
regenerator-runtime: 0.14.1
- '@dotenvx/dotenvx@1.41.0':
+ '@dotenvx/dotenvx@1.44.0':
dependencies:
commander: 11.1.0
dotenv: 16.5.0
@@ -4599,9 +4681,6 @@ snapshots:
'@esbuild-kit/core-utils': 3.3.2
get-tsconfig: 4.10.0
- '@esbuild/aix-ppc64@0.19.12':
- optional: true
-
'@esbuild/aix-ppc64@0.25.1':
optional: true
@@ -4611,9 +4690,6 @@ snapshots:
'@esbuild/android-arm64@0.18.20':
optional: true
- '@esbuild/android-arm64@0.19.12':
- optional: true
-
'@esbuild/android-arm64@0.25.1':
optional: true
@@ -4623,9 +4699,6 @@ snapshots:
'@esbuild/android-arm@0.18.20':
optional: true
- '@esbuild/android-arm@0.19.12':
- optional: true
-
'@esbuild/android-arm@0.25.1':
optional: true
@@ -4635,9 +4708,6 @@ snapshots:
'@esbuild/android-x64@0.18.20':
optional: true
- '@esbuild/android-x64@0.19.12':
- optional: true
-
'@esbuild/android-x64@0.25.1':
optional: true
@@ -4647,9 +4717,6 @@ snapshots:
'@esbuild/darwin-arm64@0.18.20':
optional: true
- '@esbuild/darwin-arm64@0.19.12':
- optional: true
-
'@esbuild/darwin-arm64@0.25.1':
optional: true
@@ -4659,9 +4726,6 @@ snapshots:
'@esbuild/darwin-x64@0.18.20':
optional: true
- '@esbuild/darwin-x64@0.19.12':
- optional: true
-
'@esbuild/darwin-x64@0.25.1':
optional: true
@@ -4671,9 +4735,6 @@ snapshots:
'@esbuild/freebsd-arm64@0.18.20':
optional: true
- '@esbuild/freebsd-arm64@0.19.12':
- optional: true
-
'@esbuild/freebsd-arm64@0.25.1':
optional: true
@@ -4683,9 +4744,6 @@ snapshots:
'@esbuild/freebsd-x64@0.18.20':
optional: true
- '@esbuild/freebsd-x64@0.19.12':
- optional: true
-
'@esbuild/freebsd-x64@0.25.1':
optional: true
@@ -4695,9 +4753,6 @@ snapshots:
'@esbuild/linux-arm64@0.18.20':
optional: true
- '@esbuild/linux-arm64@0.19.12':
- optional: true
-
'@esbuild/linux-arm64@0.25.1':
optional: true
@@ -4707,9 +4762,6 @@ snapshots:
'@esbuild/linux-arm@0.18.20':
optional: true
- '@esbuild/linux-arm@0.19.12':
- optional: true
-
'@esbuild/linux-arm@0.25.1':
optional: true
@@ -4719,9 +4771,6 @@ snapshots:
'@esbuild/linux-ia32@0.18.20':
optional: true
- '@esbuild/linux-ia32@0.19.12':
- optional: true
-
'@esbuild/linux-ia32@0.25.1':
optional: true
@@ -4731,9 +4780,6 @@ snapshots:
'@esbuild/linux-loong64@0.18.20':
optional: true
- '@esbuild/linux-loong64@0.19.12':
- optional: true
-
'@esbuild/linux-loong64@0.25.1':
optional: true
@@ -4743,9 +4789,6 @@ snapshots:
'@esbuild/linux-mips64el@0.18.20':
optional: true
- '@esbuild/linux-mips64el@0.19.12':
- optional: true
-
'@esbuild/linux-mips64el@0.25.1':
optional: true
@@ -4755,9 +4798,6 @@ snapshots:
'@esbuild/linux-ppc64@0.18.20':
optional: true
- '@esbuild/linux-ppc64@0.19.12':
- optional: true
-
'@esbuild/linux-ppc64@0.25.1':
optional: true
@@ -4767,9 +4807,6 @@ snapshots:
'@esbuild/linux-riscv64@0.18.20':
optional: true
- '@esbuild/linux-riscv64@0.19.12':
- optional: true
-
'@esbuild/linux-riscv64@0.25.1':
optional: true
@@ -4779,9 +4816,6 @@ snapshots:
'@esbuild/linux-s390x@0.18.20':
optional: true
- '@esbuild/linux-s390x@0.19.12':
- optional: true
-
'@esbuild/linux-s390x@0.25.1':
optional: true
@@ -4791,9 +4825,6 @@ snapshots:
'@esbuild/linux-x64@0.18.20':
optional: true
- '@esbuild/linux-x64@0.19.12':
- optional: true
-
'@esbuild/linux-x64@0.25.1':
optional: true
@@ -4809,9 +4840,6 @@ snapshots:
'@esbuild/netbsd-x64@0.18.20':
optional: true
- '@esbuild/netbsd-x64@0.19.12':
- optional: true
-
'@esbuild/netbsd-x64@0.25.1':
optional: true
@@ -4827,9 +4855,6 @@ snapshots:
'@esbuild/openbsd-x64@0.18.20':
optional: true
- '@esbuild/openbsd-x64@0.19.12':
- optional: true
-
'@esbuild/openbsd-x64@0.25.1':
optional: true
@@ -4839,9 +4864,6 @@ snapshots:
'@esbuild/sunos-x64@0.18.20':
optional: true
- '@esbuild/sunos-x64@0.19.12':
- optional: true
-
'@esbuild/sunos-x64@0.25.1':
optional: true
@@ -4851,9 +4873,6 @@ snapshots:
'@esbuild/win32-arm64@0.18.20':
optional: true
- '@esbuild/win32-arm64@0.19.12':
- optional: true
-
'@esbuild/win32-arm64@0.25.1':
optional: true
@@ -4863,9 +4882,6 @@ snapshots:
'@esbuild/win32-ia32@0.18.20':
optional: true
- '@esbuild/win32-ia32@0.19.12':
- optional: true
-
'@esbuild/win32-ia32@0.25.1':
optional: true
@@ -4875,9 +4891,6 @@ snapshots:
'@esbuild/win32-x64@0.18.20':
optional: true
- '@esbuild/win32-x64@0.19.12':
- optional: true
-
'@esbuild/win32-x64@0.25.1':
optional: true
@@ -4894,9 +4907,9 @@ snapshots:
eslint: 9.22.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
- '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@2.4.2))':
+ '@eslint-community/eslint-utils@4.7.0(eslint@9.26.0(jiti@2.4.2))':
dependencies:
- eslint: 9.25.1(jiti@2.4.2)
+ eslint: 9.26.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
@@ -4919,7 +4932,7 @@ snapshots:
'@eslint/config-helpers@0.1.0': {}
- '@eslint/config-helpers@0.2.1': {}
+ '@eslint/config-helpers@0.2.2': {}
'@eslint/core@0.12.0':
dependencies:
@@ -4959,7 +4972,7 @@ snapshots:
'@eslint/js@9.22.0': {}
- '@eslint/js@9.25.1': {}
+ '@eslint/js@9.26.0': {}
'@eslint/object-schema@2.1.6': {}
@@ -5008,6 +5021,8 @@ snapshots:
'@humanwhocodes/retry@0.4.2': {}
+ '@humanwhocodes/retry@0.4.3': {}
+
'@img/sharp-darwin-arm64@0.33.5':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.4
@@ -5085,25 +5100,25 @@ snapshots:
'@jridgewell/sourcemap-codec@1.5.0': {}
- '@libsql/client@0.14.0':
+ '@libsql/client@0.15.4':
dependencies:
- '@libsql/core': 0.14.0
+ '@libsql/core': 0.15.4
'@libsql/hrana-client': 0.7.0
js-base64: 3.7.7
- libsql: 0.4.7
+ libsql: 0.5.8
promise-limit: 2.7.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
- '@libsql/core@0.14.0':
+ '@libsql/core@0.15.4':
dependencies:
js-base64: 3.7.7
- '@libsql/darwin-arm64@0.4.7':
+ '@libsql/darwin-arm64@0.5.8':
optional: true
- '@libsql/darwin-x64@0.4.7':
+ '@libsql/darwin-x64@0.5.8':
optional: true
'@libsql/hrana-client@0.7.0':
@@ -5126,21 +5141,36 @@ snapshots:
- bufferutil
- utf-8-validate
- '@libsql/linux-arm64-gnu@0.4.7':
+ '@libsql/linux-arm64-gnu@0.5.8':
optional: true
- '@libsql/linux-arm64-musl@0.4.7':
+ '@libsql/linux-arm64-musl@0.5.8':
optional: true
- '@libsql/linux-x64-gnu@0.4.7':
+ '@libsql/linux-x64-gnu@0.5.8':
optional: true
- '@libsql/linux-x64-musl@0.4.7':
+ '@libsql/linux-x64-musl@0.5.8':
optional: true
- '@libsql/win32-x64-msvc@0.4.7':
+ '@libsql/win32-x64-msvc@0.5.8':
optional: true
+ '@modelcontextprotocol/sdk@1.11.2':
+ dependencies:
+ content-type: 1.0.5
+ cors: 2.8.5
+ cross-spawn: 7.0.6
+ eventsource: 3.0.7
+ express: 5.1.0
+ express-rate-limit: 7.5.0(express@5.1.0)
+ pkce-challenge: 5.0.0
+ raw-body: 3.0.0
+ zod: 3.24.4
+ zod-to-json-schema: 3.24.5(zod@3.24.4)
+ transitivePeerDependencies:
+ - supports-color
+
'@neon-rs/load@0.0.4': {}
'@next/env@15.2.2': {}
@@ -5193,7 +5223,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
- '@petamoriken/float16@3.9.2': {}
+ '@petamoriken/float16@3.9.2':
+ optional: true
'@radix-ui/number@1.1.0': {}
@@ -6016,60 +6047,60 @@ snapshots:
dependencies:
'@types/node': 20.17.24
- '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.26.1
- '@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.26.1
eslint: 9.22.0(jiti@2.4.2)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
- ts-api-utils: 2.0.1(typescript@5.8.2)
- typescript: 5.8.2
+ ts-api-utils: 2.0.1(typescript@5.8.3)
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)':
+ '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- '@typescript-eslint/scope-manager': 8.31.1
- '@typescript-eslint/type-utils': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- '@typescript-eslint/utils': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- '@typescript-eslint/visitor-keys': 8.31.1
- eslint: 9.25.1(jiti@2.4.2)
+ '@typescript-eslint/parser': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/type-utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.32.1
+ eslint: 9.26.0(jiti@2.4.2)
graphemer: 1.4.0
- ignore: 5.3.2
+ ignore: 7.0.4
natural-compare: 1.4.0
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/types': 8.26.1
- '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
+ '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.26.1
debug: 4.4.0
eslint: 9.22.0(jiti@2.4.2)
- typescript: 5.8.2
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)':
+ '@typescript-eslint/parser@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/scope-manager': 8.31.1
- '@typescript-eslint/types': 8.31.1
- '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
- '@typescript-eslint/visitor-keys': 8.31.1
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
+ '@typescript-eslint/visitor-keys': 8.32.1
debug: 4.4.0
- eslint: 9.25.1(jiti@2.4.2)
+ eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@@ -6079,28 +6110,28 @@ snapshots:
'@typescript-eslint/types': 8.26.1
'@typescript-eslint/visitor-keys': 8.26.1
- '@typescript-eslint/scope-manager@8.31.1':
+ '@typescript-eslint/scope-manager@8.32.1':
dependencies:
- '@typescript-eslint/types': 8.31.1
- '@typescript-eslint/visitor-keys': 8.31.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/visitor-keys': 8.32.1
- '@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
- '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
debug: 4.4.0
eslint: 9.22.0(jiti@2.4.2)
- ts-api-utils: 2.0.1(typescript@5.8.2)
- typescript: 5.8.2
+ ts-api-utils: 2.0.1(typescript@5.8.3)
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)':
+ '@typescript-eslint/type-utils@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
- '@typescript-eslint/utils': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
debug: 4.4.0
- eslint: 9.25.1(jiti@2.4.2)
+ eslint: 9.26.0(jiti@2.4.2)
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
@@ -6108,9 +6139,9 @@ snapshots:
'@typescript-eslint/types@8.26.1': {}
- '@typescript-eslint/types@8.31.1': {}
+ '@typescript-eslint/types@8.32.1': {}
- '@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.2)':
+ '@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.3)':
dependencies:
'@typescript-eslint/types': 8.26.1
'@typescript-eslint/visitor-keys': 8.26.1
@@ -6119,43 +6150,43 @@ snapshots:
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.1
- ts-api-utils: 2.0.1(typescript@5.8.2)
- typescript: 5.8.2
+ ts-api-utils: 2.1.0(typescript@5.8.3)
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/typescript-estree@8.31.1(typescript@5.8.3)':
+ '@typescript-eslint/typescript-estree@8.32.1(typescript@5.8.3)':
dependencies:
- '@typescript-eslint/types': 8.31.1
- '@typescript-eslint/visitor-keys': 8.31.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/visitor-keys': 8.32.1
debug: 4.4.0
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
- semver: 7.7.1
+ semver: 7.7.2
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+ '@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.6.1(eslint@9.22.0(jiti@2.4.2))
'@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/types': 8.26.1
- '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
+ '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
- typescript: 5.8.2
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)':
+ '@typescript-eslint/utils@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.4.2))
- '@typescript-eslint/scope-manager': 8.31.1
- '@typescript-eslint/types': 8.31.1
- '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3)
- eslint: 9.25.1(jiti@2.4.2)
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2))
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3)
+ eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@@ -6165,9 +6196,9 @@ snapshots:
'@typescript-eslint/types': 8.26.1
eslint-visitor-keys: 4.2.0
- '@typescript-eslint/visitor-keys@8.31.1':
+ '@typescript-eslint/visitor-keys@8.32.1':
dependencies:
- '@typescript-eslint/types': 8.31.1
+ '@typescript-eslint/types': 8.32.1
eslint-visitor-keys: 4.2.0
'@vitest/expect@3.0.9':
@@ -6212,6 +6243,11 @@ snapshots:
'@xobotyi/scrollbar-width@1.9.5': {}
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.1
+ negotiator: 1.0.0
+
acorn-jsx@5.3.2(acorn@8.14.1):
dependencies:
acorn: 8.14.1
@@ -6326,6 +6362,20 @@ snapshots:
balanced-match@1.0.2: {}
+ body-parser@2.2.0:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.0
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ on-finished: 2.4.1
+ qs: 6.14.0
+ raw-body: 3.0.0
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
@@ -6345,6 +6395,8 @@ snapshots:
dependencies:
streamsearch: 1.1.0
+ bytes@3.1.2: {}
+
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
@@ -6460,6 +6512,16 @@ snapshots:
concat-map@0.0.1: {}
+ content-disposition@1.0.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ content-type@1.0.5: {}
+
+ cookie-signature@1.2.2: {}
+
+ cookie@0.7.2: {}
+
copy-to-clipboard@3.3.3:
dependencies:
toggle-selection: 1.0.6
@@ -6476,6 +6538,11 @@ snapshots:
core-util-is@1.0.3: {}
+ cors@2.8.5:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
cosmiconfig@7.0.1:
dependencies:
'@types/parse-json': 4.0.2
@@ -6531,6 +6598,11 @@ snapshots:
dependencies:
ms: 2.1.3
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+ optional: true
+
deep-eql@5.0.2: {}
deep-is@0.1.4: {}
@@ -6551,6 +6623,8 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
+ depd@2.0.0: {}
+
detect-libc@2.0.2: {}
detect-libc@2.0.3: {}
@@ -6565,24 +6639,23 @@ snapshots:
dotenv@16.5.0: {}
- drizzle-kit@0.30.5:
+ drizzle-kit@0.31.1:
dependencies:
'@drizzle-team/brocli': 0.10.2
'@esbuild-kit/esm-loader': 2.6.5
- esbuild: 0.19.12
- esbuild-register: 3.6.0(esbuild@0.19.12)
- gel: 2.0.1
+ esbuild: 0.25.3
+ esbuild-register: 3.6.0(esbuild@0.25.3)
transitivePeerDependencies:
- supports-color
- drizzle-orm@0.40.1(@libsql/client@0.14.0)(gel@2.0.1):
+ drizzle-orm@0.43.1(@libsql/client@0.15.4)(gel@2.0.1):
optionalDependencies:
- '@libsql/client': 0.14.0
+ '@libsql/client': 0.15.4
gel: 2.0.1
- drizzle-zod@0.7.0(drizzle-orm@0.40.1(@libsql/client@0.14.0)(gel@2.0.1))(zod@3.24.2):
+ drizzle-zod@0.7.0(drizzle-orm@0.43.1(@libsql/client@0.15.4)(gel@2.0.1))(zod@3.24.2):
dependencies:
- drizzle-orm: 0.40.1(@libsql/client@0.14.0)(gel@2.0.1)
+ drizzle-orm: 0.43.1(@libsql/client@0.15.4)(gel@2.0.1)
zod: 3.24.2
dunder-proto@1.0.1:
@@ -6602,12 +6675,16 @@ snapshots:
'@noble/curves': 1.9.0
'@noble/hashes': 1.8.0
+ ee-first@1.1.1: {}
+
ejs@3.1.8:
dependencies:
jake: 10.9.2
emoji-regex@8.0.0: {}
+ encodeurl@2.0.0: {}
+
enhanced-resolve@5.18.1:
dependencies:
graceful-fs: 4.2.11
@@ -6617,7 +6694,8 @@ snapshots:
dependencies:
ansi-colors: 4.1.3
- env-paths@3.0.0: {}
+ env-paths@3.0.0:
+ optional: true
error-ex@1.3.2:
dependencies:
@@ -6727,10 +6805,10 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
- esbuild-register@3.6.0(esbuild@0.19.12):
+ esbuild-register@3.6.0(esbuild@0.25.3):
dependencies:
debug: 4.4.0
- esbuild: 0.19.12
+ esbuild: 0.25.3
transitivePeerDependencies:
- supports-color
@@ -6759,32 +6837,6 @@ snapshots:
'@esbuild/win32-ia32': 0.18.20
'@esbuild/win32-x64': 0.18.20
- esbuild@0.19.12:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.19.12
- '@esbuild/android-arm': 0.19.12
- '@esbuild/android-arm64': 0.19.12
- '@esbuild/android-x64': 0.19.12
- '@esbuild/darwin-arm64': 0.19.12
- '@esbuild/darwin-x64': 0.19.12
- '@esbuild/freebsd-arm64': 0.19.12
- '@esbuild/freebsd-x64': 0.19.12
- '@esbuild/linux-arm': 0.19.12
- '@esbuild/linux-arm64': 0.19.12
- '@esbuild/linux-ia32': 0.19.12
- '@esbuild/linux-loong64': 0.19.12
- '@esbuild/linux-mips64el': 0.19.12
- '@esbuild/linux-ppc64': 0.19.12
- '@esbuild/linux-riscv64': 0.19.12
- '@esbuild/linux-s390x': 0.19.12
- '@esbuild/linux-x64': 0.19.12
- '@esbuild/netbsd-x64': 0.19.12
- '@esbuild/openbsd-x64': 0.19.12
- '@esbuild/sunos-x64': 0.19.12
- '@esbuild/win32-arm64': 0.19.12
- '@esbuild/win32-ia32': 0.19.12
- '@esbuild/win32-x64': 0.19.12
-
esbuild@0.25.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.1
@@ -6843,6 +6895,8 @@ snapshots:
escalade@3.2.0: {}
+ escape-html@1.0.3: {}
+
escape-string-regexp@1.0.5: {}
escape-string-regexp@4.0.0: {}
@@ -6879,11 +6933,11 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
- eslint-plugin-turbo@2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.5.2):
+ eslint-plugin-turbo@2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.5.3):
dependencies:
dotenv: 16.0.3
eslint: 9.22.0(jiti@2.4.2)
- turbo: 2.5.2
+ turbo: 2.5.3
eslint-scope@8.3.0:
dependencies:
@@ -6936,19 +6990,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint@9.25.1(jiti@2.4.2):
+ eslint@9.26.0(jiti@2.4.2):
dependencies:
- '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.4.2))
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2))
'@eslint-community/regexpp': 4.12.1
'@eslint/config-array': 0.20.0
- '@eslint/config-helpers': 0.2.1
+ '@eslint/config-helpers': 0.2.2
'@eslint/core': 0.13.0
'@eslint/eslintrc': 3.3.1
- '@eslint/js': 9.25.1
+ '@eslint/js': 9.26.0
'@eslint/plugin-kit': 0.2.8
'@humanfs/node': 0.16.6
'@humanwhocodes/module-importer': 1.0.1
- '@humanwhocodes/retry': 0.4.2
+ '@humanwhocodes/retry': 0.4.3
+ '@modelcontextprotocol/sdk': 1.11.2
'@types/estree': 1.0.7
'@types/json-schema': 7.0.15
ajv: 6.12.6
@@ -6973,6 +7028,7 @@ snapshots:
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.4
+ zod: 3.24.4
optionalDependencies:
jiti: 2.4.2
transitivePeerDependencies:
@@ -7000,6 +7056,8 @@ snapshots:
esutils@2.0.3: {}
+ etag@1.8.1: {}
+
event-pubsub@5.0.3:
dependencies:
copyfiles: 2.4.1
@@ -7015,6 +7073,12 @@ snapshots:
stream-combiner: 0.0.4
through: 2.3.8
+ eventsource-parser@3.0.1: {}
+
+ eventsource@3.0.7:
+ dependencies:
+ eventsource-parser: 3.0.1
+
execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
@@ -7044,6 +7108,42 @@ snapshots:
expect-type@1.2.0: {}
+ express-rate-limit@7.5.0(express@5.1.0):
+ dependencies:
+ express: 5.1.0
+
+ express@5.1.0:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.0
+ content-disposition: 1.0.0
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.0
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.1
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.14.0
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.0
+ serve-static: 2.2.0
+ statuses: 2.0.1
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
fast-deep-equal@3.1.3: {}
fast-glob@3.3.1:
@@ -7099,6 +7199,17 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
+ finalhandler@2.1.0:
+ dependencies:
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
@@ -7121,6 +7232,10 @@ snapshots:
dependencies:
fetch-blob: 3.2.0
+ forwarded@0.2.0: {}
+
+ fresh@2.0.0: {}
+
from@0.1.7: {}
fs-jetpack@4.3.1:
@@ -7151,13 +7266,14 @@ snapshots:
gel@2.0.1:
dependencies:
'@petamoriken/float16': 3.9.2
- debug: 4.4.0
+ debug: 4.4.1
env-paths: 3.0.0
- semver: 7.7.1
+ semver: 7.7.2
shell-quote: 1.8.2
which: 4.0.0
transitivePeerDependencies:
- supports-color
+ optional: true
get-caller-file@2.0.5: {}
@@ -7219,6 +7335,8 @@ snapshots:
globals@16.0.0: {}
+ globals@16.1.0: {}
+
globalthis@1.0.4:
dependencies:
define-properties: 1.2.1
@@ -7289,14 +7407,28 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
human-signals@2.1.0: {}
human-signals@8.0.0: {}
hyphenate-style-name@1.1.0: {}
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
ignore@5.3.2: {}
+ ignore@7.0.4: {}
+
import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
@@ -7321,6 +7453,8 @@ snapshots:
hasown: 2.0.2
side-channel: 1.1.0
+ ipaddr.js@1.9.1: {}
+
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@@ -7398,6 +7532,8 @@ snapshots:
is-plain-obj@4.1.0: {}
+ is-promise@4.0.0: {}
+
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -7511,18 +7647,18 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- libsql@0.4.7:
+ libsql@0.5.8:
dependencies:
'@neon-rs/load': 0.0.4
detect-libc: 2.0.2
optionalDependencies:
- '@libsql/darwin-arm64': 0.4.7
- '@libsql/darwin-x64': 0.4.7
- '@libsql/linux-arm64-gnu': 0.4.7
- '@libsql/linux-arm64-musl': 0.4.7
- '@libsql/linux-x64-gnu': 0.4.7
- '@libsql/linux-x64-musl': 0.4.7
- '@libsql/win32-x64-msvc': 0.4.7
+ '@libsql/darwin-arm64': 0.5.8
+ '@libsql/darwin-x64': 0.5.8
+ '@libsql/linux-arm64-gnu': 0.5.8
+ '@libsql/linux-arm64-musl': 0.5.8
+ '@libsql/linux-x64-gnu': 0.5.8
+ '@libsql/linux-x64-musl': 0.5.8
+ '@libsql/win32-x64-msvc': 0.5.8
lightningcss-darwin-arm64@1.29.2:
optional: true
@@ -7621,7 +7757,7 @@ snapshots:
dependencies:
yallist: 4.0.0
- lucide-react@0.479.0(react@19.0.0):
+ lucide-react@0.510.0(react@19.0.0):
dependencies:
react: 19.0.0
@@ -7635,6 +7771,10 @@ snapshots:
mdn-data@2.0.14: {}
+ media-typer@1.1.0: {}
+
+ merge-descriptors@2.0.0: {}
+
merge-stream@2.0.0: {}
merge2@1.4.1: {}
@@ -7644,6 +7784,12 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
+ mime-db@1.54.0: {}
+
+ mime-types@3.0.1:
+ dependencies:
+ mime-db: 1.54.0
+
mimic-fn@2.1.0: {}
minimatch@3.1.2:
@@ -7679,6 +7825,8 @@ snapshots:
natural-compare@1.4.0: {}
+ negotiator@1.0.0: {}
+
next-themes@0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
react: 19.0.0
@@ -7776,6 +7924,10 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -7838,6 +7990,8 @@ snapshots:
parse-ms@4.0.0: {}
+ parseurl@1.3.3: {}
+
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
@@ -7848,6 +8002,8 @@ snapshots:
path-parse@1.0.7: {}
+ path-to-regexp@8.2.0: {}
+
path-type@4.0.0: {}
pathe@2.0.3: {}
@@ -7864,6 +8020,8 @@ snapshots:
picomatch@4.0.2: {}
+ pkce-challenge@5.0.0: {}
+
pluralize@8.0.0: {}
possible-typed-array-names@1.1.0: {}
@@ -7898,14 +8056,32 @@ snapshots:
object-assign: 4.1.1
react-is: 16.13.1
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
ps-tree@1.2.0:
dependencies:
event-stream: 3.3.4
punycode@2.3.1: {}
+ qs@6.14.0:
+ dependencies:
+ side-channel: 1.1.0
+
queue-microtask@1.2.3: {}
+ range-parser@1.2.1: {}
+
+ raw-body@3.0.0:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.6.3
+ unpipe: 1.0.0
+
react-dom@19.0.0(react@19.0.0):
dependencies:
react: 19.0.0
@@ -8060,6 +8236,16 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.38.0
fsevents: 2.3.3
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.0
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.2.0
+ transitivePeerDependencies:
+ - supports-color
+
rtl-css-js@1.16.1:
dependencies:
'@babel/runtime': 7.26.10
@@ -8078,6 +8264,8 @@ snapshots:
safe-buffer@5.1.2: {}
+ safe-buffer@5.2.1: {}
+
safe-push-apply@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -8089,6 +8277,8 @@ snapshots:
es-errors: 1.3.0
is-regex: 1.2.1
+ safer-buffer@2.1.2: {}
+
scheduler@0.25.0: {}
screenfull@5.2.0: {}
@@ -8101,6 +8291,33 @@ snapshots:
semver@7.7.1: {}
+ semver@7.7.2: {}
+
+ send@1.2.0:
+ dependencies:
+ debug: 4.4.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.0
+ mime-types: 3.0.1
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@2.2.0:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.0
+ transitivePeerDependencies:
+ - supports-color
+
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
@@ -8125,6 +8342,8 @@ snapshots:
es-errors: 1.3.0
es-object-atoms: 1.1.1
+ setprototypeof@1.2.0: {}
+
sharp@0.33.5:
dependencies:
color: 4.2.3
@@ -8158,7 +8377,8 @@ snapshots:
shebang-regex@3.0.0: {}
- shell-quote@1.8.2: {}
+ shell-quote@1.8.2:
+ optional: true
side-channel-list@1.0.0:
dependencies:
@@ -8238,6 +8458,8 @@ snapshots:
stack-generator: 2.0.10
stacktrace-gps: 3.1.2
+ statuses@2.0.1: {}
+
std-env@3.8.1: {}
stream-combiner@0.0.4:
@@ -8372,9 +8594,11 @@ snapshots:
toggle-selection@1.0.6: {}
- ts-api-utils@2.0.1(typescript@5.8.2):
+ toidentifier@1.0.1: {}
+
+ ts-api-utils@2.0.1(typescript@5.8.3):
dependencies:
- typescript: 5.8.2
+ typescript: 5.8.3
ts-api-utils@2.1.0(typescript@5.8.3):
dependencies:
@@ -8391,37 +8615,43 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
- turbo-darwin-64@2.5.2:
+ turbo-darwin-64@2.5.3:
optional: true
- turbo-darwin-arm64@2.5.2:
+ turbo-darwin-arm64@2.5.3:
optional: true
- turbo-linux-64@2.5.2:
+ turbo-linux-64@2.5.3:
optional: true
- turbo-linux-arm64@2.5.2:
+ turbo-linux-arm64@2.5.3:
optional: true
- turbo-windows-64@2.5.2:
+ turbo-windows-64@2.5.3:
optional: true
- turbo-windows-arm64@2.5.2:
+ turbo-windows-arm64@2.5.3:
optional: true
- turbo@2.5.2:
+ turbo@2.5.3:
optionalDependencies:
- turbo-darwin-64: 2.5.2
- turbo-darwin-arm64: 2.5.2
- turbo-linux-64: 2.5.2
- turbo-linux-arm64: 2.5.2
- turbo-windows-64: 2.5.2
- turbo-windows-arm64: 2.5.2
+ turbo-darwin-64: 2.5.3
+ turbo-darwin-arm64: 2.5.3
+ turbo-linux-64: 2.5.3
+ turbo-linux-arm64: 2.5.3
+ turbo-windows-64: 2.5.3
+ turbo-windows-arm64: 2.5.3
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.1
+
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
@@ -8455,28 +8685,26 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
- typescript-eslint@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
+ typescript-eslint@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
- '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+ '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
- typescript: 5.8.2
+ typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- typescript-eslint@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3):
+ typescript-eslint@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3))(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- '@typescript-eslint/parser': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- '@typescript-eslint/utils': 8.31.1(eslint@9.25.1(jiti@2.4.2))(typescript@5.8.3)
- eslint: 9.25.1(jiti@2.4.2)
+ '@typescript-eslint/eslint-plugin': 8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/parser': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)
+ eslint: 9.26.0(jiti@2.4.2)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
- typescript@5.8.2: {}
-
typescript@5.8.3: {}
unbox-primitive@1.1.0:
@@ -8490,6 +8718,8 @@ snapshots:
unicorn-magic@0.3.0: {}
+ unpipe@1.0.0: {}
+
untildify@4.0.0: {}
uri-js@4.4.1:
@@ -8513,6 +8743,8 @@ snapshots:
util-deprecate@1.0.2: {}
+ vary@1.1.2: {}
+
vaul@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@radix-ui/react-dialog': 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -8691,4 +8923,10 @@ snapshots:
yoctocolors@2.1.1: {}
+ zod-to-json-schema@3.24.5(zod@3.24.4):
+ dependencies:
+ zod: 3.24.4
+
zod@3.24.2: {}
+
+ zod@3.24.4: {}
diff --git a/evals/scripts/setup.sh b/evals/scripts/setup.sh
index f58f80793e9..de3c05393a9 100755
--- a/evals/scripts/setup.sh
+++ b/evals/scripts/setup.sh
@@ -286,35 +286,49 @@ fi
# To reset VSCode:
# rm -rvf ~/.vscode && rm -rvf ~/Library/Application\ Support/Code
-echo "🔌 Installing Visual Studio Code extensions..."
+echo -n "🔌 Installing Visual Studio Code extensions... "
code --install-extension golang.go &>/dev/null || exit 1
code --install-extension dbaeumer.vscode-eslint&>/dev/null || exit 1
code --install-extension redhat.java &>/dev/null || exit 1
code --install-extension ms-python.python&>/dev/null || exit 1
code --install-extension rust-lang.rust-analyzer &>/dev/null || exit 1
-code --install-extension rooveterinaryinc.roo-cline &>/dev/null || exit 1
+
+if ! code --list-extensions 2>/dev/null | grep -q "rooveterinaryinc.roo-cline"; then
+ code --install-extension rooveterinaryinc.roo-cline &>/dev/null || exit 1
+fi
+
+echo "✅ Done"
if [[ ! -d "../../evals" ]]; then
- if gh auth status &>/dev/null; then
- read -p "🔗 Would you like to be able to share eval results? (Y/n): " fork_evals
+ echo -n "🔗 Cloning evals repository... "
- if [[ "$fork_evals" =~ ^[Yy]|^$ ]]; then
- gh repo fork cte/evals --clone ../../evals || exit 1
- else
- gh repo clone cte/evals ../../evals || exit 1
- fi
+ if gh auth status &>/dev/null; then
+ gh repo clone cte/evals ../../evals || exit 1
else
git clone https://github.com/cte/evals.git ../../evals || exit 1
fi
+
+ echo "✅ Done"
+else
+ echo -n "🔄 Updating evals repository... "
+
+ (cd ../../evals && \
+ git checkout -f &>/dev/null && \
+ git clean -f -d &>/dev/null && \
+ git checkout main &>/dev/null && \
+ git pull &>/dev/null) || { echo "❌ Failed to update evals repository."; exit 1; }
+
+ echo "✅ Done"
fi
if [[ ! -s .env ]]; then
cp .env.sample .env || exit 1
fi
-echo "🗄️ Syncing Roo Code evals database..."
+echo -n "🗄️ Syncing Roo Code evals database... "
pnpm --filter @evals/db db:push &>/dev/null || exit 1
pnpm --filter @evals/db db:enable-wal &>/dev/null || exit 1
+echo "✅ Done"
if ! grep -q "OPENROUTER_API_KEY" .env; then
read -p "🔐 Enter your OpenRouter API key (sk-or-v1-...): " openrouter_api_key
@@ -323,14 +337,11 @@ if ! grep -q "OPENROUTER_API_KEY" .env; then
echo "OPENROUTER_API_KEY=$openrouter_api_key" >> .env || exit 1
fi
-if [[ ! -s "../bin/roo-code-latest.vsix" ]]; then
- build_extension
-else
- read -p "💻 Do you want to build a new version of the Roo Code extension? (y/N): " build_extension
+current_version=$(code --list-extensions --show-versions 2>/dev/null | grep roo)
+read -p "💻 Do you want to build a new version of the Roo Code extension? [currently $current_version] (y/N): " build_extension
- if [[ "$build_extension" =~ ^[Yy]$ ]]; then
- build_extension
- fi
+if [[ "$build_extension" =~ ^[Yy]$ ]]; then
+ build_extension
fi
echo -e "\n🚀 You're ready to rock and roll! \n"
diff --git a/git b/git
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/jest.config.js b/jest.config.js
index cd4944c5477..e05776918e9 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -14,7 +14,6 @@ module.exports = {
allowJs: true,
},
diagnostics: false,
- isolatedModules: true,
},
],
},
diff --git a/locales/ca/CODE_OF_CONDUCT.md b/locales/ca/CODE_OF_CONDUCT.md
index a433818592e..0d572628186 100644
--- a/locales/ca/CODE_OF_CONDUCT.md
+++ b/locales/ca/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • Català • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Codi de Conducta del Pacte de Col·laboradors
## El nostre Compromís
diff --git a/locales/ca/CONTRIBUTING.md b/locales/ca/CONTRIBUTING.md
index 5f2beefc79e..41a227c497c 100644
--- a/locales/ca/CONTRIBUTING.md
+++ b/locales/ca/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Contribuir a Roo Code
-
-Estem entusiasmats que estigueu interessats en contribuir a Roo Code. Ja sigui arreglant un error, afegint una funcionalitat o millorant la nostra documentació, cada contribució fa que Roo Code sigui més intel·ligent! Per mantenir la nostra comunitat vibrant i acollidora, tots els membres han de complir el nostre [Codi de Conducta](CODE_OF_CONDUCT.md).
-
-## Uniu-vos a la nostra comunitat
-
-Encoratgem fortament a tots els col·laboradors a unir-se a la nostra [comunitat de Discord](https://discord.gg/roocode)! Formar part del nostre servidor de Discord us ajuda a:
-
-- Obtenir ajuda i orientació en temps real sobre les vostres contribucions
-- Connectar amb altres col·laboradors i membres de l'equip principal
-- Mantenir-vos al dia sobre els desenvolupaments i prioritats del projecte
-- Participar en discussions que configuren el futur de Roo Code
-- Trobar oportunitats de col·laboració amb altres desenvolupadors
+[English](../../CONTRIBUTING.md) • Català • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Informar d'errors o problemes
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Els informes d'errors ajuden a millorar Roo Code per a tothom! Abans de crear un nou informe, si us plau [cerqueu entre els existents](https://github.com/RooVetGit/Roo-Code/issues) per evitar duplicats. Quan estigueu a punt per informar d'un error, dirigiu-vos a la nostra [pàgina d'incidències](https://github.com/RooVetGit/Roo-Code/issues/new/choose) on trobareu una plantilla per ajudar-vos a completar la informació rellevant.
-
-
- 🔐 Important: Si descobriu una vulnerabilitat de seguretat, utilitzeu l'eina de seguretat de Github per informar-ne privadament.
-
+# Contribuir a Roo Code
-## Decidir en què treballar
+Roo Code és un projecte impulsat per la comunitat i valorem molt cada contribució. Per simplificar la col·laboració, treballem amb un enfoc [Issue-First](#enfoc-issue-first), que significa que tots els [Pull Requests (PRs)](#enviar-un-pull-request) han d'estar primer vinculats a una Issue de GitHub. Si us plau, llegeix aquesta guia amb atenció.
-Buscant una bona primera contribució? Consulteu les incidències a la secció "Issue [Unassigned]" del nostre [Projecte de Github de Roo Code](https://github.com/orgs/RooVetGit/projects/1). Aquestes estan específicament seleccionades per a nous col·laboradors i àrees on ens encantaria rebre ajuda!
+## Taula de continguts
-També donem la benvinguda a contribucions a la nostra [documentació](https://docs.roocode.com/)! Ja sigui corregint errors tipogràfics, millorant guies existents o creant nou contingut educatiu - ens encantaria construir un repositori de recursos impulsat per la comunitat que ajudi a tothom a aprofitar al màxim Roo Code. Podeu fer clic a "Editar aquesta pàgina" a qualsevol pàgina per arribar ràpidament al lloc correcte a Github per editar el fitxer, o podeu anar directament a https://github.com/RooVetGit/Roo-Code-Docs.
+- [Abans de contribuir](#abans-de-contribuir)
+- [Trobar i planificar la teva contribució](#trobar-i-planificar-la-teva-contribució)
+- [Procés de desenvolupament i enviament](#procés-de-desenvolupament-i-enviament)
+- [Legal](#legal)
-Si esteu planejant treballar en una funcionalitat més gran, si us plau creeu primer una [sol·licitud de funcionalitat](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) perquè puguem discutir si s'alinea amb la visió de Roo Code. També podeu consultar el nostre [Full de Ruta del Projecte](#full-de-ruta-del-projecte) a continuació per veure si la vostra idea s'ajusta a la nostra direcció estratègica.
+## Abans de contribuir
-## Full de Ruta del Projecte
+### 1. Codi de conducta
-Roo Code té un full de ruta de desenvolupament clar que guia les nostres prioritats i direcció futura. Entendre el nostre full de ruta us pot ajudar a:
+Tots els col·laboradors han de complir el nostre [Codi de conducta](./CODE_OF_CONDUCT.md).
-- Alinear les vostres contribucions amb els objectius del projecte
-- Identificar àrees on la vostra experiència seria més valuosa
-- Entendre el context darrere de certes decisions de disseny
-- Trobar inspiració per a noves funcionalitats que donin suport a la nostra visió
+### 2. Fulla de ruta del projecte
-El nostre full de ruta actual se centra en sis pilars clau:
+La nostra fulla de ruta orienta la direcció del projecte. Alinea les teves contribucions amb aquests objectius clau:
-### Suport de Proveïdors
+### Fiabilitat primer
-Aspirem a donar suport a tants proveïdors com sigui possible:
+- Garantir que l'edició de diferències i l'execució de comandes siguin consistentment fiables
+- Reduir els punts de fricció que desanimen l'ús regular
+- Garantir un funcionament fluid en tots els idiomes i plataformes
+- Ampliar el suport robust per a una àmplia varietat de proveïdors i models d'IA
-- Suport més versàtil per a "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Suport millorat per a Ollama i LM Studio
+### Experiència d'usuari millorada
-### Suport de Models
+- Simplificar la interfície d'usuari per a més claredat i intuïció
+- Millorar contínuament el flux de treball per satisfer les altes expectatives dels desenvolupadors
-Volem que Roo funcioni tan bé com sigui possible amb tants models com sigui possible, inclosos els models locals:
+### Lideratge en rendiment dels agents
-- Suport de models locals a través de prompts de sistema personalitzats i fluxos de treball
-- Avaluacions de rendiment i casos de prova
+- Establir punts de referència d'avaluació (evals) complets per mesurar la productivitat real
+- Facilitar que tothom pugui executar i interpretar aquestes avaluacions fàcilment
+- Proporcionar millores que demostrin increments clars en les puntuacions d'avaluació
-### Suport de Sistemes
+Esmenta la relació amb aquestes àrees als teus PRs.
-Volem que Roo funcioni bé a l'ordinador de tothom:
+### 3. Uneix-te a la comunitat Roo Code
-- Integració de terminal multiplataforma
-- Suport sòlid i consistent per a Mac, Windows i Linux
+- **Principal:** Uneix-te al nostre [Discord](https://discord.gg/roocode) i envia un DM a **Hannes Rudolph (`hrudolph`)**.
+- **Alternativa:** Els col·laboradors experimentats poden participar directament via [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Documentació
+## Trobar i planificar la teva contribució
-Volem documentació completa i accessible per a tots els usuaris i col·laboradors:
+### Tipus de contribucions
-- Guies d'usuari i tutorials ampliats
-- Documentació clara de l'API
-- Millor orientació per als col·laboradors
-- Recursos de documentació multilingües
-- Exemples interactius i mostres de codi
+- **Correcció d'errors:** Solucionar problemes en el codi.
+- **Noves funcionalitats:** Afegir noves capacitats.
+- **Documentació:** Millorar guies i claredat.
-### Estabilitat
+### Enfoc Issue-First
-Volem reduir significativament el nombre d'errors i augmentar les proves automatitzades:
+Totes les contribucions han de començar amb una Issue de GitHub.
-- Interruptor de registre de depuració
-- Botó de còpia "Informació de Màquina/Tasca" per enviar amb sol·licituds d'error/suport
+- **Revisar issues existents:** Cerca a [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Crear una issue:** Utilitza les plantilles adequades:
+ - **Errors:** Plantilla "Bug Report".
+ - **Funcionalitats:** Plantilla "Detailed Feature Proposal". Es requereix aprovació abans de començar.
+- **Reclamar issues:** Comenta i espera l'assignació oficial.
-### Internacionalització
+**Els PRs sense issues aprovades poden ser tancats.**
-Volem que Roo parli l'idioma de tothom:
+### Decidir en què treballar
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Consulta el [Projecte GitHub](https://github.com/orgs/RooVetGit/projects/1) per trobar "Good First Issues" no assignades.
+- Per a documentació, visita [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Donem especialment la benvinguda a contribucions que avancin els nostres objectius del full de ruta. Si esteu treballant en alguna cosa que s'alinea amb aquests pilars, si us plau mencioneu-ho a la descripció del vostre PR.
+### Informar d'errors
-## Configuració de desenvolupament
+- Comprova primer els informes existents.
+- Crea nous informes d'errors utilitzant la [plantilla "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Vulnerabilitats de seguretat:** Informa de manera privada via [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Cloneu** el repositori:
+## Procés de desenvolupament i enviament
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Configuració de desenvolupament
-2. **Instal·leu les dependències**:
+1. **Fork & Clona:**
-```sh
-npm run install:all
```
-
-3. **Inicieu la vista web (aplicació Vite/React amb HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/EL_TEU_USUARI/Roo-Code.git
```
-4. **Depuració**:
- Premeu `F5` (o **Execució** → **Inicia la depuració**) a VSCode per obrir una nova sessió amb Roo Code carregat.
-
-Els canvis a la vista web apareixeran immediatament. Els canvis a l'extensió principal requeriran reiniciar l'amfitrió de l'extensió.
-
-Alternativament, podeu crear un .vsix i instal·lar-lo directament a VSCode:
+2. **Instal·la dependències:**
-```sh
-npm run build
```
-
-Apareixerà un fitxer `.vsix` al directori `bin/` que es pot instal·lar amb:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Escriure i enviar codi
-
-Qualsevol persona pot contribuir amb codi a Roo Code, però us demanem que seguiu aquestes directrius per assegurar que les vostres contribucions puguin ser integrades sense problemes:
-
-1. **Mantingueu les Pull Requests enfocades**
-
- - Limiteu les PR a una sola funcionalitat o correcció d'error
- - Dividiu els canvis més grans en PR més petites i relacionades
- - Dividiu els canvis en commits lògics que puguin ser revisats independentment
-
-2. **Qualitat del codi**
+3. **Depuració:** Obre amb VS Code (`F5`).
- - Totes les PR han de passar les comprovacions de CI que inclouen tant anàlisi com formatació
- - Solucioneu qualsevol advertència o error d'ESLint abans d'enviar
- - Responeu a tots els comentaris d'Ellipsis, la nostra eina automatitzada de revisió de codi
- - Seguiu les millors pràctiques de TypeScript i mantingueu la seguretat de tipus
+### Guia per escriure codi
-3. **Proves**
+- Un PR centrat per funcionalitat o correcció.
+- Segueix les millors pràctiques d'ESLint i TypeScript.
+- Escriu missatges de commit clars i descriptius que facin referència a issues (ex: `Fixes #123`).
+- Proporciona proves completes (`npm test`).
+- Rebaseja a la branca `main` més recent abans d'enviar.
- - Afegiu proves per a noves funcionalitats
- - Executeu `npm test` per assegurar que totes les proves passin
- - Actualitzeu les proves existents si els vostres canvis les afecten
- - Incloeu tant proves unitàries com proves d'integració quan sigui apropiat
+### Enviar un Pull Request
-4. **Directrius de commits**
+- Comença com a **PR en esborrany** si busques feedback primerenc.
+- Descriu clarament els teus canvis seguint la Plantilla de Pull Request.
+- Proporciona captures de pantalla/vídeos per a canvis d'UI.
+- Indica si es necessiten actualitzacions de documentació.
- - Escriviu missatges de commit clars i descriptius
- - Feu referència a incidències rellevants als commits utilitzant #número-incidència
+### Política de Pull Request
-5. **Abans d'enviar**
+- Ha de fer referència a issues preaprovades i assignades.
+- Els PRs que no segueixen la política poden ser tancats.
+- Els PRs han de passar els tests de CI, alinear-se amb la fulla de ruta i tenir documentació clara.
- - Rebaseu la vostra branca sobre l'última main
- - Assegureu-vos que la vostra branca es construeix amb èxit
- - Comproveu doblement que totes les proves passen
- - Reviseu els vostres canvis per qualsevol codi de depuració o registres de consola
+### Procés de revisió
-6. **Descripció de la Pull Request**
- - Descriviu clarament què fan els vostres canvis
- - Incloeu passos per provar els canvis
- - Enumereu qualsevol canvi important
- - Afegiu captures de pantalla per a canvis d'interfície d'usuari
+- **Triatge diari:** Comprovacions ràpides pels mantenidors.
+- **Revisió setmanal detallada:** Avaluació exhaustiva.
+- **Itera ràpidament** en base al feedback.
-## Acord de contribució
+## Legal
-En enviar una pull request, accepteu que les vostres contribucions estaran sota la mateixa llicència que el projecte ([Apache 2.0](../LICENSE)).
+En enviar un pull request, acceptes que les teves contribucions es llicenciïn sota la Llicència Apache 2.0, d'acord amb la llicència de Roo Code.
diff --git a/locales/ca/README.md b/locales/ca/README.md
index 4bbcfb1e36e..42853a8b785 100644
--- a/locales/ca/README.md
+++ b/locales/ca/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • Català • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • Català • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Tant si busqueu un soci de programació flexible, un arquitecte de sistemes o rols especialitzats com un enginyer de control de qualitat o un gestor de producte, Roo Code us pot ajudar a construir programari de manera més eficient.
-Consulteu el [CHANGELOG](../CHANGELOG.md) per a actualitzacions i correccions detallades.
+Consulteu el [CHANGELOG](../../CHANGELOG.md) per a actualitzacions i correccions detallades.
---
-## 🎉 Roo Code 3.15 Llançat
+## 🎉 Roo Code 3.17 Llançat
-Roo Code 3.15 aporta noves funcionalitats i millores basades en els vostres comentaris!
+Roo Code 3.17 aporta noves i potents funcionalitats i millores basades en els vostres comentaris!
-- **Memòria cau per a prompts a Vertex** - Vertex AI ara suporta memòria cau de prompts, millorant els temps de resposta i reduint els costos d'API.
-- **Mecanisme alternatiu per al Terminal** - S'ha implementat un mecanisme alternatiu quan la integració de shell del terminal de VSCode falla, assegurant operacions de terminal més fiables.
-- **Fragments de codi millorats** - S'ha millorat la renderització i interacció amb fragments de codi a la interfície de xat per a una millor llegibilitat i usabilitat.
+- **Memòria cau implícita per a Gemini** - Les crides a l'API de Gemini ara es desen automàticament a la memòria cau, reduint els costos d'API.
+- **Selecció de mode més intel·ligent** - Les definicions de mode ara poden incloure orientació sobre quan s'ha d'utilitzar cada mode, permetent una millor orquestració.
+- **Condensació intel·ligent del context** - Resumeix de manera intel·ligent l'historial de converses quan el context s'omple en lloc de truncar-lo (activeu-ho a Configuració -> Experimental).
---
@@ -178,32 +178,36 @@ Ens encanten les contribucions de la comunitat! Comenceu llegint el nostre [CONT
Gràcies a tots els nostres col·laboradors que han ajudat a millorar Roo Code!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Llicència
diff --git a/locales/de/CODE_OF_CONDUCT.md b/locales/de/CODE_OF_CONDUCT.md
index d2fc00beb81..b1fa6e3128f 100644
--- a/locales/de/CODE_OF_CONDUCT.md
+++ b/locales/de/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • Deutsch • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Verhaltenskodex für Mitwirkende
## Unser Versprechen
diff --git a/locales/de/CONTRIBUTING.md b/locales/de/CONTRIBUTING.md
index 1aa7a5b6c2a..df96ef42b4a 100644
--- a/locales/de/CONTRIBUTING.md
+++ b/locales/de/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Beitrag zu Roo Code
-
-Wir freuen uns, dass du Interesse hast, zu Roo Code beizutragen. Ob du einen Fehler behebst, eine Funktion hinzufügst oder unsere Dokumentation verbesserst, jeder Beitrag macht Roo Code intelligenter! Um unsere Community lebendig und einladend zu halten, müssen sich alle Mitglieder an unseren [Verhaltenskodex](CODE_OF_CONDUCT.md) halten.
-
-## Treten Sie unserer Community bei
-
-Wir ermutigen alle Mitwirkenden nachdrücklich, unserer [Discord-Community](https://discord.gg/roocode) beizutreten! Teil unseres Discord-Servers zu sein, hilft dir:
-
-- Echtzeit-Hilfe und Anleitung für deine Beiträge zu erhalten
-- Mit anderen Mitwirkenden und Kernteammitgliedern in Kontakt zu treten
-- Über Projektentwicklungen und Prioritäten auf dem Laufenden zu bleiben
-- An Diskussionen teilzunehmen, die die Zukunft von Roo Code gestalten
-- Kooperationsmöglichkeiten mit anderen Entwicklern zu finden
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • Deutsch • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Fehler oder Probleme melden
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Fehlerberichte helfen, Roo Code für alle besser zu machen! Bevor du ein neues Issue erstellst, bitte [suche in bestehenden Issues](https://github.com/RooVetGit/Roo-Code/issues), um Duplikate zu vermeiden. Wenn du bereit bist, einen Fehler zu melden, gehe zu unserer [Issues-Seite](https://github.com/RooVetGit/Roo-Code/issues/new/choose), wo du eine Vorlage findest, die dir beim Ausfüllen der relevanten Informationen hilft.
-
-
- 🔐 Wichtig: Wenn du eine Sicherheitslücke entdeckst, nutze bitte das Github-Sicherheitstool, um sie privat zu melden.
-
+# Beitrag zu Roo Code
-## Entscheiden, woran Sie arbeiten möchten
+Roo Code ist ein Community-getriebenes Projekt, und wir schätzen jeden Beitrag sehr. Für eine reibungslose Zusammenarbeit arbeiten wir nach dem [Issue-First-Ansatz](#issue-first-ansatz), was bedeutet, dass alle [Pull Requests (PRs)](#einen-pull-request-einreichen) zuerst mit einem GitHub Issue verknüpft werden müssen. Bitte lies diesen Leitfaden sorgfältig durch.
-Suchst du nach einem guten ersten Beitrag? Schau dir Issues im Abschnitt "Issue [Unassigned]" unseres [Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1) Github-Projekts an. Diese sind speziell für neue Mitwirkende und Bereiche ausgewählt, in denen wir Hilfe gebrauchen könnten!
+## Inhaltsverzeichnis
-Wir begrüßen auch Beiträge zu unserer [Dokumentation](https://docs.roocode.com/)! Ob du Tippfehler korrigierst, bestehende Anleitungen verbesserst oder neue Bildungsinhalte erstellst - wir würden gerne ein Community-geführtes Repository von Ressourcen aufbauen, das jedem hilft, das Beste aus Roo Code herauszuholen. Du kannst auf jeder Seite auf "Edit this page" klicken, um schnell zur richtigen Stelle in Github zu gelangen, um die Datei zu bearbeiten, oder du kannst direkt zu https://github.com/RooVetGit/Roo-Code-Docs gehen.
+- [Bevor du beiträgst](#bevor-du-beiträgst)
+- [Beitrag finden & planen](#beitrag-finden--planen)
+- [Entwicklung & Einreichung](#entwicklung--einreichung)
+- [Rechtliches](#rechtliches)
-Wenn du an einer größeren Funktion arbeiten möchtest, erstelle bitte zuerst eine [Funktionsanfrage](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop), damit wir diskutieren können, ob sie mit der Vision von Roo Code übereinstimmt. Du kannst auch unseren [Projekt-Fahrplan](#projekt-fahrplan) unten überprüfen, um zu sehen, ob deine Idee mit unserer strategischen Ausrichtung übereinstimmt.
+## Bevor du beiträgst
-## Projekt-Fahrplan
+### 1. Verhaltenskodex
-Roo Code hat einen klaren Entwicklungsfahrplan, der unsere Prioritäten und zukünftige Richtung leitet. Das Verständnis unseres Fahrplans kann dir helfen:
+Alle Mitwirkenden müssen sich an unseren [Verhaltenskodex](./CODE_OF_CONDUCT.md) halten.
-- Deine Beiträge mit den Projektzielen abzustimmen
-- Bereiche zu identifizieren, in denen deine Expertise am wertvollsten wäre
-- Den Kontext hinter bestimmten Designentscheidungen zu verstehen
-- Inspiration für neue Funktionen zu finden, die unsere Vision unterstützen
+### 2. Projekt-Roadmap
-Unser aktueller Fahrplan konzentriert sich auf sechs Schlüsselsäulen:
+Unsere Roadmap gibt die Richtung des Projekts vor. Richte deine Beiträge an diesen Schlüsselzielen aus:
-### Provider-Unterstützung
+### Zuverlässigkeit an erster Stelle
-Wir möchten so viele Provider wie möglich gut unterstützen:
+- Sicherstellen, dass Diff-Bearbeitung und Befehlsausführung durchgängig zuverlässig sind.
+- Reibungspunkte reduzieren, die von der regelmäßigen Nutzung abhalten.
+- Reibungslosen Betrieb in allen Sprachen und auf allen Plattformen garantieren.
+- Robuste Unterstützung für eine Vielzahl von KI-Anbietern und -Modellen ausbauen.
-- Vielseitigere "OpenAI Compatible" Unterstützung
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Verbesserte Unterstützung für Ollama und LM Studio
+### Verbesserte Benutzererfahrung
-### Modell-Unterstützung
+- Die Benutzeroberfläche für mehr Klarheit und Intuitivität optimieren.
+- Den Workflow kontinuierlich verbessern, um den hohen Erwartungen gerecht zu werden, die Entwickler an täglich genutzte Tools stellen.
-Wir wollen, dass Roo mit so vielen Modellen wie möglich gut funktioniert, einschließlich lokaler Modelle:
+### Führend bei der Agentenleistung
-- Lokale Modellunterstützung durch benutzerdefiniertes System-Prompting und Workflows
-- Benchmark-Evaluierungen und Testfälle
+- Umfassende Evaluierungsmaßstäbe (Evals) etablieren, um die Produktivität in der realen Welt zu messen.
+- Es für jeden einfach machen, diese Evals durchzuführen und zu interpretieren.
+- Verbesserungen liefern, die klare Steigerungen der Eval-Ergebnisse zeigen.
-### System-Unterstützung
+Erwähne die Ausrichtung an diesen Bereichen in deinen PRs.
-Wir wollen, dass Roo auf jedem Computer gut läuft:
+### 3. Werde Teil der Roo Code Community
-- Plattformübergreifende Terminal-Integration
-- Starke und konsistente Unterstützung für Mac, Windows und Linux
+- **Hauptweg:** Tritt unserem [Discord](https://discord.gg/roocode) bei und schreibe eine DM an **Hannes Rudolph (`hrudolph`)**.
+- **Alternative:** Erfahrene Mitwirkende können sich direkt über [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1) beteiligen.
-### Dokumentation
+## Beitrag finden & planen
-Wir wollen umfassende, zugängliche Dokumentation für alle Benutzer und Mitwirkenden:
+### Beitragsarten
-- Erweiterte Benutzerhandbücher und Tutorials
-- Klare API-Dokumentation
-- Bessere Anleitung für Mitwirkende
-- Mehrsprachige Dokumentationsressourcen
-- Interaktive Beispiele und Codebeispiele
+- **Bugfixes:** Fehler im Code beheben.
+- **Neue Features:** Neue Funktionen hinzufügen.
+- **Dokumentation:** Anleitungen verbessern und klarer gestalten.
-### Stabilität
+### Issue-First-Ansatz
-Wir wollen die Anzahl der Fehler deutlich reduzieren und die automatisierte Testabdeckung erhöhen:
+Alle Beiträge müssen mit einem GitHub Issue beginnen.
-- Debug-Logging-Schalter
-- "Maschinen-/Aufgabeninformationen" Kopier-Button zum Einsenden mit Fehler-/Support-Anfragen
+- **Bestehende Issues prüfen**: Durchsuche die [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Issue erstellen**: Nutze die passenden Vorlagen:
+ - **Bugs:** "Bug Report"-Vorlage.
+ - **Features:** "Detailed Feature Proposal"-Vorlage. Vor dem Start ist eine Genehmigung erforderlich.
+- **Issues beanspruchen**: Kommentiere und warte auf die offizielle Zuweisung.
-### Internationalisierung
+**PRs ohne genehmigte Issues können geschlossen werden.**
-Wir wollen, dass Roo die Sprache aller spricht:
+### Was soll ich machen?
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Schau im [GitHub Project](https://github.com/orgs/RooVetGit/projects/1) nach nicht zugewiesenen "Good First Issues".
+- Für Dokumentation besuche das [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs) Repository.
-Wir begrüßen besonders Beiträge, die unsere Fahrplanziele voranbringen. Wenn du an etwas arbeitest, das mit diesen Säulen übereinstimmt, erwähne es bitte in deiner PR-Beschreibung.
+### Bugs melden
-## Entwicklungs-Setup
+- Prüfe zuerst, ob der Bug bereits gemeldet wurde.
+- Erstelle neue Bug-Reports mit der ["Bug Report"-Vorlage](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Sicherheitslücken:** Melde diese privat über [Security Advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Klone** das Repository:
+## Entwicklung & Einreichung
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Entwicklungs-Setup
-2. **Installiere Abhängigkeiten**:
+1. **Fork & Clone:**
-```sh
-npm run install:all
```
-
-3. **Starte die Webansicht (Vite/React-App mit HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/DEIN_USERNAME/Roo-Code.git
```
-4. **Debugging**:
- Drücke `F5` (oder **Ausführen** → **Debugging starten**) in VSCode, um eine neue Sitzung mit geladenem Roo Code zu öffnen.
-
-Änderungen an der Webansicht erscheinen sofort. Änderungen an der Kern-Erweiterung erfordern einen Neustart des Erweiterungs-Hosts.
-
-Alternativ kannst du eine .vsix-Datei erstellen und direkt in VSCode installieren:
+2. **Abhängigkeiten installieren:**
-```sh
-npm run build
```
-
-Eine `.vsix`-Datei erscheint im `bin/`-Verzeichnis, die mit folgendem Befehl installiert werden kann:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Code schreiben und einreichen
-
-Jeder kann Code zu Roo Code beitragen, aber wir bitten dich, diese Richtlinien zu befolgen, um sicherzustellen, dass deine Beiträge reibungslos integriert werden können:
-
-1. **Halten Sie Pull Requests fokussiert**
-
- - Beschränke PRs auf eine einzelne Funktion oder Fehlerbehebung
- - Teile größere Änderungen in kleinere, zusammenhängende PRs auf
- - Unterteile Änderungen in logische Commits, die unabhängig überprüft werden können
-
-2. **Codequalität**
+3. **Debugging:** Öffne mit VS Code (`F5`).
- - Alle PRs müssen CI-Prüfungen bestehen, die sowohl Linting als auch Formatierung umfassen
- - Behebe alle ESLint-Warnungen oder -Fehler vor dem Einreichen
- - Reagiere auf alle Rückmeldungen von Ellipsis, unserem automatisierten Code-Review-Tool
- - Folge TypeScript-Best-Practices und halte die Typsicherheit aufrecht
+### Code-Richtlinien
-3. **Testen**
+- Ein fokussierter PR pro Feature oder Fix.
+- Folge den ESLint und TypeScript Best Practices.
+- Schreibe klare, beschreibende Commits, die auf Issues verweisen (z.B. `Fixes #123`).
+- Liefere gründliche Tests (`npm test`).
+- Rebase auf den neuesten `main`-Branch vor dem Einreichen.
- - Füge Tests für neue Funktionen hinzu
- - Führe `npm test` aus, um sicherzustellen, dass alle Tests bestanden werden
- - Aktualisiere bestehende Tests, wenn deine Änderungen diese beeinflussen
- - Schließe sowohl Unit-Tests als auch Integrationstests ein, wo angemessen
+### Einen Pull Request einreichen
-4. **Commit-Richtlinien**
+- Beginne als **Draft PR**, wenn du frühes Feedback suchst.
+- Beschreibe deine Änderungen klar und folge der Pull Request Vorlage.
+- Stelle Screenshots/Videos für UI-Änderungen bereit.
+- Gib an, ob Dokumentationsaktualisierungen notwendig sind.
- - Schreibe klare, beschreibende Commit-Nachrichten
- - Verweise auf relevante Issues in Commits mit #issue-nummer
+### Pull Request Richtlinie
-5. **Vor dem Einreichen**
+- Muss auf vorab genehmigte, zugewiesene Issues verweisen.
+- PRs ohne Einhaltung der Richtlinie können geschlossen werden.
+- PRs sollten CI-Tests bestehen, zur Roadmap passen und klare Dokumentation haben.
- - Rebase deinen Branch auf den neuesten main-Branch
- - Stelle sicher, dass dein Branch erfolgreich baut
- - Überprüfe erneut, dass alle Tests bestanden werden
- - Prüfe deine Änderungen auf Debug-Code oder Konsolenausgaben
+### Review-Prozess
-6. **Pull Request Beschreibung**
- - Beschreibe klar, was deine Änderungen bewirken
- - Füge Schritte zum Testen der Änderungen hinzu
- - Liste alle Breaking Changes auf
- - Füge Screenshots für UI-Änderungen hinzu
+- **Tägliche Triage:** Schnelle Prüfungen durch Maintainer.
+- **Wöchentliche Tiefenprüfung:** Umfassende Bewertung.
+- **Zeitnah auf Feedback reagieren** und entsprechend iterieren.
-## Beitragsvereinbarung
+## Rechtliches
-Durch das Einreichen eines Pull Requests stimmst du zu, dass deine Beiträge unter derselben Lizenz wie das Projekt ([Apache 2.0](../LICENSE)) lizenziert werden.
+Mit deinem Beitrag erklärst du dich damit einverstanden, dass deine Beiträge unter der Apache 2.0 Lizenz lizenziert werden, konsistent mit der Lizenzierung von Roo Code.
diff --git a/locales/de/README.md b/locales/de/README.md
index 19ad5ebb6e1..348a06d3873 100644
--- a/locales/de/README.md
+++ b/locales/de/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • Deutsch • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • Deutsch • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Ob Sie einen flexiblen Coding-Partner, einen Systemarchitekten oder spezialisierte Rollen wie einen QA-Ingenieur oder Produktmanager suchen, Roo Code kann Ihnen helfen, Software effizienter zu entwickeln.
-Sehen Sie sich das [CHANGELOG](../CHANGELOG.md) für detaillierte Updates und Fehlerbehebungen an.
+Sehen Sie sich das [CHANGELOG](../../CHANGELOG.md) für detaillierte Updates und Fehlerbehebungen an.
---
-## 🎉 Roo Code 3.15 veröffentlicht
+## 🎉 Roo Code 3.17 veröffentlicht
-Roo Code 3.15 bringt neue Funktionen und Verbesserungen basierend auf deinem Feedback!
+Roo Code 3.17 bringt leistungsstarke neue Funktionen und Verbesserungen basierend auf deinem Feedback!
-- **Prompt-Caching für Vertex** - Vertex AI unterstützt jetzt Prompt-Caching, was die Antwortzeiten verbessert und API-Kosten reduziert.
-- **Terminal-Fallback** - Ein Fallback-Mechanismus wurde implementiert, der greift, wenn die VSCode-Terminal-Shell-Integration fehlschlägt, um zuverlässigere Terminal-Operationen zu gewährleisten.
-- **Verbesserte Code-Snippets** - Verbesserte Darstellung und Interaktion mit Code-Snippets in der Chat-Oberfläche für bessere Lesbarkeit und Benutzerfreundlichkeit.
+- **Implizites Caching für Gemini** - Gemini API-Aufrufe werden jetzt automatisch gecacht, was die API-Kosten reduziert.
+- **Intelligentere Modusauswahl** - Modusdefinitionen können jetzt Hinweise enthalten, wann jeder Modus verwendet werden sollte, was eine bessere Orchestrierung ermöglicht.
+- **Intelligente Kontextkondensierung** - Fasst den Gesprächsverlauf intelligent zusammen, wenn der Kontext voll ist, anstatt ihn abzuschneiden (aktiviere dies in Einstellungen -> Experimentell).
---
@@ -178,32 +178,36 @@ Wir lieben Community-Beiträge! Beginnen Sie mit dem Lesen unserer [CONTRIBUTING
Danke an alle unsere Mitwirkenden, die geholfen haben, Roo Code zu verbessern!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Lizenz
diff --git a/locales/es/CODE_OF_CONDUCT.md b/locales/es/CODE_OF_CONDUCT.md
index 9375965456f..e978484e35e 100644
--- a/locales/es/CODE_OF_CONDUCT.md
+++ b/locales/es/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • Español • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Código de Conducta del Pacto de Colaboradores
## Nuestro Compromiso
diff --git a/locales/es/CONTRIBUTING.md b/locales/es/CONTRIBUTING.md
index 14cf3a96f36..545af5174e7 100644
--- a/locales/es/CONTRIBUTING.md
+++ b/locales/es/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Contribuir a Roo Code
-
-Estamos encantados de que estés interesado en contribuir a Roo Code. Ya sea que estés arreglando un error, añadiendo una función o mejorando nuestra documentación, ¡cada contribución hace que Roo Code sea más inteligente! Para mantener nuestra comunidad vibrante y acogedora, todos los miembros deben adherirse a nuestro [Código de Conducta](CODE_OF_CONDUCT.md).
-
-## Únete a nuestra comunidad
-
-¡Animamos encarecidamente a todos los colaboradores a unirse a nuestra [comunidad de Discord](https://discord.gg/roocode)! Formar parte de nuestro servidor de Discord te ayuda a:
-
-- Obtener ayuda y orientación en tiempo real para tus contribuciones
-- Conectar con otros colaboradores y miembros del equipo principal
-- Mantenerte actualizado sobre los desarrollos y prioridades del proyecto
-- Participar en discusiones que dan forma al futuro de Roo Code
-- Encontrar oportunidades de colaboración con otros desarrolladores
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • Español • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Reportar errores o problemas
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-¡Los informes de errores ayudan a mejorar Roo Code para todos! Antes de crear un nuevo issue, por favor [busca entre los existentes](https://github.com/RooVetGit/Roo-Code/issues) para evitar duplicados. Cuando estés listo para reportar un error, dirígete a nuestra [página de issues](https://github.com/RooVetGit/Roo-Code/issues/new/choose) donde encontrarás una plantilla para ayudarte a completar la información relevante.
-
-
- 🔐 Importante: Si descubres una vulnerabilidad de seguridad, por favor utiliza la herramienta de seguridad de GitHub para reportarla de forma privada.
-
+# Contribuir a Roo Code
-## Decidir en qué trabajar
+Roo Code es un proyecto impulsado por la comunidad, y valoramos profundamente cada contribución. Para agilizar la colaboración, operamos con un enfoque [Issue-First](#enfoque-issue-first), lo que significa que todos los [Pull Requests (PRs)](#enviar-un-pull-request) deben estar vinculados primero a un Issue de GitHub. Por favor, revisa esta guía cuidadosamente.
-¿Buscas una buena primera contribución? Revisa los issues en la sección "Issue [Unassigned]" de nuestro [Proyecto GitHub de Roo Code](https://github.com/orgs/RooVetGit/projects/1). ¡Estos están específicamente seleccionados para nuevos colaboradores y áreas donde nos encantaría recibir ayuda!
+## Tabla de Contenidos
-¡También damos la bienvenida a contribuciones a nuestra [documentación](https://docs.roocode.com/)! Ya sea arreglando errores tipográficos, mejorando guías existentes o creando nuevo contenido educativo - nos encantaría construir un repositorio de recursos impulsado por la comunidad que ayude a todos a sacar el máximo provecho de Roo Code. Puedes hacer clic en "Edit this page" en cualquier página para llegar rápidamente al lugar correcto en Github para editar el archivo, o puedes ir directamente a https://github.com/RooVetGit/Roo-Code-Docs.
+- [Antes de Contribuir](#antes-de-contribuir)
+- [Encontrar y Planificar tu Contribución](#encontrar-y-planificar-tu-contribución)
+- [Proceso de Desarrollo y Envío](#proceso-de-desarrollo-y-envío)
+- [Legal](#legal)
-Si estás planeando trabajar en una función más grande, por favor crea una [solicitud de función](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) primero para que podamos discutir si se alinea con la visión de Roo Code. También puedes consultar nuestra [Hoja de Ruta del Proyecto](#hoja-de-ruta-del-proyecto) a continuación para ver si tu idea encaja con nuestra dirección estratégica.
+## Antes de Contribuir
-## Hoja de Ruta del Proyecto
+### 1. Código de Conducta
-Roo Code tiene una hoja de ruta de desarrollo clara que guía nuestras prioridades y dirección futura. Entender nuestra hoja de ruta puede ayudarte a:
+Todos los colaboradores deben adherirse a nuestro [Código de Conducta](./CODE_OF_CONDUCT.md).
-- Alinear tus contribuciones con los objetivos del proyecto
-- Identificar áreas donde tu experiencia sería más valiosa
-- Entender el contexto detrás de ciertas decisiones de diseño
-- Encontrar inspiración para nuevas funciones que apoyen nuestra visión
+### 2. Hoja de Ruta del Proyecto
-Nuestra hoja de ruta actual se centra en seis pilares clave:
+Nuestra hoja de ruta guía la dirección del proyecto. Alinea tus contribuciones con estos objetivos clave:
-### Soporte de Proveedores
+### Confiabilidad Primero
-Nuestro objetivo es dar soporte a tantos proveedores como sea posible:
+- Garantizar que la edición de diferencias y la ejecución de comandos sean consistentemente confiables.
+- Reducir los puntos de fricción que disuaden el uso regular.
+- Garantizar un funcionamiento fluido en todos los idiomas y plataformas.
+- Ampliar el soporte sólido para una amplia variedad de proveedores y modelos de IA.
-- Soporte más versátil para "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Soporte mejorado para Ollama y LM Studio
+### Experiencia de Usuario Mejorada
-### Soporte de Modelos
+- Simplificar la interfaz de usuario para mayor claridad e intuitividad.
+- Mejorar continuamente el flujo de trabajo para satisfacer las altas expectativas que los desarrolladores tienen para herramientas de uso diario.
-Queremos que Roo funcione bien con tantos modelos como sea posible, incluidos los modelos locales:
+### Liderazgo en Rendimiento de Agentes
-- Soporte para modelos locales a través de system prompting personalizado y flujos de trabajo
-- Evaluaciones de benchmarking y casos de prueba
+- Establecer evaluaciones comparativas completas (evals) para medir la productividad en el mundo real.
+- Facilitar que todos puedan ejecutar e interpretar estas evaluaciones fácilmente.
+- Ofrecer mejoras que demuestren aumentos claros en las puntuaciones de evaluación.
-### Soporte de Sistemas
+Menciona la alineación con estas áreas en tus PRs.
-Queremos que Roo funcione bien en el ordenador de todos:
+### 3. Únete a la Comunidad Roo Code
-- Integración de terminal multiplataforma
-- Soporte sólido y consistente para Mac, Windows y Linux
+- **Principal:** Únete a nuestro [Discord](https://discord.gg/roocode) y envía un DM a **Hannes Rudolph (`hrudolph`)**.
+- **Alternativa:** Los colaboradores experimentados pueden participar directamente a través de [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Documentación
+## Encontrar y Planificar tu Contribución
-Queremos una documentación completa y accesible para todos los usuarios y colaboradores:
+### Tipos de Contribuciones
-- Guías de usuario y tutoriales ampliados
-- Documentación clara de la API
-- Mejor orientación para colaboradores
-- Recursos de documentación multilingües
-- Ejemplos interactivos y muestras de código
+- **Corrección de errores:** Solucionar problemas en el código.
+- **Nuevas funciones:** Añadir funcionalidades.
+- **Documentación:** Mejorar guías y claridad.
-### Estabilidad
+### Enfoque Issue-First
-Queremos disminuir significativamente el número de errores y aumentar las pruebas automatizadas:
+Todas las contribuciones deben comenzar con un Issue de GitHub.
-- Interruptor de registro de depuración
-- Botón de copia de "Información de Máquina/Tarea" para enviar con solicitudes de soporte/errores
+- **Revisar issues existentes**: Busca en [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Crear un issue**: Usa las plantillas apropiadas:
+ - **Errores:** Plantilla "Bug Report".
+ - **Funciones:** Plantilla "Detailed Feature Proposal". Se requiere aprobación antes de comenzar.
+- **Reclamar issues**: Comenta y espera la asignación oficial.
-### Internacionalización
+**Los PRs sin issues aprobados pueden ser cerrados.**
-Queremos que Roo hable el idioma de todos:
+### Decidir en Qué Trabajar
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Revisa el [Proyecto GitHub](https://github.com/orgs/RooVetGit/projects/1) para "Good First Issues" no asignados.
+- Para documentación, visita [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Damos especialmente la bienvenida a contribuciones que avancen nuestros objetivos de la hoja de ruta. Si estás trabajando en algo que se alinea con estos pilares, por favor menciónalo en la descripción de tu PR.
+### Reportar Errores
-## Configuración de desarrollo
+- Primero verifica si ya existen reportes.
+- Crea nuevos reportes de errores usando la [plantilla "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Problemas de seguridad**: Reporta de forma privada a través de [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Clona** el repositorio:
+## Proceso de Desarrollo y Envío
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Configuración de Desarrollo
-2. **Instala dependencias**:
+1. **Fork & Clona:**
-```sh
-npm run install:all
```
-
-3. **Inicia la vista web (aplicación Vite/React con HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/TU_USUARIO/Roo-Code.git
```
-4. **Depuración**:
- Presiona `F5` (o **Ejecutar** → **Iniciar depuración**) en VSCode para abrir una nueva sesión con Roo Code cargado.
-
-Los cambios en la vista web aparecerán inmediatamente. Los cambios en la extensión principal requerirán un reinicio del host de extensión.
-
-Alternativamente, puedes construir un archivo .vsix e instalarlo directamente en VSCode:
+2. **Instalar Dependencias:**
-```sh
-npm run build
```
-
-Un archivo `.vsix` aparecerá en el directorio `bin/` que puede ser instalado con:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Escribir y enviar código
-
-Cualquiera puede contribuir con código a Roo Code, pero te pedimos que sigas estas pautas para asegurar que tus contribuciones puedan integrarse sin problemas:
-
-1. **Mantén los Pull Requests enfocados**
-
- - Limita los PRs a una sola función o corrección de errores
- - Divide los cambios más grandes en PRs más pequeños y relacionados
- - Separa los cambios en commits lógicos que puedan revisarse independientemente
-
-2. **Calidad del código**
+3. **Depuración:** Abre con VS Code (`F5`).
- - Todos los PRs deben pasar las comprobaciones de CI que incluyen tanto linting como formateo
- - Soluciona cualquier advertencia o error de ESLint antes de enviar
- - Responde a todos los comentarios de Ellipsis, nuestra herramienta automatizada de revisión de código
- - Sigue las mejores prácticas de TypeScript y mantén la seguridad de tipos
+### Guía para Escribir Código
-3. **Pruebas**
+- Un PR enfocado por función o corrección.
+- Sigue las mejores prácticas de ESLint y TypeScript.
+- Escribe commits claros y descriptivos que referencien issues (ej., `Fixes #123`).
+- Proporciona pruebas exhaustivas (`npm test`).
+- Rebase sobre la última rama `main` antes de enviar.
- - Añade pruebas para nuevas funciones
- - Ejecuta `npm test` para asegurar que todas las pruebas pasen
- - Actualiza las pruebas existentes si tus cambios les afectan
- - Incluye tanto pruebas unitarias como de integración cuando sea apropiado
+### Enviar un Pull Request
-4. **Directrices para commits**
+- Comienza como **PR en Borrador** si buscas feedback temprano.
+- Describe claramente tus cambios siguiendo la Plantilla de Pull Request.
+- Proporciona capturas de pantalla/videos para cambios en la UI.
+- Indica si son necesarias actualizaciones de documentación.
- - Escribe mensajes de commit claros y descriptivos
- - Haz referencia a los issues relevantes en los commits usando #número-de-issue
+### Política de Pull Request
-5. **Antes de enviar**
+- Debe referenciar issues preaprobados y asignados.
+- Los PRs que no cumplan con la política pueden ser cerrados.
+- Los PRs deben pasar las pruebas de CI, alinearse con la hoja de ruta y tener documentación clara.
- - Haz rebase de tu rama sobre la última main
- - Asegúrate de que tu rama se construye correctamente
- - Comprueba que todas las pruebas están pasando
- - Revisa tus cambios para detectar código de depuración o logs de consola
+### Proceso de Revisión
-6. **Descripción del Pull Request**
- - Describe claramente lo que hacen tus cambios
- - Incluye pasos para probar los cambios
- - Enumera cualquier cambio que rompa la compatibilidad
- - Añade capturas de pantalla para cambios en la interfaz de usuario
+- **Triage Diario:** Revisiones rápidas por parte de los mantenedores.
+- **Revisión Semanal en Profundidad:** Evaluación integral.
+- **Itera rápidamente** basándote en el feedback.
-## Acuerdo de contribución
+## Legal
-Al enviar un pull request, aceptas que tus contribuciones serán licenciadas bajo la misma licencia que el proyecto ([Apache 2.0](../LICENSE)).
+Al contribuir, aceptas que tus contribuciones serán licenciadas bajo la Licencia Apache 2.0, consistente con la licencia de Roo Code.
diff --git a/locales/es/README.md b/locales/es/README.md
index a5d8df2f8e2..c25925687c7 100644
--- a/locales/es/README.md
+++ b/locales/es/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • Español • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • Español • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Ya sea que busques un socio de programación flexible, un arquitecto de sistemas o roles especializados como ingeniero de control de calidad o gestor de productos, Roo Code puede ayudarte a construir software de manera más eficiente.
-Consulta el [CHANGELOG](../CHANGELOG.md) para ver actualizaciones detalladas y correcciones.
+Consulta el [CHANGELOG](../../CHANGELOG.md) para ver actualizaciones detalladas y correcciones.
---
-## 🎉 Roo Code 3.15 Lanzado
+## 🎉 Roo Code 3.17 Lanzado
-¡Roo Code 3.15 trae nuevas funcionalidades y mejoras basadas en tus comentarios!
+¡Roo Code 3.17 trae potentes nuevas funcionalidades y mejoras basadas en tus comentarios!
-- **Caché para prompts en Vertex** - Vertex AI ahora admite caché de prompts, mejorando los tiempos de respuesta y reduciendo los costos de API.
-- **Mecanismo de respaldo para terminal** - Se implementó un mecanismo de respaldo cuando la integración de shell de terminal de VSCode falla, asegurando operaciones de terminal más confiables.
-- **Fragmentos de código mejorados** - Renderizado e interacción mejorados de fragmentos de código en la interfaz de chat para mejor legibilidad y usabilidad.
+- **Caché implícito para Gemini** - Las llamadas a la API de Gemini ahora se almacenan automáticamente en caché, reduciendo los costos de API.
+- **Selección de modo más inteligente** - Las definiciones de modo ahora pueden incluir orientación sobre cuándo debe usarse cada modo, permitiendo una mejor orquestación.
+- **Condensación inteligente de contexto** - Resume de forma inteligente el historial de conversación cuando el contexto se llena en lugar de truncarlo (actívalo en Configuración -> Experimental).
---
@@ -178,32 +178,36 @@ Usamos [changesets](https://github.com/changesets/changesets) para versionar y p
¡Gracias a todos nuestros colaboradores que han ayudado a mejorar Roo Code!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Licencia
diff --git a/locales/fr/CODE_OF_CONDUCT.md b/locales/fr/CODE_OF_CONDUCT.md
index bba5efa6e6e..b872617481d 100644
--- a/locales/fr/CODE_OF_CONDUCT.md
+++ b/locales/fr/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • Français • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Code de Conduite des Contributeurs
## Notre Engagement
diff --git a/locales/fr/CONTRIBUTING.md b/locales/fr/CONTRIBUTING.md
index fdb4796a272..6036c4a891c 100644
--- a/locales/fr/CONTRIBUTING.md
+++ b/locales/fr/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Contribuer à Roo Code
-
-Nous sommes ravis que vous soyez intéressé à contribuer à Roo Code. Que vous corrigiez un bug, ajoutiez une fonctionnalité ou amélioriez notre documentation, chaque contribution rend Roo Code plus intelligent ! Pour maintenir notre communauté dynamique et accueillante, tous les membres doivent adhérer à notre [Code de Conduite](CODE_OF_CONDUCT.md).
-
-## Rejoindre Notre Communauté
-
-Nous encourageons fortement tous les contributeurs à rejoindre notre [communauté Discord](https://discord.gg/roocode) ! Faire partie de notre serveur Discord vous aide à :
-
-- Obtenir de l'aide et des conseils en temps réel sur vos contributions
-- Vous connecter avec d'autres contributeurs et membres de l'équipe principale
-- Rester informé des développements et priorités du projet
-- Participer aux discussions qui façonnent l'avenir de Roo Code
-- Trouver des opportunités de collaboration avec d'autres développeurs
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • Français • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Signaler des Bugs ou des Problèmes
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Les rapports de bugs aident à améliorer Roo Code pour tout le monde ! Avant de créer un nouveau problème, veuillez [rechercher parmi les existants](https://github.com/RooVetGit/Roo-Code/issues) pour éviter les doublons. Lorsque vous êtes prêt à signaler un bug, rendez-vous sur notre [page d'issues](https://github.com/RooVetGit/Roo-Code/issues/new/choose) où vous trouverez un modèle pour vous aider à remplir les informations pertinentes.
-
-
- 🔐 Important : Si vous découvrez une vulnérabilité de sécurité, veuillez utiliser l'outil de sécurité Github pour la signaler en privé.
-
+# Contribuer à Roo Code
-## Décider Sur Quoi Travailler
+Roo Code est un projet porté par la communauté, et chaque contribution compte beaucoup pour nous. Pour fluidifier la collaboration, nous fonctionnons selon une [approche Issue-First](#approche-issue-first), ce qui signifie que toutes les [Pull Requests (PRs)](#soumettre-une-pull-request) doivent d'abord être liées à un ticket GitHub. Lis attentivement ce guide.
-Vous cherchez une bonne première contribution ? Consultez les issues dans la section "Issue [Unassigned]" de notre [Projet Github Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1). Celles-ci sont spécifiquement sélectionnées pour les nouveaux contributeurs et les domaines où nous aimerions recevoir de l'aide !
+## Table des matières
-Nous accueillons également les contributions à notre [documentation](https://docs.roocode.com/) ! Qu'il s'agisse de corriger des fautes de frappe, d'améliorer les guides existants ou de créer du nouveau contenu éducatif - nous aimerions construire un référentiel de ressources guidé par la communauté qui aide chacun à tirer le meilleur parti de Roo Code. Vous pouvez cliquer sur "Edit this page" sur n'importe quelle page pour accéder rapidement au bon endroit dans Github pour éditer le fichier, ou vous pouvez plonger directement dans https://github.com/RooVetGit/Roo-Code-Docs.
+- [Avant de contribuer](#avant-de-contribuer)
+- [Trouver et planifier ta contribution](#trouver-et-planifier-ta-contribution)
+- [Processus de développement et de soumission](#processus-de-développement-et-de-soumission)
+- [Légal](#légal)
-Si vous prévoyez de travailler sur une fonctionnalité plus importante, veuillez d'abord créer une [demande de fonctionnalité](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) afin que nous puissions discuter si elle s'aligne avec la vision de Roo Code. Vous pouvez également consulter notre [Feuille de route du projet](#feuille-de-route-du-projet) ci-dessous pour voir si votre idée s'inscrit dans notre orientation stratégique.
+## Avant de contribuer
-## Feuille de route du projet
+### 1. Code de conduite
-Roo Code dispose d'une feuille de route de développement claire qui guide nos priorités et notre orientation future. Comprendre notre feuille de route peut vous aider à :
+Tous les contributeurs doivent respecter notre [Code de conduite](./CODE_OF_CONDUCT.md).
-- Aligner vos contributions avec les objectifs du projet
-- Identifier les domaines où votre expertise serait la plus précieuse
-- Comprendre le contexte derrière certaines décisions de conception
-- Trouver de l'inspiration pour de nouvelles fonctionnalités qui soutiennent notre vision
+### 2. Feuille de route du projet
-Notre feuille de route actuelle se concentre sur six piliers clés :
+Notre feuille de route guide la direction du projet. Aligne tes contributions avec ces objectifs clés :
-### Support des fournisseurs
+### Fiabilité avant tout
-Nous visons à prendre en charge autant de fournisseurs que possible :
+- Garantir que l'édition des différences et l'exécution des commandes soient toujours fiables.
+- Réduire les points de friction qui découragent l'utilisation régulière.
+- Assurer un fonctionnement fluide dans toutes les langues et sur toutes les plateformes.
+- Étendre le support robuste pour une grande variété de fournisseurs et de modèles d'IA.
-- Support plus polyvalent pour "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Support amélioré pour Ollama et LM Studio
+### Expérience utilisateur améliorée
-### Support des modèles
+- Simplifier l'interface utilisateur pour plus de clarté et d'intuitivité.
+- Améliorer continuellement le flux de travail pour répondre aux attentes élevées des développeurs.
-Nous voulons que Roo fonctionne aussi bien que possible avec autant de modèles que possible, y compris les modèles locaux :
+### Leadership en performance des agents
-- Support des modèles locaux via des prompts système personnalisés et des flux de travail
-- Évaluations de benchmarking et cas de test
+- Établir des référentiels d'évaluation (evals) complets pour mesurer la productivité réelle.
+- Permettre à chacun d'exécuter et d'interpréter facilement ces évaluations.
+- Fournir des améliorations qui démontrent des augmentations claires dans les scores d'évaluation.
-### Support des systèmes
+Mentionne l'alignement avec ces domaines dans tes PRs.
-Nous voulons que Roo fonctionne bien sur l'ordinateur de chacun :
+### 3. Rejoindre la communauté Roo Code
-- Intégration de terminal multiplateforme
-- Support solide et cohérent pour Mac, Windows et Linux
+- **Principal :** Rejoins notre [Discord](https://discord.gg/roocode) et envoie un DM à **Hannes Rudolph (`hrudolph`)**.
+- **Alternative :** Les contributeurs expérimentés peuvent participer directement via [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Documentation
+## Trouver et planifier ta contribution
-Nous voulons une documentation complète et accessible pour tous les utilisateurs et contributeurs :
+### Types de contributions
-- Guides utilisateur et tutoriels étendus
-- Documentation API claire
-- Meilleure orientation pour les contributeurs
-- Ressources de documentation multilingues
-- Exemples interactifs et échantillons de code
+- **Corrections de bugs :** Résoudre des problèmes dans le code.
+- **Nouvelles fonctionnalités :** Ajouter de nouvelles fonctions.
+- **Documentation :** Améliorer les guides et la clarté.
-### Stabilité
+### Approche Issue-First
-Nous voulons réduire considérablement le nombre de bugs et augmenter les tests automatisés :
+Toutes les contributions doivent commencer par un ticket GitHub.
-- Interrupteur de journalisation de débogage
-- Bouton de copie "Informations machine/tâche" pour l'envoi avec les demandes de support/bug
+- **Vérifier les tickets existants :** Cherche dans les [Issues GitHub](https://github.com/RooVetGit/Roo-Code/issues).
+- **Créer un ticket :** Utilise les modèles appropriés :
+ - **Bugs :** Modèle "Bug Report".
+ - **Fonctionnalités :** Modèle "Detailed Feature Proposal". Approbation requise avant de commencer.
+- **Réclamer des tickets :** Commente et attends l'assignation officielle.
-### Internationalisation
+**Les PRs sans tickets approuvés peuvent être fermées.**
-Nous voulons que Roo parle la langue de tous :
+### Décider sur quoi travailler
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Consulte le [Projet GitHub](https://github.com/orgs/RooVetGit/projects/1) pour les "Good First Issues" non assignés.
+- Pour la documentation, visite [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Nous accueillons particulièrement les contributions qui font progresser nos objectifs de feuille de route. Si vous travaillez sur quelque chose qui s'aligne avec ces piliers, veuillez le mentionner dans la description de votre PR.
+### Signaler des bugs
-## Configuration de Développement
+- Vérifie d'abord les rapports existants.
+- Crée de nouveaux rapports de bugs avec le [modèle "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Failles de sécurité :** Signale-les en privé via [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Clonez** le dépôt :
+## Processus de développement et de soumission
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Configuration du développement
-2. **Installez les dépendances** :
+1. **Fork & Clone :**
-```sh
-npm run install:all
```
-
-3. **Démarrez la vue web (application Vite/React avec HMR)** :
-
-```sh
-npm run dev
+git clone https://github.com/TON_UTILISATEUR/Roo-Code.git
```
-4. **Débogage** :
- Appuyez sur `F5` (ou **Exécuter** → **Démarrer le débogage**) dans VSCode pour ouvrir une nouvelle session avec Roo Code chargé.
-
-Les modifications apportées à la vue web apparaîtront immédiatement. Les modifications apportées à l'extension principale nécessiteront un redémarrage de l'hôte d'extension.
-
-Vous pouvez également créer un fichier .vsix et l'installer directement dans VSCode :
+2. **Installer les dépendances :**
-```sh
-npm run build
```
-
-Un fichier `.vsix` apparaîtra dans le répertoire `bin/` qui peut être installé avec :
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Écrire et Soumettre du Code
-
-Tout le monde peut contribuer avec du code à Roo Code, mais nous vous demandons de suivre ces directives pour vous assurer que vos contributions puissent être intégrées en douceur :
-
-1. **Gardez les Pull Requests Ciblées**
-
- - Limitez les PRs à une seule fonctionnalité ou correction de bug
- - Divisez les changements plus importants en PRs plus petites et liées
- - Divisez les changements en commits logiques qui peuvent être examinés indépendamment
-
-2. **Qualité du Code**
+3. **Débogage :** Ouvre avec VS Code (`F5`).
- - Toutes les PRs doivent passer les vérifications CI qui incluent à la fois le linting et le formatage
- - Résolvez toutes les alertes ou erreurs ESLint avant de soumettre
- - Répondez à tous les retours d'Ellipsis, notre outil automatisé de revue de code
- - Suivez les meilleures pratiques TypeScript et maintenez la sécurité des types
+### Guide d'écriture du code
-3. **Tests**
+- Une PR ciblée par fonctionnalité ou correction.
+- Suis les bonnes pratiques ESLint et TypeScript.
+- Écris des commits clairs et descriptifs référençant les tickets (ex : `Fixes #123`).
+- Fournis des tests complets (`npm test`).
+- Rebase sur la dernière branche `main` avant de soumettre.
- - Ajoutez des tests pour les nouvelles fonctionnalités
- - Exécutez `npm test` pour vous assurer que tous les tests passent
- - Mettez à jour les tests existants si vos changements les affectent
- - Incluez à la fois des tests unitaires et d'intégration lorsque c'est approprié
+### Soumettre une Pull Request
-4. **Directives pour les Commits**
+- Commence par un **brouillon de PR** si tu cherches un feedback précoce.
+- Décris clairement tes changements en suivant le modèle de Pull Request.
+- Fournis des captures d'écran/vidéos pour les changements d'interface.
+- Indique si des mises à jour de documentation sont nécessaires.
- - Écrivez des messages de commit clairs et descriptifs
- - Référencez les issues pertinentes dans les commits en utilisant #numéro-issue
+### Politique de Pull Request
-5. **Avant de Soumettre**
+- Doit référencer des tickets pré-approuvés et assignés.
+- Les PRs ne respectant pas cette politique peuvent être fermées.
+- Les PRs doivent passer les tests CI, s'aligner avec la feuille de route et avoir une documentation claire.
- - Rebasez votre branche sur la dernière main
- - Assurez-vous que votre branche se construit avec succès
- - Vérifiez à nouveau que tous les tests passent
- - Revoyez vos changements pour détecter tout code de débogage ou logs de console
+### Processus de revue
-6. **Description du Pull Request**
- - Décrivez clairement ce que font vos changements
- - Incluez des étapes pour tester les changements
- - Listez tous les changements incompatibles
- - Ajoutez des captures d'écran pour les changements d'interface utilisateur
+- **Triage quotidien :** Vérifications rapides par les mainteneurs.
+- **Revue hebdomadaire approfondie :** Évaluation complète.
+- **Itère rapidement** sur la base du feedback.
-## Accord de Contribution
+## Légal
-En soumettant une pull request, vous acceptez que vos contributions soient sous licence selon la même licence que le projet ([Apache 2.0](../LICENSE)).
+En contribuant, tu acceptes que tes contributions soient sous licence Apache 2.0, conformément à la licence de Roo Code.
diff --git a/locales/fr/README.md b/locales/fr/README.md
index bb5f3862a76..f55e3f47f33 100644
--- a/locales/fr/README.md
+++ b/locales/fr/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • Français • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • Français • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Que vous recherchiez un partenaire de codage flexible, un architecte système, ou des rôles spécialisés comme un ingénieur QA ou un chef de produit, Roo Code peut vous aider à développer des logiciels plus efficacement.
-Consultez le [CHANGELOG](../CHANGELOG.md) pour des mises à jour détaillées et des corrections.
+Consultez le [CHANGELOG](../../CHANGELOG.md) pour des mises à jour détaillées et des corrections.
---
-## 🎉 Roo Code 3.15 est sorti
+## 🎉 Roo Code 3.17 est sorti
-Roo Code 3.15 apporte de nouvelles fonctionnalités et améliorations basées sur vos commentaires !
+Roo Code 3.17 apporte de nouvelles fonctionnalités puissantes et des améliorations basées sur vos commentaires !
-- **Cache pour les prompts dans Vertex** - Vertex AI prend maintenant en charge le cache des prompts, améliorant les temps de réponse et réduisant les coûts d'API.
-- **Mécanisme de secours pour le terminal** - Implémentation d'un mécanisme de secours lorsque l'intégration du shell du terminal VSCode échoue, garantissant des opérations de terminal plus fiables.
-- **Fragments de code améliorés** - Rendu et interaction améliorés des fragments de code dans l'interface de chat pour une meilleure lisibilité et facilité d'utilisation.
+- **Mise en cache implicite pour Gemini** - Les appels API Gemini sont désormais automatiquement mis en cache, réduisant les coûts d'API.
+- **Sélection de mode plus intelligente** - Les définitions de mode peuvent maintenant inclure des indications sur quand chaque mode doit être utilisé, permettant une meilleure orchestration.
+- **Condensation intelligente du contexte** - Résume intelligemment l'historique des conversations lorsque le contexte est plein au lieu de le tronquer (activez-le dans Paramètres -> Expérimental).
---
@@ -178,32 +178,36 @@ Nous adorons les contributions de la communauté ! Commencez par lire notre [CON
Merci à tous nos contributeurs qui ont aidé à améliorer Roo Code !
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Licence
diff --git a/locales/hi/CODE_OF_CONDUCT.md b/locales/hi/CODE_OF_CONDUCT.md
index 4f1529c5911..9d22f43944a 100644
--- a/locales/hi/CODE_OF_CONDUCT.md
+++ b/locales/hi/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • हिंदी • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# योगदानकर्ता संधि आचार संहिता
## हमारी प्रतिज्ञा
diff --git a/locales/hi/CONTRIBUTING.md b/locales/hi/CONTRIBUTING.md
index 9f388c295f8..2ec62365b0c 100644
--- a/locales/hi/CONTRIBUTING.md
+++ b/locales/hi/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Roo Code में योगदान देना
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • हिंदी • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-हम खुश हैं कि आप Roo Code में योगदान देने में रुचि रखते हैं। चाहे आप एक बग ठीक कर रहे हों, एक फीचर जोड़ रहे हों, या हमारे दस्तावेज़ों को सुधार रहे हों, हर योगदान Roo Code को अधिक स्मार्ट बनाता है! हमारे समुदाय को जीवंत और स्वागतयोग्य बनाए रखने के लिए, सभी सदस्यों को हमारे [आचार संहिता](CODE_OF_CONDUCT.md) का पालन करना चाहिए।
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## हमारे समुदाय में शामिल हों
+# Roo Code में योगदान करें
-हम सभी योगदानकर्ताओं को हमारे [Discord समुदाय](https://discord.gg/roocode) में शामिल होने के लिए दृढ़ता से प्रोत्साहित करते हैं! हमारे Discord सर्वर का हिस्सा होने से आपको मदद मिलती है:
+Roo Code एक समुदाय-आधारित प्रोजेक्ट है और हम हर योगदान को बहुत महत्व देते हैं। सहयोग को सरल बनाने के लिए, हम [Issue-First](#issue-first-एप्रोच) पद्धति अपनाते हैं, जिसका अर्थ है कि सभी [Pull Requests (PRs)](#pull-request-सबमिट-करना) को पहले GitHub Issue से जोड़ना आवश्यक है। कृपया इस गाइड को ध्यान से पढ़ें।
-- अपने योगदान पर रीयल-टाइम मदद और मार्गदर्शन प्राप्त करें
-- अन्य योगदानकर्ताओं और कोर टीम के सदस्यों से जुड़ें
-- प्रोजेक्ट के विकास और प्राथमिकताओं से अपडेट रहें
-- ऐसी चर्चाओं में भाग लें जो Roo Code के भविष्य को आकार देती हैं
-- अन्य डेवलपर्स के साथ सहयोग के अवसर खोजें
+## विषय सूची
-## बग या समस्याओं की रिपोर्ट करना
+- [योगदान करने से पहले](#योगदान-करने-से-पहले)
+- [अपना योगदान ढूंढना और योजना बनाना](#अपना-योगदान-ढूंढना-और-योजना-बनाना)
+- [विकास और सबमिशन प्रक्रिया](#विकास-और-सबमिशन-प्रक्रिया)
+- [कानूनी](#कानूनी)
-बग रिपोर्ट हर किसी के लिए Roo Code को बेहतर बनाने में मदद करती हैं! नई समस्या बनाने से पहले, कृपया डुप्लिकेट से बचने के लिए [मौजूदा समस्याओं की खोज करें](https://github.com/RooVetGit/Roo-Code/issues)। जब आप बग की रिपोर्ट करने के लिए तैयार हों, तो हमारे [इश्यूज पेज](https://github.com/RooVetGit/Roo-Code/issues/new/choose) पर जाएं जहां आपको प्रासंगिक जानकारी भरने में मदद करने के लिए एक टेम्पलेट मिलेगा।
+## योगदान करने से पहले
-
- 🔐 महत्वपूर्ण: यदि आप कोई सुरक्षा कमजोरी खोजते हैं, तो कृपया इसे निजी तौर पर रिपोर्ट करने के लिए Github सुरक्षा उपकरण का उपयोग करें।
-
+### 1. आचार संहिता
-## किस पर काम करना है यह तय करना
+सभी योगदानकर्ताओं को हमारी [आचार संहिता](./CODE_OF_CONDUCT.md) का पालन करना चाहिए।
-पहले योगदान के लिए एक अच्छा अवसर खोज रहे हैं? हमारे [Roo Code इश्यूज](https://github.com/orgs/RooVetGit/projects/1) Github प्रोजेक्ट के "Issue [Unassigned]" सेक्शन में इश्यूज देखें। ये विशेष रूप से नए योगदानकर्ताओं के लिए और ऐसे क्षेत्रों के लिए क्यूरेट किए गए हैं जहां हमें कुछ मदद की जरूरत होगी!
+### 2. प्रोजेक्ट रोडमैप
-हम अपने [दस्तावेज़ीकरण](https://docs.roocode.com/) में योगदान का भी स्वागत करते हैं! चाहे वह टाइपो ठीक करना हो, मौजूदा गाइड को सुधारना हो, या नई शैक्षिक सामग्री बनाना हो - हम संसाधनों का एक समुदाय-संचालित भंडार बनाना चाहते हैं जो हर किसी को Roo Code का अधिकतम उपयोग करने में मदद करे। आप फ़ाइल को संपादित करने के लिए किसी भी पृष्ठ पर "Edit this page" पर क्लिक कर सकते हैं या सीधे https://github.com/RooVetGit/Roo-Code-Docs में जा सकते हैं।
+हमारा रोडमैप प्रोजेक्ट की दिशा तय करता है। अपने योगदान को इन प्रमुख लक्ष्यों के साथ संरेखित करें:
-यदि आप एक बड़ी विशेषता पर काम करने की योजना बना रहे हैं, तो कृपया पहले एक [फीचर अनुरोध](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) बनाएं ताकि हम चर्चा कर सकें कि क्या यह Roo Code के दृष्टिकोण के अनुरूप है। आप नीचे दिए गए हमारे [प्रोजेक्ट रोडमैप](#प्रोजेक्ट-रोडमैप) को भी देख सकते हैं यह जानने के लिए कि क्या आपका विचार हमारी रणनीतिक दिशा के अनुरूप है।
+### विश्वसनीयता पहले
-## प्रोजेक्ट रोडमैप
+- सुनिश्चित करें कि diff एडिटिंग और कमांड एक्जीक्यूशन लगातार विश्वसनीय हों
+- नियमित उपयोग को हतोत्साहित करने वाले फ्रिक्शन पॉइंट्स को कम करें
+- सभी भाषाओं और प्लेटफॉर्म्स पर सुचारू संचालन की गारंटी दें
+- विभिन्न AI प्रदाताओं और मॉडल्स के लिए मजबूत समर्थन का विस्तार करें
-Roo Code का एक स्पष्ट विकास रोडमैप है जो हमारी प्राथमिकताओं और भविष्य की दिशा का मार्गदर्शन करता है। हमारे रोडमैप को समझने से आपको मदद मिल सकती है:
+### बेहतर उपयोगकर्ता अनुभव
-- अपने योगदान को प्रोजेक्ट के लक्ष्यों के साथ संरेखित करना
-- ऐसे क्षेत्रों की पहचान करना जहां आपकी विशेषज्ञता सबसे मूल्यवान होगी
-- कुछ डिज़ाइन निर्णयों के पीछे के संदर्भ को समझना
-- नई विशेषताओं के लिए प्रेरणा पाना जो हमारे दृष्टिकोण का समर्थन करती हैं
+- स्पष्टता और सहजता के लिए UI/UX को सरल बनाएं
+- डेवलपर्स के उच्च अपेक्षाओं को पूरा करने के लिए वर्कफ़्लो में निरंतर सुधार करें
-हमारा वर्तमान रोडमैप छह प्रमुख स्तंभों पर केंद्रित है:
+### एजेंट प्रदर्शन में अग्रणी
-### प्रोवाइडर सपोर्ट
+- वास्तविक दुनिया की उत्पादकता को मापने के लिए व्यापक मूल्यांकन बेंचमार्क (evals) स्थापित करें
+- हर किसी के लिए इन मूल्यांकनों को आसानी से चलाना और समझना संभव बनाएं
+- ऐसे सुधार लाएं जो मूल्यांकन स्कोर में स्पष्ट वृद्धि दिखाएं
-हम जितने संभव हो सके उतने प्रोवाइडर्स को सपोर्ट करना चाहते हैं:
+अपने PR में इन क्षेत्रों से संबंधित कार्य का उल्लेख करें।
-- "OpenAI Compatible" के लिए अधिक बहुमुखी समर्थन
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Ollama और LM Studio के लिए बेहतर समर्थन
+### 3. Roo Code कम्युनिटी से जुड़ें
-### मॉडल सपोर्ट
+- **मुख्य तरीका:** हमारे [Discord](https://discord.gg/roocode) से जुड़ें और **Hannes Rudolph (`hrudolph`)** को DM भेजें।
+- **विकल्प:** अनुभवी योगदानकर्ता [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1) के माध्यम से सीधे भाग ले सकते हैं।
-हम चाहते हैं कि Roo जितना संभव हो उतने मॉडल पर अच्छी तरह से काम करे, जिसमें लोकल मॉडल भी शामिल हैं:
+## अपना योगदान ढूंढना और योजना बनाना
-- कस्टम सिस्टम प्रॉम्प्टिंग और वर्कफ़्लोज़ के माध्यम से लोकल मॉडल सपोर्ट
-- बेंचमार्किंग एवैल्युएशन और टेस्ट केस
+### योगदान के प्रकार
-### सिस्टम सपोर्ट
+- **बग फिक्स:** कोड की समस्याओं को हल करना।
+- **नई विशेषताएं:** नई कार्यक्षमता जोड़ना।
+- **डॉक्युमेंटेशन:** गाइड सुधारना और स्पष्टता बढ़ाना।
-हम चाहते हैं कि Roo हर किसी के कंप्यूटर पर अच्छी तरह से चले:
+### Issue-First एप्रोच
-- क्रॉस प्लेटफॉर्म टर्मिनल इंटीग्रेशन
-- Mac, Windows और Linux के लिए मजबूत और सुसंगत समर्थन
+हर योगदान GitHub Issue से शुरू होना चाहिए।
-### डॉक्युमेंटेशन
+- **मौजूदा Issues देखें:** [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues) में खोजें।
+- **Issue बनाएं:** उपयुक्त टेम्पलेट का उपयोग करें:
+ - **बग:** "Bug Report" टेम्पलेट।
+ - **फीचर्स:** "Detailed Feature Proposal" टेम्पलेट। शुरू करने से पहले अनुमोदन आवश्यक है।
+- **Issue क्लेम करें:** कमेंट करें और आधिकारिक असाइनमेंट का इंतजार करें।
-हम सभी उपयोगकर्ताओं और योगदानकर्ताओं के लिए व्यापक, सुलभ दस्तावेज़ीकरण चाहते हैं:
+**अनुमोदित Issue के बिना PR बंद किए जा सकते हैं।**
-- विस्तारित उपयोगकर्ता गाइड और ट्यूटोरियल
-- स्पष्ट API दस्तावेज़ीकरण
-- योगदानकर्ताओं के लिए बेहतर मार्गदर्शन
-- बहुभाषी दस्तावेज़ीकरण संसाधन
-- इंटरैक्टिव उदाहरण और कोड सैंपल
+### क्या काम करें चुनना
-### स्थिरता
+- [GitHub प्रोजेक्ट](https://github.com/orgs/RooVetGit/projects/1) में असाइन न किए गए "Good First Issues" देखें।
+- डॉक्युमेंटेशन के लिए, [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs) देखें।
-हम बग की संख्या को काफी कम करना और स्वचालित परीक्षण को बढ़ाना चाहते हैं:
+### बग या समस्या रिपोर्ट करना
-- डीबग लॉगिंग स्विच
-- बग/सपोर्ट अनुरोधों के साथ भेजने के लिए "मशीन/टास्क इन्फॉर्मेशन" कॉपी बटन
+- पहले मौजूदा रिपोर्ट देखें।
+- ["Bug Report" टेम्पलेट](https://github.com/RooVetGit/Roo-Code/issues/new/choose) का उपयोग करके नए बग रिपोर्ट बनाएं।
+- **सुरक्षा कमजोरियां:** [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new) के माध्यम से निजी तौर पर रिपोर्ट करें।
-### अंतर्राष्ट्रीयकरण
+## विकास और सबमिशन प्रक्रिया
-हम चाहते हैं कि Roo हर किसी की भाषा बोले:
+### विकास सेटअप
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-हम विशेष रूप से उन योगदानों का स्वागत करते हैं जो हमारे रोडमैप लक्ष्यों को आगे बढ़ाते हैं। यदि आप कुछ ऐसा कर रहे हैं जो इन स्तंभों के अनुरूप है, तो कृपया अपने PR विवरण में इसका उल्लेख करें।
-
-## डेवलपमेंट सेटअप
-
-1. रिपो **क्लोन** करें:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **डिपेंडेंसीज इंस्टॉल** करें:
-
-```sh
-npm run install:all
-```
-
-3. **वेबव्यू शुरू करें (Vite/React ऐप HMR के साथ)**:
-
-```sh
-npm run dev
+git clone https://github.com/आपका_यूज़रनेम/Roo-Code.git
```
-4. **डिबग**:
- VSCode में `F5` दबाएं (या **Run** → **Start Debugging**) Roo Code लोड के साथ एक नया सेशन खोलने के लिए।
+2. **डिपेंडेंसी इंस्टॉल करें:**
-वेबव्यू में परिवर्तन तुरंत दिखाई देंगे। कोर एक्सटेंशन में परिवर्तनों के लिए एक्सटेंशन होस्ट को रीस्टार्ट करने की आवश्यकता होगी।
-
-वैकल्पिक रूप से आप .vsix बना सकते हैं और इसे सीधे VSCode में इंस्टॉल कर सकते हैं:
-
-```sh
-npm run build
```
-
-`bin/` डायरेक्टरी में एक `.vsix` फ़ाइल दिखाई देगी जिसे इस कमांड से इंस्टॉल किया जा सकता है:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## कोड लिखना और सबमिट करना
-
-कोई भी Roo Code में कोड का योगदान दे सकता है, लेकिन हम आपसे अनुरोध करते हैं कि आप इन दिशानिर्देशों का पालन करें ताकि आपके योगदान को सुचारू रूप से एकीकृत किया जा सके:
-
-1. **पुल रिक्वेस्ट को फोकस्ड रखें**
-
- - PR को एक ही फीचर या बग फिक्स तक सीमित रखें
- - बड़े परिवर्तनों को छोटी, संबंधित PR में विभाजित करें
- - परिवर्तनों को तार्किक कमिट्स में तोड़ें जिन्हें स्वतंत्र रूप से समीक्षा की जा सके
-
-2. **कोड क्वालिटी**
+3. **डिबगिंग:** VS Code में `F5` दबाएं।
- - सभी PR को CI चेक पास करना चाहिए जिसमें लिंटिंग और फॉर्मेटिंग दोनों शामिल हैं
- - सबमिट करने से पहले किसी भी ESLint चेतावनी या त्रुटि को संबोधित करें
- - Ellipsis, हमारे स्वचालित कोड समीक्षा टूल से सभी फीडबैक का जवाब दें
- - TypeScript के बेस्ट प्रैक्टिस का पालन करें और टाइप सुरक्षा बनाए रखें
+### कोड लिखने के दिशा-निर्देश
-3. **टेस्टिंग**
+- प्रति फीचर या फिक्स एक फोकस्ड PR।
+- ESLint और TypeScript बेस्ट प्रैक्टिस का पालन करें।
+- स्पष्ट, वर्णनात्मक कमिट मैसेज लिखें जो Issues को रेफर करें (जैसे `Fixes #123`)।
+- पूर्ण टेस्टिंग प्रदान करें (`npm test`)।
+- सबमिट करने से पहले अपनी ब्रांच को नवीनतम `main` पर रीबेस करें।
- - नई विशेषताओं के लिए टेस्ट जोड़ें
- - यह सुनिश्चित करने के लिए `npm test` चलाएं कि सभी टेस्ट पास हों
- - यदि आपके परिवर्तन उन्हें प्रभावित करते हैं तो मौजूदा टेस्ट अपडेट करें
- - जहां उपयुक्त हो, यूनिट टेस्ट और इंटीग्रेशन टेस्ट दोनों शामिल करें
+### Pull Request सबमिट करना
-4. **कमिट दिशानिर्देश**
+- अगर आप शुरुआती फीडबैक चाहते हैं तो **ड्राफ्ट PR** से शुरू करें।
+- Pull Request टेम्पलेट का पालन करते हुए अपने परिवर्तनों का स्पष्ट वर्णन करें।
+- UI परिवर्तनों के लिए स्क्रीनशॉट/वीडियो प्रदान करें।
+- बताएं कि क्या डॉक्युमेंटेशन अपडेट आवश्यक हैं।
- - स्पष्ट, वर्णनात्मक कमिट संदेश लिखें
- - #issue-number का उपयोग करके कमिट्स में प्रासंगिक मुद्दों का संदर्भ दें
+### Pull Request नीति
-5. **सबमिट करने से पहले**
+- पूर्व-अनुमोदित और असाइन किए गए Issues का संदर्भ देना चाहिए।
+- नीति का पालन न करने वाले PR बंद किए जा सकते हैं।
+- PR को CI टेस्ट पास करना चाहिए, रोडमैप से मेल खाना चाहिए, और स्पष्ट डॉक्युमेंटेशन होनी चाहिए।
- - अपनी ब्रांच को लेटेस्ट मेन पर रीबेस करें
- - सुनिश्चित करें कि आपकी ब्रांच सफलतापूर्वक बिल्ड होती है
- - डबल-चेक करें कि सभी टेस्ट पास हो रहे हैं
- - अपने परिवर्तनों की समीक्षा करें किसी भी डिबगिंग कोड या कंसोल लॉग के लिए
+### समीक्षा प्रक्रिया
-6. **पुल रिक्वेस्ट विवरण**
- - स्पष्ट रूप से बताएं कि आपके परिवर्तन क्या करते हैं
- - परिवर्तनों का परीक्षण करने के लिए चरण शामिल करें
- - किसी भी ब्रेकिंग चेंज की सूची बनाएं
- - UI परिवर्तनों के लिए स्क्रीनशॉट जोड़ें
+- **दैनिक ट्रायज:** मेंटेनर्स द्वारा त्वरित जांच।
+- **साप्ताहिक गहन समीक्षा:** व्यापक मूल्यांकन।
+- **फीडबैक के आधार पर तेजी से सुधार** करें।
-## योगदान समझौता
+## कानूनी
-पुल रिक्वेस्ट सबमिट करके, आप सहमत होते हैं कि आपके योगदान को प्रोजेक्ट के समान लाइसेंस ([Apache 2.0](../LICENSE)) के तहत लाइसेंस दिया जाएगा।
+Pull Request सबमिट करके, आप सहमत होते हैं कि आपके योगदान Roo Code के लाइसेंसिंग के अनुरूप Apache 2.0 लाइसेंस के तहत लाइसेंस किए जाएंगे।
diff --git a/locales/hi/README.md b/locales/hi/README.md
index 2d14f74ef90..d9313f05f67 100644
--- a/locales/hi/README.md
+++ b/locales/hi/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • हिन्दी • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • हिन्दी • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
चाहे आप एक लचीला कोडिंग पार्टनर, सिस्टम आर्किटेक्ट, या क्यूए इंजीनियर या प्रोडक्ट मैनेजर जैसी विशेष भूमिकाओं की तलाश कर रहे हों, Roo Code आपको अधिक कुशलता से सॉफ्टवेयर बनाने में मदद कर सकता है।
-विस्तृत अपडेट और फिक्स के लिए [CHANGELOG](../CHANGELOG.md) देखें।
+विस्तृत अपडेट और फिक्स के लिए [CHANGELOG](../../CHANGELOG.md) देखें।
---
-## 🎉 Roo Code 3.15 जारी
+## 🎉 Roo Code 3.17 जारी
-Roo Code 3.15 आपकी प्रतिक्रियाओं के आधार पर नई सुविधाएँ और सुधार लाता है!
+Roo Code 3.17 आपकी प्रतिक्रियाओं के आधार पर शक्तिशाली नई सुविधाएँ और सुधार लाता है!
-- **Vertex के लिए प्रॉम्प्ट कैशिंग** - Vertex AI अब प्रॉम्प्ट कैशिंग का समर्थन करता है, जिससे प्रतिक्रिया समय में सुधार और API लागत में कमी आती है।
-- **टर्मिनल फॉलबैक** - VSCode टर्मिनल शेल एकीकरण विफल होने पर एक फॉलबैक तंत्र लागू किया गया है, जिससे अधिक विश्वसनीय टर्मिनल संचालन सुनिश्चित होता है।
-- **बेहतर कोड स्निपेट्स** - चैट इंटरफेस में कोड स्निपेट्स की रेंडरिंग और इंटरैक्शन को बेहतर पठनीयता और उपयोगिता के लिए बढ़ाया गया है।
+- **Gemini के लिए स्वचालित कैशिंग** - Gemini API कॉल अब स्वचालित रूप से कैश किए जाते हैं, जिससे API लागत कम होती है।
+- **स्मार्ट मोड चयन** - मोड परिभाषाओं में अब यह निर्देश शामिल किया जा सकता है कि प्रत्येक मोड कब उपयोग किया जाना चाहिए, जिससे बेहतर ऑर्केस्ट्रेशन संभव होता है।
+- **बुद्धिमान कॉन्टेक्स्ट कंडेंसिंग** - जब कॉन्टेक्स्ट भर जाता है, तो वार्तालाप इतिहास को काटने के बजाय बुद्धिमानी से सारांशित करता है (सेटिंग्स -> एक्सपेरिमेंटल में सक्षम करें)।
---
@@ -178,32 +178,36 @@ code --install-extension bin/roo-cline-.vsix
Roo Code को बेहतर बनाने में मदद करने वाले हमारे सभी योगदानकर्ताओं को धन्यवाद!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## लाइसेंस
diff --git a/locales/it/CODE_OF_CONDUCT.md b/locales/it/CODE_OF_CONDUCT.md
index b58e011b37d..7c6f5754e07 100644
--- a/locales/it/CODE_OF_CONDUCT.md
+++ b/locales/it/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • Italiano • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Codice di Condotta del Patto del Contributore
## Il Nostro Impegno
diff --git a/locales/it/CONTRIBUTING.md b/locales/it/CONTRIBUTING.md
index 9e6ca151113..66f4143f5fa 100644
--- a/locales/it/CONTRIBUTING.md
+++ b/locales/it/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Contribuire a Roo Code
-
-Siamo entusiasti che tu sia interessato a contribuire a Roo Code. Che tu stia correggendo un bug, aggiungendo una funzionalità o migliorando la nostra documentazione, ogni contributo rende Roo Code più intelligente! Per mantenere la nostra comunità vivace e accogliente, tutti i membri devono aderire al nostro [Codice di Condotta](CODE_OF_CONDUCT.md).
-
-## Unisciti alla Nostra Comunità
-
-Incoraggiamo fortemente tutti i contributori a unirsi alla nostra [comunità Discord](https://discord.gg/roocode)! Far parte del nostro server Discord ti aiuta a:
-
-- Ottenere aiuto e guida in tempo reale sui tuoi contributi
-- Connetterti con altri contributori e membri del team principale
-- Rimanere aggiornato sugli sviluppi e le priorità del progetto
-- Partecipare a discussioni che modellano il futuro di Roo Code
-- Trovare opportunità di collaborazione con altri sviluppatori
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • Italiano • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Segnalare Bug o Problemi
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Le segnalazioni di bug aiutano a migliorare Roo Code per tutti! Prima di creare un nuovo problema, per favore [cerca tra quelli esistenti](https://github.com/RooVetGit/Roo-Code/issues) per evitare duplicati. Quando sei pronto a segnalare un bug, vai alla nostra [pagina dei problemi](https://github.com/RooVetGit/Roo-Code/issues/new/choose) dove troverai un modello per aiutarti a compilare le informazioni rilevanti.
-
-
- 🔐 Importante: Se scopri una vulnerabilità di sicurezza, utilizza lo strumento di sicurezza Github per segnalarla privatamente.
-
+# Contribuire a Roo Code
-## Decidere Su Cosa Lavorare
+Roo Code è un progetto guidato dalla community e apprezziamo molto ogni contributo. Per semplificare la collaborazione, operiamo secondo un approccio [Issue-First](#approccio-issue-first), il che significa che tutte le [Pull Request (PR)](#inviare-una-pull-request) devono prima essere collegate a una Issue GitHub. Ti preghiamo di leggere attentamente questa guida.
-Cerchi un buon primo contributo? Controlla i problemi nella sezione "Issue [Unassigned]" del nostro [Progetto Github di Roo Code](https://github.com/orgs/RooVetGit/projects/1). Questi sono specificamente selezionati per nuovi contributori e aree in cui ci piacerebbe avere un po' di aiuto!
+## Indice
-Accogliamo anche contributi alla nostra [documentazione](https://docs.roocode.com/)! Che si tratti di correggere errori di battitura, migliorare guide esistenti o creare nuovi contenuti educativi - ci piacerebbe costruire un repository di risorse guidato dalla comunità che aiuti tutti a ottenere il massimo da Roo Code. Puoi cliccare su "Edit this page" su qualsiasi pagina per arrivare rapidamente al punto giusto in Github per modificare il file, oppure puoi andare direttamente a https://github.com/RooVetGit/Roo-Code-Docs.
+- [Prima di contribuire](#prima-di-contribuire)
+- [Trovare e pianificare il tuo contributo](#trovare-e-pianificare-il-tuo-contributo)
+- [Processo di sviluppo e invio](#processo-di-sviluppo-e-invio)
+- [Legale](#legale)
-Se stai pianificando di lavorare su una funzionalità più grande, per favore crea prima una [richiesta di funzionalità](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) così possiamo discutere se si allinea con la visione di Roo Code. Puoi anche consultare la nostra [Roadmap del Progetto](#roadmap-del-progetto) qui sotto per vedere se la tua idea si adatta alla nostra direzione strategica.
+## Prima di contribuire
-## Roadmap del Progetto
+### 1. Codice di condotta
-Roo Code ha una chiara roadmap di sviluppo che guida le nostre priorità e la direzione futura. Comprendere la nostra roadmap può aiutarti a:
+Tutti i collaboratori devono rispettare il nostro [Codice di condotta](./CODE_OF_CONDUCT.md).
-- Allineare i tuoi contributi con gli obiettivi del progetto
-- Identificare aree in cui la tua esperienza sarebbe più preziosa
-- Comprendere il contesto dietro certe decisioni di design
-- Trovare ispirazione per nuove funzionalità che supportino la nostra visione
+### 2. Roadmap del progetto
-La nostra roadmap attuale si concentra su sei pilastri chiave:
+La nostra roadmap guida la direzione del progetto. Allinea i tuoi contributi con questi obiettivi chiave:
-### Supporto Provider
+### Affidabilità prima di tutto
-Miriamo a supportare quanti più provider possibile:
+- Garantire che l'editing delle differenze e l'esecuzione dei comandi siano costantemente affidabili
+- Ridurre i punti di attrito che scoraggiano l'uso regolare
+- Garantire un funzionamento fluido in tutte le lingue e su tutte le piattaforme
+- Ampliare il supporto robusto per una vasta gamma di provider e modelli di IA
-- Supporto più versatile per "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Supporto migliorato per Ollama e LM Studio
+### Esperienza utente migliorata
-### Supporto Modelli
+- Semplificare l'interfaccia utente per maggiore chiarezza e intuitività
+- Migliorare continuamente il flusso di lavoro per soddisfare le elevate aspettative degli sviluppatori
-Vogliamo che Roo funzioni al meglio su quanti più modelli possibile, inclusi i modelli locali:
+### Leadership nelle prestazioni degli agenti
-- Supporto per modelli locali attraverso prompt di sistema personalizzati e flussi di lavoro
-- Valutazioni di benchmark e casi di test
+- Stabilire parametri di valutazione completi (evals) per misurare la produttività nel mondo reale
+- Rendere facile per tutti eseguire e interpretare queste valutazioni
+- Fornire miglioramenti che dimostrino chiari aumenti nei punteggi di valutazione
-### Supporto Sistemi
+Menziona l'allineamento con queste aree nelle tue PR.
-Vogliamo che Roo funzioni bene sul computer di tutti:
+### 3. Unisciti alla community Roo Code
-- Integrazione del terminale multipiattaforma
-- Supporto forte e coerente per Mac, Windows e Linux
+- **Principale:** Unisciti al nostro [Discord](https://discord.gg/roocode) e invia un DM a **Hannes Rudolph (`hrudolph`)**.
+- **Alternativa:** I collaboratori esperti possono partecipare direttamente tramite [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Documentazione
+## Trovare e pianificare il tuo contributo
-Vogliamo una documentazione completa e accessibile per tutti gli utenti e contributori:
+### Tipi di contributi
-- Guide utente e tutorial ampliati
-- Documentazione API chiara
-- Migliore orientamento per i contributori
-- Risorse di documentazione multilingue
-- Esempi interattivi e campioni di codice
+- **Correzione bug:** Risolvere problemi nel codice.
+- **Nuove funzionalità:** Aggiungere nuove funzionalità.
+- **Documentazione:** Migliorare guide e chiarezza.
-### Stabilità
+### Approccio Issue-First
-Vogliamo ridurre significativamente il numero di bug e aumentare i test automatizzati:
+Tutti i contributi devono iniziare con una Issue GitHub.
-- Interruttore di registrazione debug
-- Pulsante di copia "Informazioni Macchina/Attività" per l'invio con richieste di supporto/bug
+- **Verificare le issue esistenti:** Cerca su [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Creare una issue:** Usa i template appropriati:
+ - **Bug:** Template "Bug Report".
+ - **Funzionalità:** Template "Detailed Feature Proposal". Approvazione richiesta prima di iniziare.
+- **Reclamare issue:** Commenta e attendi l'assegnazione ufficiale.
-### Internazionalizzazione
+**Le PR senza issue approvate potrebbero essere chiuse.**
-Vogliamo che Roo parli la lingua di tutti:
+### Decidere su cosa lavorare
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Controlla il [Progetto GitHub](https://github.com/orgs/RooVetGit/projects/1) per "Good First Issues" non assegnate.
+- Per la documentazione, visita [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Accogliamo particolarmente i contributi che fanno progredire gli obiettivi della nostra roadmap. Se stai lavorando su qualcosa che si allinea con questi pilastri, per favore menzionalo nella descrizione della tua PR.
+### Segnalare bug
-## Configurazione per lo Sviluppo
+- Controlla prima i report esistenti.
+- Crea nuovi report di bug usando il [template "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Problemi di sicurezza:** Segnala privatamente tramite [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Clona** il repository:
+## Processo di sviluppo e invio
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Configurazione dello sviluppo
-2. **Installa le dipendenze**:
+1. **Fork & Clona:**
-```sh
-npm run install:all
```
-
-3. **Avvia la webview (app Vite/React con HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/TUO_USERNAME/Roo-Code.git
```
-4. **Debug**:
- Premi `F5` (o **Run** → **Start Debugging**) in VSCode per aprire una nuova sessione con Roo Code caricato.
-
-Le modifiche alla webview appariranno immediatamente. Le modifiche all'estensione principale richiederanno un riavvio dell'host dell'estensione.
-
-In alternativa puoi creare un file .vsix e installarlo direttamente in VSCode:
+2. **Installa le dipendenze:**
-```sh
-npm run build
```
-
-Un file `.vsix` apparirà nella directory `bin/` che può essere installato con:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Scrivere e Inviare Codice
-
-Chiunque può contribuire con codice a Roo Code, ma ti chiediamo di seguire queste linee guida per assicurare che i tuoi contributi possano essere integrati senza problemi:
-
-1. **Mantieni le Pull Request Focalizzate**
-
- - Limita le PR a una singola funzionalità o correzione di bug
- - Suddividi i cambiamenti più grandi in PR più piccole e correlate
- - Suddividi i cambiamenti in commit logici che possono essere revisionati indipendentemente
-
-2. **Qualità del Codice**
+3. **Debug:** Apri con VS Code (`F5`).
- - Tutte le PR devono passare i controlli CI che includono sia linting che formattazione
- - Risolvi qualsiasi avviso o errore di ESLint prima di inviare
- - Rispondi a tutti i feedback da Ellipsis, il nostro strumento automatico di revisione del codice
- - Segui le migliori pratiche di TypeScript e mantieni la sicurezza dei tipi
+### Linee guida per scrivere codice
-3. **Testing**
+- Una PR focalizzata per funzionalità o correzione.
+- Segui le best practice di ESLint e TypeScript.
+- Scrivi commit chiari e descrittivi che fanno riferimento alle issue (es. `Fixes #123`).
+- Fornisci test approfonditi (`npm test`).
+- Fai rebase sul branch `main` più recente prima dell'invio.
- - Aggiungi test per le nuove funzionalità
- - Esegui `npm test` per assicurarti che tutti i test passino
- - Aggiorna i test esistenti se le tue modifiche li influenzano
- - Includi sia test unitari che test di integrazione dove appropriato
+### Inviare una Pull Request
-4. **Linee Guida per i Commit**
+- Inizia come **PR in bozza** se cerchi feedback anticipato.
+- Descrivi chiaramente le tue modifiche seguendo il Template di Pull Request.
+- Fornisci screenshot/video per modifiche UI.
+- Indica se sono necessari aggiornamenti alla documentazione.
- - Scrivi messaggi di commit chiari e descrittivi
- - Fai riferimento ai problemi rilevanti nei commit usando #numero-problema
+### Politica di Pull Request
-5. **Prima di Inviare**
+- Deve fare riferimento a issue pre-approvate e assegnate.
+- Le PR che non rispettano la politica potrebbero essere chiuse.
+- Le PR dovrebbero superare i test CI, allinearsi con la roadmap e avere documentazione chiara.
- - Fai il rebase del tuo branch sull'ultimo main
- - Assicurati che il tuo branch si costruisca con successo
- - Ricontrolla che tutti i test stiano passando
- - Rivedi le tue modifiche per qualsiasi codice di debug o log della console
+### Processo di revisione
-6. **Descrizione della Pull Request**
- - Descrivi chiaramente cosa fanno le tue modifiche
- - Includi passaggi per testare le modifiche
- - Elenca eventuali breaking changes
- - Aggiungi screenshot per modifiche UI
+- **Triage quotidiano:** Controlli rapidi da parte dei maintainer.
+- **Revisione settimanale approfondita:** Valutazione completa.
+- **Itera rapidamente** in base al feedback.
-## Accordo di Contribuzione
+## Legale
-Inviando una pull request, accetti che i tuoi contributi saranno concessi in licenza con la stessa licenza del progetto ([Apache 2.0](../LICENSE)).
+Inviando una pull request, accetti che i tuoi contributi siano concessi in licenza sotto la Licenza Apache 2.0, in linea con la licenza di Roo Code.
diff --git a/locales/it/README.md b/locales/it/README.md
index dbf6fb5e886..a6c8387da26 100644
--- a/locales/it/README.md
+++ b/locales/it/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • Italiano • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • Italiano • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Che tu stia cercando un partner di codifica flessibile, un architetto di sistema o ruoli specializzati come un ingegnere QA o un product manager, Roo Code può aiutarti a costruire software in modo più efficiente.
-Consulta il [CHANGELOG](../CHANGELOG.md) per aggiornamenti dettagliati e correzioni.
+Consulta il [CHANGELOG](../../CHANGELOG.md) per aggiornamenti dettagliati e correzioni.
---
-## 🎉 Roo Code 3.15 Rilasciato
+## 🎉 Roo Code 3.17 Rilasciato
-Roo Code 3.15 porta nuove funzionalità e miglioramenti basati sui tuoi feedback!
+Roo Code 3.17 porta potenti nuove funzionalità e miglioramenti basati sui tuoi feedback!
-- **Cache per i prompt in Vertex** - Vertex AI ora supporta la cache dei prompt, migliorando i tempi di risposta e riducendo i costi API.
-- **Fallback del Terminale** - Implementato un meccanismo di fallback quando l'integrazione della shell del terminale VSCode fallisce, garantendo operazioni del terminale più affidabili.
-- **Snippet di Codice Migliorati** - Rendering e interazione migliorati degli snippet di codice nell'interfaccia di chat per una migliore leggibilità e usabilità.
+- **Caching implicito per Gemini** - Le chiamate API Gemini vengono ora memorizzate automaticamente nella cache, riducendo i costi API.
+- **Selezione delle modalità più intelligente** - Le definizioni delle modalità possono ora includere indicazioni su quando utilizzare ciascuna modalità, consentendo una migliore orchestrazione.
+- **Condensazione intelligente del contesto** - Riassume intelligentemente la cronologia delle conversazioni quando il contesto si riempie invece di troncarla (attivabile in Impostazioni -> Sperimentale).
---
@@ -178,32 +178,36 @@ Amiamo i contributi della community! Inizia leggendo il nostro [CONTRIBUTING.md]
Grazie a tutti i nostri contributori che hanno aiutato a migliorare Roo Code!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Licenza
diff --git a/locales/ja/CODE_OF_CONDUCT.md b/locales/ja/CODE_OF_CONDUCT.md
index 9dbb9b776dc..fb7dd9b11a6 100644
--- a/locales/ja/CODE_OF_CONDUCT.md
+++ b/locales/ja/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+日本語 • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# コントリビューター行動規範
## 私たちの誓約
diff --git a/locales/ja/CONTRIBUTING.md b/locales/ja/CONTRIBUTING.md
index 42be40e33d2..2fd4a436768 100644
--- a/locales/ja/CONTRIBUTING.md
+++ b/locales/ja/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Roo Codeへの貢献
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-Roo Codeへの貢献に興味を持っていただき、ありがとうございます。バグの修正、機能の追加、またはドキュメントの改善など、すべての貢献がRoo Codeをよりスマートにします!コミュニティを活気に満ちた歓迎的なものに保つため、すべてのメンバーは[行動規範](CODE_OF_CONDUCT.md)を順守する必要があります。
+日本語 • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## コミュニティに参加する
+# Roo Code への貢献
-すべての貢献者に[Discordコミュニティ](https://discord.gg/roocode)への参加を強く推奨します!Discordサーバーに参加することで以下のメリットがあります:
+Roo Code はコミュニティ主導のプロジェクトであり、すべての貢献を大切にしています。協力をスムーズにするため、[Issue-First](#issue-first-アプローチ)方式を採用しています。これはすべての[Pull Request (PR)](#pull-request-の提出)がまずGitHub Issueに紐付けられる必要があることを意味します。このガイドをよく読んでください。
-- 貢献に関するリアルタイムのヘルプとガイダンスを得られる
-- 他の貢献者やコアチームメンバーとつながれる
-- プロジェクトの開発と優先事項について最新情報を得られる
-- Roo Codeの将来を形作るディスカッションに参加できる
-- 他の開発者とのコラボレーションの機会を見つけられる
+## 目次
-## バグや問題の報告
+- [貢献する前に](#貢献する前に)
+- [貢献内容の発見と計画](#貢献内容の発見と計画)
+- [開発と提出のプロセス](#開発と提出のプロセス)
+- [法的事項](#法的事項)
-バグレポートはRoo Codeをより良くするのに役立ちます!新しい課題を作成する前に、重複を避けるために[既存の課題を検索](https://github.com/RooVetGit/Roo-Code/issues)してください。バグを報告する準備ができたら、関連情報の入力を手助けするテンプレートが用意されている[課題ページ](https://github.com/RooVetGit/Roo-Code/issues/new/choose)にアクセスしてください。
+## 貢献する前に
-
- 🔐 重要: セキュリティ脆弱性を発見した場合は、Githubセキュリティツールを使用して非公開で報告してください。
-
+### 1. 行動規範
-## 取り組む内容の決定
+すべてのコントリビューターは[行動規範](./CODE_OF_CONDUCT.md)を守る必要があります。
-良い最初の貢献を探していますか?[Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1) Githubプロジェクトの「Issue [Unassigned]」セクションの課題をチェックしてください。これらは新しい貢献者や私たちが助けを必要としている領域のために特別に選ばれています!
+### 2. プロジェクトロードマップ
-また、[ドキュメント](https://docs.roocode.com/)への貢献も歓迎します!タイプミスの修正、既存ガイドの改善、または新しい教育コンテンツの作成など、Roo Codeを最大限に活用するためのコミュニティ主導のリソースリポジトリの構築を目指しています。任意のページで「Edit this page」をクリックすると、ファイルを編集するためのGithubの適切な場所にすぐに移動できます。または、https://github.com/RooVetGit/Roo-Code-Docs に直接アクセスすることもできます。
+ロードマップはプロジェクトの方向性を示します。貢献をこれらの主要目標に沿わせてください:
-より大きな機能に取り組む予定がある場合は、Roo Codeのビジョンに合致するかどうかを議論するために、まず[機能リクエスト](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop)を作成してください。また、アイデアが私たちの戦略的方向性に合っているかどうかを確認するために、下記の[プロジェクトロードマップ](#プロジェクトロードマップ)をチェックすることもできます。
+### 信頼性優先
-## プロジェクトロードマップ
+- diff編集とコマンド実行が常に信頼できることを保証
+- 定期的な使用を妨げる摩擦ポイントの削減
+- すべての言語環境とプラットフォームでのスムーズな動作を保証
+- 様々なAIプロバイダーとモデルへの堅牢なサポートを拡大
-Roo Codeには、私たちの優先事項と将来の方向性を導く明確な開発ロードマップがあります。私たちのロードマップを理解することで、以下のような助けになります:
+### ユーザー体験の強化
-- あなたの貢献をプロジェクトの目標に合わせる
-- あなたの専門知識が最も価値がある領域を特定する
-- 特定のデザイン決定の背景を理解する
-- 私たちのビジョンをサポートする新機能のインスピレーションを得る
+- 明確さと直感性のためのUI/UXの合理化
+- 開発者が日常的に使用するツールに求める高い期待に応えるためのワークフローの継続的改善
-現在のロードマップは、6つの主要な柱に焦点を当てています:
+### エージェントパフォーマンスの先導
-### プロバイダーサポート
+- 実際の生産性を測定する包括的な評価基準(evals)の確立
+- 誰もが簡単にこれらの評価を実行して解釈できるようにする
+- 評価スコアの明確な向上を示す改善を提供
-できるだけ多くのプロバイダーをサポートすることを目指しています:
+PRでこれらの領域との関連性に言及してください。
-- より汎用的な「OpenAI互換」サポート
-- xAI、Microsoft Azure AI、Alibaba Cloud Qwen、IBM Watsonx、Together AI、DeepInfra、Fireworks AI、Cohere、Perplexity AI、FriendliAI、Replicate
-- OllamaとLM Studioの強化されたサポート
+### 3. Roo Code コミュニティに参加する
-### モデルサポート
+- **主な方法:** [Discord](https://discord.gg/roocode)に参加し、**Hannes Rudolph (`hrudolph`)**にDMを送る。
+- **代替手段:** 経験豊富なコントリビューターは[GitHub Projects](https://github.com/orgs/RooVetGit/projects/1)を通じて直接参加できます。
-ローカルモデルを含め、できるだけ多くのモデルでRooが良好に動作することを望んでいます:
+## 貢献内容の発見と計画
-- カスタムシステムプロンプティングとワークフローを通じたローカルモデルサポート
-- ベンチマーク評価とテストケース
+### 貢献の種類
-### システムサポート
+- **バグ修正:** コードの問題を解決。
+- **新機能:** 機能を追加。
+- **ドキュメント:** ガイドを改善し明確にする。
-Rooが誰のコンピュータでも良好に動作することを望んでいます:
+### Issue-First アプローチ
-- クロスプラットフォームターミナル統合
-- Mac、Windows、Linuxの強力で一貫したサポート
+すべての貢献はGitHub Issueから始めてください。
-### ドキュメンテーション
+- **既存Issueの確認:** [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues)を検索。
+- **Issueの作成:** 適切なテンプレートを使用:
+ - **バグ:** 「Bug Report」テンプレート。
+ - **機能:** 「Detailed Feature Proposal」テンプレート。開始前に承認が必要。
+- **Issue担当表明:** コメントし、正式な割り当てを待つ。
-すべてのユーザーと貢献者のための包括的でアクセスしやすいドキュメントを望んでいます:
+**承認されたIssueに紐付けられていないPRは閉じられる可能性があります。**
-- 拡張されたユーザーガイドとチュートリアル
-- 明確なAPIドキュメント
-- 貢献者のためのより良いガイダンス
-- 多言語ドキュメントリソース
-- インタラクティブな例とコードサンプル
+### 何に取り組むか決める
-### 安定性
+- 未割り当ての「Good First Issues」を[GitHub Project](https://github.com/orgs/RooVetGit/projects/1)でチェック。
+- ドキュメント関連は[Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs)を参照。
-バグの数を大幅に減らし、自動テストを増やすことを望んでいます:
+### バグの報告
-- デバッグロギングスイッチ
-- バグ/サポートリクエストと一緒に送信するための「マシン/タスク情報」コピーボタン
+- まず既存の報告がないか確認。
+- 新しいバグは[「Bug Report」テンプレート](https://github.com/RooVetGit/Roo-Code/issues/new/choose)で報告。
+- **セキュリティ問題:** [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new)を通じて非公開で報告。
-### 国際化
+## 開発と提出のプロセス
-Rooが誰の言語も話すことを望んでいます:
+### 開発環境のセットアップ
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-私たちは特に、ロードマップの目標を前進させる貢献を歓迎します。これらの柱に沿った何かに取り組んでいる場合は、PRの説明でそれについて言及してください。
-
-## 開発のセットアップ
-
-1. リポジトリを**クローン**します:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **依存関係をインストール**します:
-
-```sh
-npm run install:all
-```
-
-3. **ウェブビュー(Vite/ReactアプリとHMR)を起動**します:
-
-```sh
-npm run dev
+git clone https://github.com/あなたのユーザー名/Roo-Code.git
```
-4. **デバッグ**:
- VSCodeで`F5`キー(または**実行**→**デバッグの開始**)を押すと、Roo Codeがロードされた新しいセッションが開きます。
+2. **依存関係のインストール:**
-ウェブビューへの変更はすぐに反映されます。コア拡張機能への変更は、拡張機能ホストの再起動が必要です。
-
-または、.vsixファイルをビルドしてVSCodeに直接インストールすることもできます:
-
-```sh
-npm run build
```
-
-`bin/`ディレクトリに`.vsix`ファイルが作成され、以下のコマンドでインストールできます:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## コードの作成と提出
-
-誰でもRoo Codeにコードを貢献できますが、貢献がスムーズに統合されるように以下のガイドラインに従ってください:
-
-1. **プルリクエストを焦点を絞ったものにする**
-
- - PRを単一の機能またはバグ修正に限定する
- - より大きな変更を小さく関連したPRに分割する
- - 変更を独立してレビューできる論理的なコミットに分ける
-
-2. **コード品質**
+3. **デバッグ:** VS Codeで`F5`を押して開く。
- - すべてのPRはlintingとフォーマットの両方を含むCIチェックに合格する必要がある
- - 提出前にESLintの警告やエラーを解決する
- - 自動コードレビューツールであるEllipsisからのすべてのフィードバックに対応する
- - TypeScriptのベストプラクティスに従い、型の安全性を維持する
+### コーディングガイドライン
-3. **テスト**
+- 1つの機能または修正ごとに1つのPR。
+- ESLintとTypeScriptのベストプラクティスに従う。
+- 関連Issueを参照する明確なコミットメッセージを書く(例:`Fixes #123`)。
+- 十分なテストを提供(`npm test`)。
+- 提出前に最新の`main`ブランチにリベース。
- - 新機能にはテストを追加する
- - `npm test`を実行してすべてのテストが合格することを確認する
- - 変更が影響する既存のテストを更新する
- - 適切な場合は単体テストと統合テストの両方を含める
+### Pull Request の提出
-4. **コミットガイドライン**
+- 早期フィードバックを求める場合は**ドラフトPR**から始める。
+- Pull Requestテンプレートに従って変更を明確に説明。
+- UI変更のスクリーンショット/動画を提供。
+- ドキュメント更新が必要かどうかを示す。
- - 明確で説明的なコミットメッセージを書く
- - #issue-number を使用してコミットで関連する課題を参照する
+### Pull Request ポリシー
-5. **提出前に**
+- 承認・割り当て済みIssueを参照する必要がある。
+- ポリシーに従わないPRは閉じられる可能性がある。
+- PRはCIテストに合格し、ロードマップに沿い、明確なドキュメントを持つべき。
- - 最新のmainブランチに対してあなたのブランチをリベースする
- - あなたのブランチが正常にビルドされることを確認する
- - すべてのテストが合格していることを再確認する
- - デバッグコードやコンソールログがないか変更を見直す
+### レビュープロセス
-6. **プルリクエストの説明**
- - 変更内容を明確に説明する
- - 変更をテストするための手順を含める
- - 破壊的変更がある場合はリストアップする
- - UI変更の場合はスクリーンショットを追加する
+- **日次トリアージ:** メンテナーによる迅速なチェック。
+- **週次詳細レビュー:** 包括的な評価。
+- **フィードバックに基づいて迅速に改善**。
-## 貢献同意
+## 法的事項
-プルリクエストを提出することにより、あなたの貢献がプロジェクトと同じライセンス([Apache 2.0](../LICENSE))の下でライセンスされることに同意したものとみなします。
+Pull Requestを提出することで、あなたの貢献がRoo Codeと同じApache 2.0ライセンスの下で提供されることに同意したことになります。
diff --git a/locales/ja/README.md b/locales/ja/README.md
index 3700bc271a5..46ffcd02a52 100644
--- a/locales/ja/README.md
+++ b/locales/ja/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
柔軟なコーディングパートナー、システムアーキテクト、QAエンジニアやプロダクトマネージャーなどの専門的な役割を求めているかどうかにかかわらず、Roo Codeはより効率的にソフトウェアを構築するのを手助けします。
-詳細な更新と修正については[CHANGELOG](../CHANGELOG.md)をご覧ください。
+詳細な更新と修正については[CHANGELOG](../../CHANGELOG.md)をご覧ください。
---
-## 🎉 Roo Code 3.15リリース
+## 🎉 Roo Code 3.17リリース
-Roo Code 3.15はユーザーのフィードバックに基づく新機能と改善を提供します!
+Roo Code 3.17はユーザーのフィードバックに基づく強力な新機能と改善を提供します!
-- **Vertex向けプロンプトキャッシング** - Vertex AIがプロンプトキャッシングをサポートするようになり、応答時間の改善とAPIコストの削減を実現しました
-- **ターミナルフォールバック** - VSCodeターミナルシェル統合が失敗した場合のフォールバックメカニズムを実装し、より信頼性の高いターミナル操作を確保しました
-- **コードスニペットの改善** - チャットインターフェースでのコードスニペットのレンダリングと操作性を向上させ、読みやすさと使いやすさを改善しました
+- **Geminiの暗黙的キャッシング** - Gemini APIコールが自動的にキャッシュされるようになり、APIコストが削減されます
+- **よりスマートなモード選択** - モード定義に各モードがいつ使用されるべきかの指針を含めることができるようになり、より良いオーケストレーションが可能になりました
+- **インテリジェントなコンテキスト凝縮** - コンテキストが一杯になったとき、切り捨てる代わりに会話履歴をインテリジェントに要約します(設定→実験的機能で有効化)
---
@@ -178,32 +178,36 @@ code --install-extension bin/roo-cline-.vsix
Roo Codeの改善に貢献してくれたすべての貢献者に感謝します!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## ライセンス
diff --git a/locales/ko/CODE_OF_CONDUCT.md b/locales/ko/CODE_OF_CONDUCT.md
index cb3bdfc4914..4b52ef8f279 100644
--- a/locales/ko/CODE_OF_CONDUCT.md
+++ b/locales/ko/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • 한국어 • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# 기여자 서약 행동 강령
## 우리의 약속
diff --git a/locales/ko/CONTRIBUTING.md b/locales/ko/CONTRIBUTING.md
index 342fcbc4512..ef216182da8 100644
--- a/locales/ko/CONTRIBUTING.md
+++ b/locales/ko/CONTRIBUTING.md
@@ -1,174 +1,129 @@
-# Roo Code에 기여하기
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-Roo Code에 기여하는 데 관심을 가져주셔서 기쁩니다. 버그를 수정하든, 기능을 추가하든, 문서를 개선하든, 모든 기여는 Roo Code를 더 스마트하게 만듭니다! 우리 커뮤니티를 활기차고 친절하게 유지하기 위해, 모든 구성원은 우리의 [행동 강령](CODE_OF_CONDUCT.md)을 준수해야 합니다.
+[日本語](../ja/CONTRIBUTING.md) • 한국어 • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## 우리 커뮤니티에 참여하세요
+# Roo Code 기여 가이드
-모든 기여자가 우리의 [Discord 커뮤니티](https://discord.gg/roocode)에 참여할 것을 강력히 권장합니다! Discord 서버의 일원이 되면 다음과 같은 도움을 받을 수 있습니다:
+Roo Code는 커뮤니티 주도의 프로젝트이며, 모든 기여를 소중하게 생각합니다. 협업을 간소화하기 위해 [Issue-First](#issue-first-접근법) 원칙을 적용하고 있으며, 이는 모든 [Pull Request (PR)](#pull-request-제출)가 먼저 GitHub Issue와 연결되어야 함을 의미합니다. 이 가이드를 주의 깊게 검토해 주세요.
-- 기여에 대한 실시간 도움과 지침 얻기
-- 다른 기여자 및 핵심 팀원과 연결
-- 프로젝트 개발 및 우선순위에 대한 최신 정보 유지
-- Roo Code의 미래를 형성하는 토론에 참여
-- 다른 개발자와의 협업 기회 찾기
+## 목차
-## 버그 또는 이슈 보고하기
+- [기여 전 준비](#기여-전-준비)
+- [기여 내용 찾기 및 계획 세우기](#기여-내용-찾기-및-계획-세우기)
+- [개발 및 제출 프로세스](#개발-및-제출-프로세스)
+- [법적 안내](#법적-안내)
-버그 보고는 모두를 위해 Roo Code를 더 좋게 만드는 데 도움이 됩니다! 새 이슈를 만들기 전에, 중복을 피하기 위해 [기존 이슈 검색](https://github.com/RooVetGit/Roo-Code/issues)을 해주세요. 버그를 보고할 준비가 되면, 관련 정보를 작성하는 데 도움이 되는 템플릿이 있는 [이슈 페이지](https://github.com/RooVetGit/Roo-Code/issues/new/choose)로 이동하세요.
+## 기여 전 준비
-
- 🔐 중요: 보안 취약점을 발견한 경우, 비공개로 보고하기 위해 Github 보안 도구를 사용하세요.
-
+### 1. 행동 강령
-## 작업할 내용 결정하기
+모든 기여자는 [행동 강령](./CODE_OF_CONDUCT.md)을 준수해야 합니다.
-첫 기여를 위한 좋은 시작점을 찾고 계신가요? 우리의 [Roo Code 이슈](https://github.com/orgs/RooVetGit/projects/1) Github 프로젝트의 "Issue [Unassigned]" 섹션에서 이슈를 확인하세요. 이러한 이슈들은 새로운 기여자와 우리가 도움을 필요로 하는 영역을 위해 특별히 선별되었습니다!
+### 2. 프로젝트 로드맵
-우리는 [문서](https://docs.roocode.com/)에 대한 기여도 환영합니다! 오타 수정, 기존 가이드 개선 또는 새로운 교육 콘텐츠 생성 등 - 모든 사람이 Roo Code를 최대한 활용할 수 있도록 도와주는 커뮤니티 기반 리소스 저장소를 구축하고 싶습니다. 모든
-페이지에서 "Edit this page"를 클릭하여 파일을 편집할 수 있는 Github의 적절한 위치로 빠르게 이동하거나, https://github.com/RooVetGit/Roo-Code-Docs에 직접 접근할 수 있습니다.
+로드맵은 프로젝트 방향을 안내합니다. 기여를 다음 핵심 목표에 맞추세요:
-더 큰 기능 작업을 계획하고 있다면, Roo Code의 비전과 일치하는지 논의할 수 있도록 먼저 [기능 요청](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop)을 생성해주세요. 또한 아이디어가 우리의 전략적 방향과 일치하는지 확인하기 위해 아래의 [프로젝트 로드맵](#프로젝트-로드맵)을 확인할 수도 있습니다.
+### 신뢰성 우선
-## 프로젝트 로드맵
+- diff 편집과 명령 실행의 일관된 신뢰성 보장
+- 정기적 사용을 방해하는 마찰점 감소
+- 모든 언어 환경과 플랫폼에서의 원활한 작동 보장
+- 다양한 AI 제공업체 및 모델에 대한 강력한 지원 확대
-Roo Code는 우리의 우선순위와 미래 방향을 안내하는 명확한 개발 로드맵을 가지고 있습니다. 우리의 로드맵을 이해하면 다음과 같은 도움을 받을 수 있습니다:
+### 향상된 사용자 경험
-- 프로젝트 목표에 맞게 기여 조정
-- 당신의 전문 지식이 가장 가치 있는 영역 식별
-- 특정 디자인 결정 배경 이해
-- 우리의 비전을 지원하는 새로운 기능에 대한 영감 찾기
+- 명확성과 직관성을 위한 UI/UX 간소화
+- 개발자들이 일상적으로 사용하는 도구에 기대하는 높은 기준을 충족하기 위한 지속적인 워크플로우 개선
-현재 로드맵은 여섯 가지 주요 기둥에 초점을 맞추고 있습니다:
+### 에이전트 성능 선도
-### 제공업체 지원
+- 실제 생산성을 측정하는 포괄적인 평가 기준(evals) 수립
+- 누구나 이러한 평가를 쉽게 실행하고 해석할 수 있도록 지원
+- 평가 점수의 명확한 향상을 보여주는 개선 제공
-가능한 한 많은 제공업체를 지원하는 것을 목표로 합니다:
+PR에서 이러한 영역과의 연관성을 언급하세요.
-- 더 다재다능한 "OpenAI 호환" 지원
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Ollama와 LM Studio에 대한 향상된 지원
+### 3. Roo Code 커뮤니티 참여
-### 모델 지원
+- **주요 방법:** [Discord](https://discord.gg/roocode)에 가입하고 **Hannes Rudolph (`hrudolph`)**에게 DM을 보내세요.
+- **대안:** 경험 많은 기여자는 [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1)를 통해 직접 참여할 수 있습니다.
-로컬 모델을 포함하여 가능한 한 많은 모델에서 Roo가 잘 작동하기를 원합니다:
+## 기여 내용 찾기 및 계획 세우기
-- 사용자 정의 시스템 프롬프팅 및 워크플로우를 통한 로컬 모델 지원
-- 벤치마킹 평가 및 테스트 케이스
+### 기여 유형
-### 시스템 지원
+- **버그 수정:** 코드 문제 해결.
+- **새 기능:** 기능 추가.
+- **문서화:** 가이드 개선 및 명확성 향상.
-Roo가 모든 사람의 컴퓨터에서 잘 작동하기를 원합니다:
+### Issue-First 접근법
-- 크로스 플랫폼 터미널 통합
-- Mac, Windows 및 Linux에 대한 강력하고 일관된 지원
+모든 기여는 GitHub Issue에서 시작해야 합니다.
-### 문서화
+- **기존 Issue 확인:** [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues)를 검색하세요.
+- **Issue 생성:** 적절한 템플릿 사용:
+ - **버그:** "Bug Report" 템플릿.
+ - **기능:** "Detailed Feature Proposal" 템플릿. 시작 전 승인 필요.
+- **Issue 담당:** 댓글을 달고 공식 할당을 기다리세요.
-모든 사용자와 기여자를 위한 포괄적이고 접근 가능한 문서를 원합니다:
+**승인된 Issue 없는 PR은 닫힐 수 있습니다.**
-- 확장된 사용자 가이드 및 튜토리얼
-- 명확한 API 문서
-- 기여자를 위한 더 나은 가이드
-- 다국어 문서 리소스
-- 대화형 예제 및 코드 샘플
+### 작업 선택하기
-### 안정성
+- 할당되지 않은 "Good First Issues"를 [GitHub 프로젝트](https://github.com/orgs/RooVetGit/projects/1)에서 확인하세요.
+- 문서 관련은 [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs)를 참조하세요.
-버그 수를 크게 줄이고 자동화된 테스트를 증가시키고자 합니다:
+### 버그 신고
-- 디버그 로깅 스위치
-- 버그/지원 요청과 함께 보낼 수 있는 "기기/작업 정보" 복사 버튼
+- 먼저 기존 신고를 확인하세요.
+- ["Bug Report" 템플릿](https://github.com/RooVetGit/Roo-Code/issues/new/choose)을 사용하여 새 버그를 신고하세요.
+- **보안 문제:** [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new)를 통해 비공개로 신고하세요.
-### 국제화
+## 개발 및 제출 프로세스
-Roo가 모든 사람의 언어를 말하기를 원합니다:
+### 개발 환경 설정
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-우리는 특히 로드맵 목표를 발전시키는 기여를 환영합니다. 이러한 기둥에 맞는 작업을 하고 있다면, PR 설명에서 이를 언급해 주세요.
-
-## 개발 설정
-
-1. 저장소 **클론**:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **의존성 설치**:
-
-```sh
-npm run install:all
-```
-
-3. **웹뷰 시작(HMR이 있는 Vite/React 앱)**:
-
-```sh
-npm run dev
+git clone https://github.com/당신의_아이디/Roo-Code.git
```
-4. **디버깅**:
- VSCode에서 `F5`를 누르거나(**실행** → **디버깅 시작**) Roo Code가 로드된 새 세션을 엽니다.
+2. **의존성 설치:**
-웹뷰의 변경 사항은 즉시 나타납니다. 코어 확장에 대한 변경 사항은 확장 호스트를 다시 시작해야 합니다.
-
-또는 .vsix를 빌드하고 VSCode에 직접 설치할 수 있습니다:
-
-```sh
-npm run build
```
-
-`bin/` 디렉토리에 `.vsix` 파일이 나타나며 다음 명령으로 설치할 수 있습니다:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## 코드 작성 및 제출
-
-누구나 Roo Code에 코드를 기여할 수 있지만, 기여가 원활하게 통합될 수 있도록 다음 지침을 따라주시기 바랍니다:
-
-1. **Pull Request 집중**
-
- - PR을 단일 기능 또는 버그 수정으로 제한
- - 더 큰 변경사항을 더 작고 관련된 PR로 분할
- - 독립적으로 검토할 수 있는 논리적인 커밋으로 변경사항 분할
-
-2. **코드 품질**
+3. **디버깅:** VS Code에서 `F5`를 눌러 실행하세요.
- - 모든 PR은 린팅 및 포맷팅을 포함한 CI 검사를 통과해야 함
- - 제출하기 전에 모든 ESLint 경고나 오류 해결
- - Ellipsis, 자동화된 코드 리뷰 도구의 모든 피드백에 응답
- - TypeScript 모범 사례를 따르고 타입 안전성 유지
+### 코드 작성 가이드라인
-3. **테스팅**
+- 하나의 기능 또는 수정당 하나의 집중된 PR.
+- ESLint와 TypeScript 모범 사례를 따르세요.
+- Issue를 참조하는 명확한 커밋 메시지를 작성하세요(예: `Fixes #123`).
+- 철저한 테스트를 제공하세요(`npm test`).
+- 제출 전 최신 `main` 브랜치에 리베이스하세요.
- - 새로운 기능에 대한 테스트 추가
- - 모든 테스트가 통과하는지 확인하기 위해 `npm test` 실행
- - 변경사항이 영향을 미치는 경우 기존 테스트 업데이트
- - 적절한 경우 단위 테스트와 통합 테스트 모두 포함
+### Pull Request 제출
-4. **커밋 가이드라인**
+- 초기 피드백을 원한다면 **드래프트 PR**로 시작하세요.
+- Pull Request 템플릿에 따라 변경 사항을 명확히 설명하세요.
+- UI 변경에 대한 스크린샷/동영상을 제공하세요.
+- 문서 업데이트가 필요한지 표시하세요.
- - 명확하고 설명적인 커밋 메시지 작성
- - #이슈-번호를 사용하여 커밋에서 관련 이슈 참조
+### Pull Request 정책
-5. **제출 전**
+- 사전 승인 및 할당된 Issue를 참조해야 합니다.
+- 정책을 준수하지 않는 PR은 닫힐 수 있습니다.
+- PR은 CI 테스트를 통과하고, 로드맵에 부합하며, 명확한 문서를 갖추어야 합니다.
- - 최신 main에 브랜치 리베이스
- - 브랜치가 성공적으로 빌드되는지 확인
- - 모든 테스트가 통과하는지 다시 확인
- - 디버깅 코드나 콘솔 로그가 있는지 변경사항 검토
+### 리뷰 프로세스
-6. **Pull Request 설명**
- - 변경사항이 무엇을 하는지 명확하게 설명
- - 변경사항을 테스트하는 단계 포함
- - 모든 주요 변경사항 나열
- - UI 변경사항에 대한 스크린샷 추가
+- **일일 분류:** 메인테이너의 빠른 검토.
+- **주간 심층 리뷰:** 종합적인 평가.
+- **피드백에 따라 신속히 반복**하세요.
-## 기여 동의
+## 법적 안내
-Pull request를 제출함으로써, 귀하의 기여는 프로젝트와 동일한 라이선스([Apache 2.0](../LICENSE))에 따라 라이선스가 부여된다는 데 동의합니다.
+기여함으로써, 귀하의 기여가 Roo Code의 라이선스와 일치하는 Apache 2.0 라이선스 하에 제공됨에 동의합니다.
diff --git a/locales/ko/README.md b/locales/ko/README.md
index 29e2358178c..e4e94c4d1b6 100644
--- a/locales/ko/README.md
+++ b/locales/ko/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
유연한 코딩 파트너, 시스템 아키텍트, QA 엔지니어나 제품 관리자와 같은 전문화된 역할을 찾고 있든, Roo Code는 더 효율적으로 소프트웨어를 구축하는 데 도움이 될 수 있습니다.
-상세한 업데이트 및 수정 사항은 [CHANGELOG](../CHANGELOG.md)를 확인하세요.
+상세한 업데이트 및 수정 사항은 [CHANGELOG](../../CHANGELOG.md)를 확인하세요.
---
-## 🎉 Roo Code 3.15 출시
+## 🎉 Roo Code 3.17 출시
-Roo Code 3.15가 사용자 피드백을 바탕으로 새로운 기능과 개선 사항을 제공합니다!
+Roo Code 3.17이 사용자 피드백을 바탕으로 강력한 새로운 기능과 개선 사항을 제공합니다!
-- **Vertex용 프롬프트 캐싱** - Vertex AI에서 이제 프롬프트 캐싱을 지원하여 응답 시간을 개선하고 API 비용을 절감합니다.
-- **터미널 폴백 메커니즘** - VSCode 터미널 쉘 통합이 실패할 때 작동하는 폴백 메커니즘을 구현하여 더 안정적인 터미널 작업을 보장합니다.
-- **개선된 코드 스니펫** - 채팅 인터페이스에서 코드 스니펫의 렌더링과 상호작용을 개선하여 가독성과 사용성을 향상시켰습니다.
+- **Gemini용 암시적 캐싱** - Gemini API 호출이 이제 자동으로 캐시되어 API 비용이 절감됩니다.
+- **더 스마트한 모드 선택** - 모드 정의에 각 모드가 언제 사용되어야 하는지에 대한 지침을 포함할 수 있어 더 나은 오케스트레이션이 가능해졌습니다.
+- **지능형 컨텍스트 응축** - 컨텍스트가 가득 찼을 때 잘라내는 대신 대화 기록을 지능적으로 요약합니다(설정 -> 실험적 기능에서 활성화).
---
@@ -178,32 +178,36 @@ code --install-extension bin/roo-cline-.vsix
Roo Code를 더 좋게 만드는 데 도움을 준 모든 기여자에게 감사드립니다!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## 라이선스
diff --git a/locales/nl/CODE_OF_CONDUCT.md b/locales/nl/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..2c9ba7d3f5f
--- /dev/null
+++ b/locales/nl/CODE_OF_CONDUCT.md
@@ -0,0 +1,52 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • Nederlands • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
+# Contributor Covenant Gedragscode
+
+## Onze Belofte
+
+In het belang van het bevorderen van een open en gastvrije omgeving, beloven wij als bijdragers en beheerders om deelname aan ons project en onze community een ervaring zonder intimidatie te maken voor iedereen, ongeacht leeftijd, lichaamsgrootte, handicap, etniciteit, geslachtskenmerken, genderidentiteit en -expressie, ervaringsniveau, opleiding, sociaal-economische status, nationaliteit, uiterlijk, ras, religie of seksuele identiteit en oriëntatie.
+
+## Onze Standaarden
+
+Voorbeelden van gedrag dat bijdraagt aan het creëren van een positieve omgeving zijn onder andere:
+
+- Gebruik van gastvrije en inclusieve taal
+- Respect tonen voor verschillende standpunten en ervaringen
+- Constructieve kritiek gracieus accepteren
+- Focus op wat het beste is voor de community
+- Empathie tonen voor andere communityleden
+
+Voorbeelden van onacceptabel gedrag van deelnemers zijn onder andere:
+
+- Het gebruik van seksueel getinte taal of beelden en ongewenste seksuele aandacht of toenadering
+- Trollgedrag, beledigende/denigrerende opmerkingen en persoonlijke of politieke aanvallen
+- Openbare of privé-intimidatie
+- Het publiceren van andermans privé-informatie, zoals een fysiek of elektronisch adres, zonder uitdrukkelijke toestemming
+- Ander gedrag dat redelijkerwijs als ongepast kan worden beschouwd in een professionele omgeving
+
+## Onze Verantwoordelijkheden
+
+Projectbeheerders zijn verantwoordelijk voor het verduidelijken van de normen voor acceptabel gedrag en worden geacht passende en eerlijke corrigerende maatregelen te nemen in reactie op gevallen van onacceptabel gedrag.
+
+Projectbeheerders hebben het recht en de verantwoordelijkheid om opmerkingen, commits, code, wiki-bewerkingen, issues en andere bijdragen die niet in overeenstemming zijn met deze Gedragscode te verwijderen, te bewerken of te weigeren, of om elke bijdrager tijdelijk of permanent te verbannen voor ander gedrag dat zij ongepast, bedreigend, beledigend of schadelijk achten.
+
+## Toepassingsgebied
+
+Deze Gedragscode is van toepassing binnen projectruimtes en in openbare ruimtes wanneer een individu het project of de community vertegenwoordigt. Voorbeelden van vertegenwoordiging van een project of community zijn het gebruik van een officieel project-e-mailadres, posten via een officieel socialmedia-account of optreden als een aangestelde vertegenwoordiger op een online of offline evenement. De definitie van vertegenwoordiging van een project kan verder worden gespecificeerd door projectbeheerders.
+
+## Handhaving
+
+Voorvallen van beledigend, intimiderend of anderszins onacceptabel gedrag kunnen worden gemeld door contact op te nemen met het projectteam via support@roocode.com. Alle klachten zullen worden beoordeeld en onderzocht en zullen resulteren in een reactie die passend wordt geacht voor de omstandigheden. Het projectteam is verplicht vertrouwelijkheid te bewaren met betrekking tot de melder van het incident. Verdere details over specifiek handhavingsbeleid kunnen afzonderlijk worden gepubliceerd.
+
+Projectbeheerders die de Gedragscode niet te goeder trouw volgen of handhaven, kunnen tijdelijke of permanente gevolgen ondervinden zoals bepaald door andere leden van het leiderschap van het project.
+
+## Toeschrijving
+
+Deze Gedragscode is gebaseerd op [Cline's versie][cline_coc] van de [Contributor Covenant][homepage], versie 1.4, beschikbaar op https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[cline_coc]: https://github.com/cline/cline/blob/main/CODE_OF_CONDUCT.md
+[homepage]: https://www.contributor-covenant.org
+
+Voor antwoorden op veelgestelde vragen over deze gedragscode, zie https://www.contributor-covenant.org/faq
diff --git a/locales/nl/CONTRIBUTING.md b/locales/nl/CONTRIBUTING.md
new file mode 100644
index 00000000000..46cc80fa304
--- /dev/null
+++ b/locales/nl/CONTRIBUTING.md
@@ -0,0 +1,129 @@
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • Nederlands • [Русский](../ru/CONTRIBUTING.md)
+
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
+
+# Bijdragen aan Roo Code
+
+Roo Code is een door de community gedreven project en we waarderen elke bijdrage enorm. Om de samenwerking te stroomlijnen, werken we volgens een [Issue-First](#issue-first-aanpak) principe, wat betekent dat alle [Pull Requests (PR's)](#een-pull-request-indienen) eerst gekoppeld moeten worden aan een GitHub Issue. Lees deze gids zorgvuldig door.
+
+## Inhoudsopgave
+
+- [Voordat je bijdraagt](#voordat-je-bijdraagt)
+- [Je bijdrage vinden & plannen](#je-bijdrage-vinden--plannen)
+- [Ontwikkelings- & indieningsproces](#ontwikkelings--indieningsproces)
+- [Juridisch](#juridisch)
+
+## Voordat je bijdraagt
+
+### 1. Gedragscode
+
+Alle bijdragers moeten zich houden aan onze [Gedragscode](./CODE_OF_CONDUCT.md).
+
+### 2. De project-roadmap
+
+Onze roadmap bepaalt de richting van het project. Stem je bijdragen af op deze kernpunten:
+
+### Betrouwbaarheid eerst
+
+- Zorgen dat diff-bewerking en opdrachtuitvoering consistent betrouwbaar zijn
+- Verminderen van wrijvingspunten die regelmatig gebruik ontmoedigen
+- Garanderen van soepele werking in alle talen en op alle platforms
+- Uitbreiden van robuuste ondersteuning voor een breed scala aan AI-providers en -modellen
+
+### Verbeterde gebruikerservaring
+
+- Vereenvoudigen van de gebruikersinterface voor meer duidelijkheid en intuïtiviteit
+- Continu verbeteren van de workflow om te voldoen aan de hoge verwachtingen van ontwikkelaars
+
+### Voorop lopen in agent-prestaties
+
+- Opstellen van uitgebreide evaluatiebenchmarks (evals) om productiviteit in de echte wereld te meten
+- Het voor iedereen gemakkelijk maken om deze evaluaties uit te voeren en te interpreteren
+- Verbeteringen leveren die duidelijke stijgingen in evaluatiescores aantonen
+
+Vermeld de afstemming met deze gebieden in je PR's.
+
+### 3. Word lid van de Roo Code-community
+
+- **Hoofdmethode:** Word lid van onze [Discord](https://discord.gg/roocode) en stuur een DM naar **Hannes Rudolph (`hrudolph`)**.
+- **Alternatief:** Ervaren bijdragers kunnen direct meedoen via [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
+
+## Je bijdrage vinden & plannen
+
+### Soorten bijdragen
+
+- **Bugfixes:** Problemen in code oplossen.
+- **Nieuwe functies:** Functionaliteit toevoegen.
+- **Documentatie:** Handleidingen verbeteren en verduidelijken.
+
+### Issue-First-aanpak
+
+Elke bijdrage moet beginnen met een GitHub Issue.
+
+- **Bestaande issues controleren:** Zoek in [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Issue aanmaken:** Gebruik de juiste templates:
+ - **Bugs:** "Bug Report"-template.
+ - **Functies:** "Detailed Feature Proposal"-template. Goedkeuring vereist voor je begint.
+- **Issues claimen:** Reageer en wacht op officiële toewijzing.
+
+**PR's zonder goedgekeurde issues kunnen worden gesloten.**
+
+### Bepalen waar je aan werkt
+
+- Bekijk het [GitHub Project](https://github.com/orgs/RooVetGit/projects/1) voor niet-toegewezen "Good First Issues".
+- Voor documentatie, bezoek [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
+
+### Bugs of problemen melden
+
+- Controleer eerst of er al meldingen zijn.
+- Maak nieuwe bugmeldingen met de ["Bug Report"-template](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Beveiligingsproblemen:** Meld privé via [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
+
+## Ontwikkelings- & indieningsproces
+
+### Ontwikkelomgeving instellen
+
+1. **Fork & Clone:**
+
+```
+git clone https://github.com/JOUW_GEBRUIKERSNAAM/Roo-Code.git
+```
+
+2. **Installeer afhankelijkheden:**
+
+```
+npm run install:all
+```
+
+3. **Debuggen:** Open met VS Code (`F5`).
+
+### Richtlijnen voor het schrijven van code
+
+- Eén gerichte PR per functie of fix.
+- Volg ESLint en TypeScript best practices.
+- Schrijf duidelijke, beschrijvende commits die verwijzen naar issues (bijv. `Fixes #123`).
+- Zorg voor grondige tests (`npm test`).
+- Rebase op de nieuwste `main`-branch vóór indiening.
+
+### Een Pull Request indienen
+
+- Begin als **concept-PR** als je vroege feedback zoekt.
+- Beschrijf je wijzigingen duidelijk volgens de Pull Request Template.
+- Voeg screenshots/video's toe voor UI-wijzigingen.
+- Geef aan of documentatie-updates nodig zijn.
+
+### Pull Request beleid
+
+- Moet verwijzen naar vooraf goedgekeurde en toegewezen issues.
+- PR's die niet aan het beleid voldoen, kunnen worden gesloten.
+- PR's moeten CI-tests doorstaan, aansluiten bij de roadmap en duidelijke documentatie hebben.
+
+### Reviewproces
+
+- **Dagelijkse triage:** Snelle controles door maintainers.
+- **Wekelijkse diepgaande review:** Uitgebreide beoordeling.
+- **Snel itereren** op basis van feedback.
+
+## Juridisch
+
+Door een pull request in te dienen, ga je ermee akkoord dat je bijdragen worden gelicenseerd onder de Apache 2.0-licentie, in overeenstemming met de licentie van Roo Code.
diff --git a/locales/nl/README.md b/locales/nl/README.md
new file mode 100644
index 00000000000..d172499037a
--- /dev/null
+++ b/locales/nl/README.md
@@ -0,0 +1,220 @@
+
+
+
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • Nederlands • [Русский](../../locales/ru/README.md)
+
+
+
+
+[日本語](../../locales/ja/README.md) • [한국어](../../locales/ko/README.md) • [Polski](../../locales/pl/README.md) • [Português (BR)](../../locales/pt-BR/README.md) • [Türkçe](../../locales/tr/README.md) • [Tiếng Việt](../../locales/vi/README.md) • [简体中文](../../locales/zh-CN/README.md) • [繁體中文](../../locales/zh-TW/README.md)
+
+
+
+
+
+
Roo Code (voorheen Roo Cline)
+
+
+
+
Verbind met ontwikkelaars, draag ideeën bij en blijf op de hoogte met de nieuwste AI-gestuurde coderingstools.
+
+

+

+
+
+
+
+
+
+**Roo Code** is een AI-gestuurde **autonome codeeragent** die in je editor leeft. Het kan:
+
+- Communiceren in natuurlijke taal
+- Bestanden direct in je werkruimte lezen en schrijven
+- Terminalcommando's uitvoeren
+- Browseracties automatiseren
+- Integreren met elke OpenAI-compatibele of aangepaste API/model
+- Zijn "persoonlijkheid" en mogelijkheden aanpassen via **Aangepaste Modi**
+
+Of je nu op zoek bent naar een flexibele codeerpartner, een systeemarchitect, of gespecialiseerde rollen zoals QA-engineer of productmanager, Roo Code helpt je efficiënter software te bouwen.
+
+Bekijk de [CHANGELOG](../../CHANGELOG.md) voor gedetailleerde updates en fixes.
+
+---
+
+## 🎉 Roo Code 3.17 Uitgebracht
+
+Roo Code 3.17 brengt krachtige nieuwe functies en verbeteringen op basis van jullie feedback!
+
+- **Impliciete caching voor Gemini** - Gemini API-aanroepen worden nu automatisch gecachet, waardoor API-kosten worden verlaagd.
+- **Slimmere modeselectie** - Modedefinities kunnen nu richtlijnen bevatten over wanneer elke modus moet worden gebruikt, wat betere orkestratie mogelijk maakt.
+- **Intelligente contextcompressie** - Vat de gespreksgeschiedenis intelligent samen wanneer de context vol raakt in plaats van deze af te kappen (in te schakelen via Instellingen -> Experimenteel).
+
+---
+
+## Wat kan Roo Code?
+
+- 🚀 **Genereer code** vanuit natuurlijke taalbeschrijvingen
+- 🔧 **Refactor & Debug** bestaande code
+- 📝 **Schrijf & Update** documentatie
+- 🤔 **Beantwoord vragen** over je codebase
+- 🔄 **Automatiseer** repetitieve taken
+- 🏗️ **Maak** nieuwe bestanden en projecten
+
+## Snelstart
+
+1. [Installeer Roo Code](https://docs.roocode.com/getting-started/installing)
+2. [Verbind je AI-provider](https://docs.roocode.com/getting-started/connecting-api-provider)
+3. [Probeer je eerste taak](https://docs.roocode.com/getting-started/your-first-task)
+
+## Belangrijkste functies
+
+### Meerdere Modi
+
+Roo Code past zich aan jouw behoeften aan met gespecialiseerde [modi](https://docs.roocode.com/basic-usage/using-modes):
+
+- **Code-modus:** Voor algemene coderingstaken
+- **Architect-modus:** Voor planning en technisch leiderschap
+- **Vraag-modus:** Voor het beantwoorden van vragen en het geven van informatie
+- **Debug-modus:** Voor systematische probleemdiagnose
+- **[Aangepaste modi](https://docs.roocode.com/advanced-usage/custom-modes):** Maak onbeperkt gespecialiseerde persona's voor beveiligingsaudits, prestatieoptimalisatie, documentatie of andere taken
+
+### Slimme Tools
+
+Roo Code wordt geleverd met krachtige [tools](https://docs.roocode.com/basic-usage/how-tools-work) die kunnen:
+
+- Bestanden in je project lezen en schrijven
+- Commando's uitvoeren in je VS Code-terminal
+- Een webbrowser aansturen
+- Externe tools gebruiken via [MCP (Model Context Protocol)](https://docs.roocode.com/advanced-usage/mcp)
+
+MCP breidt de mogelijkheden van Roo Code uit door je in staat te stellen onbeperkt aangepaste tools toe te voegen. Integreer met externe API's, maak verbinding met databases of creëer gespecialiseerde ontwikkeltools - MCP biedt het framework om Roo Code uit te breiden naar jouw specifieke wensen.
+
+### Aanpassen
+
+Laat Roo Code werken zoals jij wilt met:
+
+- [Aangepaste instructies](https://docs.roocode.com/advanced-usage/custom-instructions) voor gepersonaliseerd gedrag
+- [Aangepaste modi](https://docs.roocode.com/advanced-usage/custom-modes) voor specialistische taken
+- [Lokale modellen](https://docs.roocode.com/advanced-usage/local-models) voor offline gebruik
+- [Auto-Approve-instellingen](https://docs.roocode.com/advanced-usage/auto-approving-actions) voor snellere workflows
+
+## Bronnen
+
+### Documentatie
+
+- [Basisgebruik](https://docs.roocode.com/basic-usage/the-chat-interface)
+- [Geavanceerde functies](https://docs.roocode.com/advanced-usage/auto-approving-actions)
+- [Veelgestelde vragen](https://docs.roocode.com/faq)
+
+### Community
+
+- **Discord:** [Word lid van onze Discord-server](https://discord.gg/roocode) voor directe hulp en discussies
+- **Reddit:** [Bezoek onze subreddit](https://www.reddit.com/r/RooCode) om ervaringen en tips te delen
+- **GitHub:** Meld [problemen](https://github.com/RooVetGit/Roo-Code/issues) of vraag [features](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) aan
+
+---
+
+## Lokale installatie & ontwikkeling
+
+1. **Kloon** de repo:
+
+```sh
+git clone https://github.com/RooVetGit/Roo-Code.git
+```
+
+2. **Installeer afhankelijkheden**:
+
+```sh
+npm run install:all
+```
+
+3. **Start de webview (Vite/React-app met HMR)**:
+
+```sh
+npm run dev
+```
+
+4. **Debuggen**:
+ Druk op `F5` (of **Run** → **Start Debugging**) in VSCode om een nieuwe sessie met Roo Code te openen.
+
+Wijzigingen aan de webview verschijnen direct. Wijzigingen aan de core-extensie vereisen een herstart van de extensiehost.
+
+Je kunt ook een .vsix bouwen en deze direct in VSCode installeren:
+
+```sh
+npm run build
+```
+
+Een `.vsix`-bestand verschijnt in de `bin/`-map en kan worden geïnstalleerd met:
+
+```sh
+code --install-extension bin/roo-cline-.vsix
+```
+
+We gebruiken [changesets](https://github.com/changesets/changesets) voor versiebeheer en publicatie. Bekijk onze `CHANGELOG.md` voor release-opmerkingen.
+
+---
+
+## Disclaimer
+
+**Let op**: Roo Code, Inc geeft **geen** garanties of waarborgen met betrekking tot enige code, modellen of andere tools die worden geleverd of beschikbaar worden gesteld in verband met Roo Code, bijbehorende tools van derden, of enige resulterende output. Je neemt **alle risico's** die gepaard gaan met het gebruik van dergelijke tools of output; deze tools worden geleverd op een **"AS IS"** en **"AS AVAILABLE"** basis. Risico's kunnen onder meer zijn: inbreuk op intellectueel eigendom, cyberkwetsbaarheden of -aanvallen, vooringenomenheid, onnauwkeurigheden, fouten, defecten, virussen, uitval, verlies of schade aan eigendommen en/of persoonlijk letsel. Je bent zelf volledig verantwoordelijk voor het gebruik van dergelijke tools of output (inclusief, maar niet beperkt tot, de legaliteit, geschiktheid en resultaten daarvan).
+
+---
+
+## Bijdragen
+
+We houden van bijdragen uit de community! Begin met het lezen van onze [CONTRIBUTING.md](CONTRIBUTING.md).
+
+---
+
+## Bijdragers
+
+Dank aan alle bijdragers die Roo Code beter hebben gemaakt!
+
+
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
+
+
+## Licentie
+
+[Apache 2.0 © 2025 Roo Code, Inc.](../../LICENSE)
+
+---
+
+**Veel plezier met Roo Code!** Of je het nu kort houdt of autonoom laat werken, we zijn benieuwd wat je bouwt. Heb je vragen of ideeën voor functies, kom dan langs op onze [Reddit-community](https://www.reddit.com/r/RooCode/) of [Discord](https://discord.gg/roocode). Veel programmeerplezier!
diff --git a/locales/pl/CODE_OF_CONDUCT.md b/locales/pl/CODE_OF_CONDUCT.md
index c1a723936fa..689269bfbd5 100644
--- a/locales/pl/CODE_OF_CONDUCT.md
+++ b/locales/pl/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • Polski • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Kodeks Postępowania Covenant Współtwórców
## Nasze Zobowiązanie
diff --git a/locales/pl/CONTRIBUTING.md b/locales/pl/CONTRIBUTING.md
index b669cb2f2ce..b19e6a81645 100644
--- a/locales/pl/CONTRIBUTING.md
+++ b/locales/pl/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Wkład w Roo Code
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-Cieszymy się, że jesteś zainteresowany wniesieniem wkładu do Roo Code. Czy naprawiasz błąd, dodajesz funkcję, czy ulepszasz naszą dokumentację, każdy wkład sprawia, że Roo Code staje się mądrzejszy! Aby utrzymać naszą społeczność żywą i przyjazną, wszyscy członkowie muszą przestrzegać naszego [Kodeksu Postępowania](CODE_OF_CONDUCT.md).
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • Polski • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## Dołącz do naszej społeczności
+# Współtworzenie Roo Code
-Gorąco zachęcamy wszystkich współtwórców do dołączenia do naszej [społeczności Discord](https://discord.gg/roocode)! Bycie częścią naszego serwera Discord pomaga:
+Roo Code to projekt napędzany przez społeczność i bardzo cenimy każdy wkład. Aby usprawnić współpracę, działamy według zasady [Issue-First](#podejście-issue-first), co oznacza, że wszystkie [Pull Requesty (PR)](#zgłaszanie-pull-requesta) muszą najpierw być powiązane z GitHub Issue. Prosimy o uważne zapoznanie się z tym przewodnikiem.
-- Uzyskać pomoc i wskazówki w czasie rzeczywistym dotyczące Twoich wkładów
-- Połączyć się z innymi współtwórcami i członkami głównego zespołu
-- Być na bieżąco z rozwojem projektu i jego priorytetami
-- Uczestniczyć w dyskusjach, które kształtują przyszłość Roo Code
-- Znaleźć możliwości współpracy z innymi programistami
+## Spis treści
-## Zgłaszanie błędów lub problemów
+- [Zanim zaczniesz współtworzyć](#zanim-zaczniesz-współtworzyć)
+- [Znajdowanie i planowanie swojego wkładu](#znajdowanie-i-planowanie-swojego-wkładu)
+- [Proces rozwoju i zgłaszania](#proces-rozwoju-i-zgłaszania)
+- [Prawne](#prawne)
-Raporty o błędach pomagają ulepszyć Roo Code dla wszystkich! Przed utworzeniem nowego zgłoszenia, proszę [przeszukaj istniejące](https://github.com/RooVetGit/Roo-Code/issues), aby uniknąć duplikatów. Kiedy jesteś gotowy, aby zgłosić błąd, przejdź do naszej [strony zgłoszeń](https://github.com/RooVetGit/Roo-Code/issues/new/choose), gdzie znajdziesz szablon, który pomoże Ci wypełnić odpowiednie informacje.
+## Zanim zaczniesz współtworzyć
-
- 🔐 Ważne: Jeśli odkryjesz lukę w zabezpieczeniach, proszę użyj narzędzia bezpieczeństwa Github, aby zgłosić ją prywatnie.
-
+### 1. Kodeks postępowania
-## Decydowanie nad czym pracować
+Wszyscy współtwórcy muszą przestrzegać naszego [Kodeksu postępowania](./CODE_OF_CONDUCT.md).
-Szukasz dobrego pierwszego wkładu? Sprawdź problemy w sekcji "Issue [Unassigned]" naszego [projektu Github Roo Code](https://github.com/orgs/RooVetGit/projects/1). Te zostały specjalnie wybrane dla nowych współtwórców i obszarów, gdzie chętnie przyjmiemy pomoc!
+### 2. Roadmapa projektu
-Cieszymy się również z wkładu do naszej [dokumentacji](https://docs.roocode.com/)! Czy to poprawianie literówek, ulepszanie istniejących przewodników, czy tworzenie nowych treści edukacyjnych - chcielibyśmy zbudować repozytorium zasobów napędzane przez społeczność, które pomaga każdemu czerpać maksimum z Roo Code. Możesz kliknąć "Edit this page" na dowolnej stronie, aby szybko przejść do odpowiedniego miejsca w Github, aby edytować plik, lub możesz przejść bezpośrednio do https://github.com/RooVetGit/Roo-Code-Docs.
+Nasza roadmapa wyznacza kierunek projektu. Dostosuj swój wkład do tych kluczowych celów:
-Jeśli planujesz pracować nad większą funkcją, proszę najpierw utwórz [prośbę o funkcję](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop), abyśmy mogli przedyskutować, czy jest ona zgodna z wizją Roo Code. Możesz również sprawdzić naszą [Mapę Drogową Projektu](#mapa-drogowa-projektu) poniżej, aby zobaczyć, czy Twój pomysł pasuje do naszego strategicznego kierunku.
+### Niezawodność przede wszystkim
-## Mapa Drogowa Projektu
+- Zapewnienie, że edycja różnic i wykonywanie poleceń są konsekwentnie niezawodne
+- Zmniejszenie punktów tarcia, które zniechęcają do regularnego użytkowania
+- Gwarancja płynnego działania we wszystkich językach i na wszystkich platformach
+- Rozszerzenie solidnego wsparcia dla szerokiej gamy dostawców i modeli AI
-Roo Code posiada jasną mapę drogową rozwoju, która kieruje naszymi priorytetami i przyszłym kierunkiem. Zrozumienie naszej mapy drogowej może pomóc Ci:
+### Ulepszone doświadczenie użytkownika
-- Dostosować swoje wkłady do celów projektu
-- Zidentyfikować obszary, w których Twoja wiedza byłaby najbardziej wartościowa
-- Zrozumieć kontekst stojący za pewnymi decyzjami projektowymi
-- Znaleźć inspirację dla nowych funkcji, które wspierają naszą wizję
+- Uproszczenie interfejsu użytkownika dla większej przejrzystości i intuicyjności
+- Ciągłe doskonalenie przepływu pracy, aby spełnić wysokie oczekiwania programistów
-Nasza obecna mapa drogowa koncentruje się na sześciu kluczowych filarach:
+### Wiodąca pozycja w wydajności agentów
-### Wsparcie dla Dostawców
+- Ustanowienie kompleksowych punktów odniesienia (evals) do mierzenia produktywności w rzeczywistym świecie
+- Ułatwienie wszystkim łatwego uruchamiania i interpretowania tych ocen
+- Dostarczanie ulepszeń, które wykazują wyraźny wzrost wyników ocen
-Dążymy do wspierania jak największej liczby dostawców:
+Wspomnij o powiązaniu z tymi obszarami w swoich PR.
-- Bardziej wszechstronne wsparcie dla "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Ulepszone wsparcie dla Ollama i LM Studio
+### 3. Dołącz do społeczności Roo Code
-### Wsparcie dla Modeli
+- **Główna metoda:** Dołącz do naszego [Discorda](https://discord.gg/roocode) i wyślij wiadomość prywatną do **Hannes Rudolph (`hrudolph`)**.
+- **Alternatywa:** Doświadczeni współtwórcy mogą angażować się bezpośrednio przez [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-Chcemy, aby Roo działał jak najlepiej na jak największej liczbie modeli, w tym modeli lokalnych:
+## Znajdowanie i planowanie swojego wkładu
-- Wsparcie dla modeli lokalnych poprzez niestandardowe promptowanie systemowe i przepływy pracy
-- Benchmarki ewaluacyjne i przypadki testowe
+### Typy wkładów
-### Wsparcie dla Systemów
+- **Poprawki błędów:** Naprawianie problemów w kodzie.
+- **Nowe funkcje:** Dodawanie nowych funkcjonalności.
+- **Dokumentacja:** Ulepszanie przewodników i zwiększanie przejrzystości.
-Chcemy, aby Roo działał dobrze na komputerze każdego:
+### Podejście Issue-First
-- Integracja terminala międzyplatformowego
-- Silne i spójne wsparcie dla Mac, Windows i Linux
+Każdy wkład musi zaczynać się od GitHub Issue.
-### Dokumentacja
+- **Sprawdź istniejące issues:** Przeszukaj [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Utwórz issue:** Używaj odpowiednich szablonów:
+ - **Błędy:** Szablon "Bug Report".
+ - **Funkcje:** Szablon "Detailed Feature Proposal". Wymagane zatwierdzenie przed rozpoczęciem.
+- **Zgłoś chęć pracy:** Skomentuj i poczekaj na oficjalne przypisanie.
-Chcemy kompleksowej, dostępnej dokumentacji dla wszystkich użytkowników i współtwórców:
+**PR bez zatwierdzonego issue może zostać zamknięty.**
-- Rozszerzone przewodniki użytkownika i tutoriale
-- Jasna dokumentacja API
-- Lepsze wskazówki dla współtwórców
-- Wielojęzyczne zasoby dokumentacji
-- Interaktywne przykłady i próbki kodu
+### Decydowanie, nad czym pracować
-### Stabilność
+- Sprawdź [Projekt GitHub](https://github.com/orgs/RooVetGit/projects/1) w poszukiwaniu nieprzypisanych "Good First Issues".
+- W kwestii dokumentacji odwiedź [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Chcemy znacznie zmniejszyć liczbę błędów i zwiększyć zautomatyzowane testowanie:
+### Zgłaszanie błędów
-- Przełącznik rejestrowania debugowania
-- Przycisk kopiowania "Informacji o Maszynie/Zadaniu" do wysyłania z prośbami o pomoc/zgłoszeniami błędów
+- Najpierw sprawdź istniejące zgłoszenia.
+- Twórz nowe zgłoszenia błędów używając [szablonu "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Luki bezpieczeństwa:** Zgłaszaj prywatnie przez [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-### Internacjonalizacja
+## Proces rozwoju i zgłaszania
-Chcemy, aby Roo mówił językiem każdego:
+### Konfiguracja środowiska
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-Szczególnie witamy wkłady, które przyspieszają realizację celów naszej mapy drogowej. Jeśli pracujesz nad czymś, co jest zgodne z tymi filarami, proszę wspomnij o tym w opisie swojego PR.
-
-## Konfiguracja rozwojowa
-
-1. **Sklonuj** repozytorium:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **Zainstaluj zależności**:
-
-```sh
-npm run install:all
-```
-
-3. **Uruchom webview (aplikację Vite/React z HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/TWÓJ_UŻYTKOWNIK/Roo-Code.git
```
-4. **Debugowanie**:
- Naciśnij `F5` (lub **Uruchom** → **Rozpocznij debugowanie**) w VSCode, aby otworzyć nową sesję z załadowanym Roo Code.
+2. **Instalacja zależności:**
-Zmiany w webview pojawią się natychmiast. Zmiany w podstawowym rozszerzeniu będą wymagać ponownego uruchomienia hosta rozszerzenia.
-
-Alternatywnie możesz zbudować plik .vsix i zainstalować go bezpośrednio w VSCode:
-
-```sh
-npm run build
```
-
-Plik `.vsix` pojawi się w katalogu `bin/` i można go zainstalować za pomocą:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Pisanie i przesyłanie kodu
-
-Każdy może wnieść wkład w kod Roo Code, ale prosimy o przestrzeganie tych wytycznych, aby zapewnić płynną integrację Twoich wkładów:
-
-1. **Utrzymuj Pull Requesty skupione**
-
- - Ogranicz PR do jednej funkcji lub naprawy błędu
- - Podziel większe zmiany na mniejsze, powiązane PR
- - Podziel zmiany na logiczne commity, które można przeglądać niezależnie
-
-2. **Jakość kodu**
+3. **Debugowanie:** Otwórz w VS Code (`F5`).
- - Wszystkie PR muszą przejść kontrole CI, które obejmują zarówno linting, jak i formatowanie
- - Rozwiąż wszelkie ostrzeżenia lub błędy ESLint przed przesłaniem
- - Odpowiedz na wszystkie informacje zwrotne od Ellipsis, naszego zautomatyzowanego narzędzia do przeglądu kodu
- - Przestrzegaj najlepszych praktyk TypeScript i zachowaj bezpieczeństwo typów
+### Wytyczne dotyczące pisania kodu
-3. **Testowanie**
+- Jeden skoncentrowany PR na funkcję lub poprawkę.
+- Przestrzegaj dobrych praktyk ESLint i TypeScript.
+- Pisz jasne, opisowe commity odnoszące się do issues (np. `Fixes #123`).
+- Zapewnij dokładne testy (`npm test`).
+- Zrebase'uj na najnowszą gałąź `main` przed zgłoszeniem.
- - Dodaj testy dla nowych funkcji
- - Uruchom `npm test`, aby upewnić się, że wszystkie testy przechodzą
- - Zaktualizuj istniejące testy, jeśli Twoje zmiany na nie wpływają
- - Uwzględnij zarówno testy jednostkowe, jak i integracyjne, gdy jest to właściwe
+### Zgłaszanie Pull Requesta
-4. **Wytyczne dotyczące commitów**
+- Zacznij od **wersji roboczej PR**, jeśli szukasz wczesnego feedbacku.
+- Jasno opisz swoje zmiany, zgodnie z szablonem Pull Request.
+- Dostarcz zrzuty ekranu/wideo dla zmian UI.
+- Wskaż, czy potrzebne są aktualizacje dokumentacji.
- - Pisz jasne, opisowe komunikaty commitów
- - Odwołuj się do odpowiednich problemów w commitach, używając #numer-problemu
+### Polityka Pull Request
-5. **Przed przesłaniem**
+- Musi odnosić się do wcześniej zatwierdzonych i przypisanych issues.
+- PR niezgodne z polityką mogą zostać zamknięte.
+- PR powinny przechodzić testy CI, być zgodne z roadmapą i mieć jasną dokumentację.
- - Rebase swojej gałęzi na najnowszego maina
- - Upewnij się, że Twoja gałąź buduje się pomyślnie
- - Sprawdź ponownie, czy wszystkie testy przechodzą
- - Przejrzyj swoje zmiany pod kątem wszelkiego kodu debugującego lub logów konsoli
+### Proces recenzji
-6. **Opis Pull Requesta**
- - Jasno opisz, co robią Twoje zmiany
- - Dołącz kroki do przetestowania zmian
- - Wymień wszelkie istotne zmiany
- - Dodaj zrzuty ekranu dla zmian UI
+- **Codzienna selekcja:** Szybkie sprawdzenia przez maintainerów.
+- **Cotygodniowy dokładny przegląd:** Kompleksowa ocena.
+- **Szybko iteruj** na podstawie feedbacku.
-## Umowa o współpracy
+## Prawne
-Przesyłając pull request, zgadzasz się, że Twoje wkłady będą licencjonowane na tej samej licencji co projekt ([Apache 2.0](../LICENSE)).
+Zgłaszając pull request, zgadzasz się, że twój wkład będzie licencjonowany na licencji Apache 2.0, zgodnie z licencją Roo Code.
diff --git a/locales/pl/README.md b/locales/pl/README.md
index 08ad175d278..f84d974004a 100644
--- a/locales/pl/README.md
+++ b/locales/pl/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Niezależnie od tego, czy szukasz elastycznego partnera do kodowania, architekta systemu, czy wyspecjalizowanych ról, takich jak inżynier QA lub menedżer produktu, Roo Code może pomóc Ci budować oprogramowanie efektywniej.
-Sprawdź [CHANGELOG](../CHANGELOG.md), aby uzyskać szczegółowe informacje o aktualizacjach i poprawkach.
+Sprawdź [CHANGELOG](../../CHANGELOG.md), aby uzyskać szczegółowe informacje o aktualizacjach i poprawkach.
---
-## 🎉 Roo Code 3.15 został wydany
+## 🎉 Roo Code 3.17 został wydany
-Roo Code 3.15 wprowadza nowe funkcje i usprawnienia na podstawie opinii użytkowników!
+Roo Code 3.17 wprowadza potężne nowe funkcje i usprawnienia na podstawie opinii użytkowników!
-- **Pamięć podręczna dla promptów w Vertex** - Vertex AI teraz obsługuje pamięć podręczną promptów, poprawiając czas odpowiedzi i zmniejszając koszty API.
-- **Awaryjny tryb terminala** - Zaimplementowano mechanizm awaryjny na wypadek niepowodzenia integracji powłoki terminala VSCode, zapewniając bardziej niezawodne działanie terminala.
-- **Ulepszone fragmenty kodu** - Udoskonalono renderowanie i interakcję z fragmentami kodu w interfejsie czatu dla lepszej czytelności i użyteczności.
+- **Niejawne buforowanie dla Gemini** - Wywołania API Gemini są teraz automatycznie buforowane, zmniejszając koszty API.
+- **Inteligentniejszy wybór trybu** - Definicje trybów mogą teraz zawierać wskazówki dotyczące tego, kiedy każdy tryb powinien być używany, umożliwiając lepszą orkiestrację.
+- **Inteligentne kondensowanie kontekstu** - Inteligentnie podsumowuje historię konwersacji, gdy kontekst się zapełnia, zamiast ucinać (włącz w Ustawienia -> Eksperymentalne).
---
@@ -178,32 +178,36 @@ Kochamy wkład społeczności! Zacznij od przeczytania naszego [CONTRIBUTING.md]
Dziękujemy wszystkim naszym współtwórcom, którzy pomogli ulepszyć Roo Code!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Licencja
diff --git a/locales/pt-BR/CODE_OF_CONDUCT.md b/locales/pt-BR/CODE_OF_CONDUCT.md
index da84a569a03..88bcaae7061 100644
--- a/locales/pt-BR/CODE_OF_CONDUCT.md
+++ b/locales/pt-BR/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • Português (BR) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Código de Conduta do Pacto de Colaboradores
## Nosso Compromisso
diff --git a/locales/pt-BR/CONTRIBUTING.md b/locales/pt-BR/CONTRIBUTING.md
index a3e04811b3e..a67a72f6e40 100644
--- a/locales/pt-BR/CONTRIBUTING.md
+++ b/locales/pt-BR/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Contribuindo para o Roo Code
-
-Estamos entusiasmados por você estar interessado em contribuir para o Roo Code. Seja corrigindo um bug, adicionando um recurso ou melhorando nossa documentação, cada contribuição torna o Roo Code mais inteligente! Para manter nossa comunidade vibrante e acolhedora, todos os membros devem aderir ao nosso [Código de Conduta](CODE_OF_CONDUCT.md).
-
-## Junte-se à Nossa Comunidade
-
-Incentivamos fortemente todos os colaboradores a se juntarem à nossa [comunidade no Discord](https://discord.gg/roocode)! Fazer parte do nosso servidor Discord ajuda você a:
-
-- Obter ajuda e orientação em tempo real sobre suas contribuições
-- Conectar-se com outros colaboradores e membros da equipe principal
-- Manter-se atualizado sobre os desenvolvimentos e prioridades do projeto
-- Participar de discussões que moldam o futuro do Roo Code
-- Encontrar oportunidades de colaboração com outros desenvolvedores
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Relatando Bugs ou Problemas
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • Português (BR) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Relatórios de bugs ajudam a tornar o Roo Code melhor para todos! Antes de criar uma nova issue, por favor [pesquise as existentes](https://github.com/RooVetGit/Roo-Code/issues) para evitar duplicatas. Quando estiver pronto para relatar um bug, vá para nossa [página de issues](https://github.com/RooVetGit/Roo-Code/issues/new/choose) onde você encontrará um modelo para ajudá-lo a preencher as informações relevantes.
-
-
- 🔐 Importante: Se você descobrir uma vulnerabilidade de segurança, por favor use a ferramenta de segurança do Github para relatá-la de forma privada.
-
+# Contribuindo para o Roo Code
-## Decidindo no que Trabalhar
+O Roo Code é um projeto impulsionado pela comunidade e valorizamos muito cada contribuição. Para simplificar a colaboração, operamos com uma abordagem [Issue-First](#abordagem-issue-first), o que significa que todos os [Pull Requests (PRs)](#enviando-um-pull-request) devem primeiro estar vinculados a uma Issue do GitHub. Por favor, leia este guia com atenção.
-Procurando uma boa primeira contribuição? Verifique as issues na seção "Issue [Unassigned]" do nosso [Projeto Github Roo Code](https://github.com/orgs/RooVetGit/projects/1). Estas são especialmente selecionadas para novos colaboradores e áreas onde gostaríamos de ter alguma ajuda!
+## Índice
-Também damos as boas-vindas a contribuições para nossa [documentação](https://docs.roocode.com/)! Seja corrigindo erros de digitação, melhorando guias existentes ou criando novo conteúdo educacional - adoraríamos construir um repositório de recursos impulsionado pela comunidade que ajude todos a obter o máximo do Roo Code. Você pode clicar em "Edit this page" em qualquer página para ir rapidamente ao local certo no Github para editar o arquivo, ou pode mergulhar diretamente em https://github.com/RooVetGit/Roo-Code-Docs.
+- [Antes de Contribuir](#antes-de-contribuir)
+- [Encontrando & Planejando sua Contribuição](#encontrando--planejando-sua-contribuição)
+- [Processo de Desenvolvimento & Submissão](#processo-de-desenvolvimento--submissão)
+- [Legal](#legal)
-Se você está planejando trabalhar em um recurso maior, por favor crie primeiro uma [solicitação de recurso](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) para que possamos discutir se está alinhado com a visão do Roo Code. Você também pode verificar nosso [Roteiro do Projeto](#roteiro-do-projeto) abaixo para ver se sua ideia se encaixa em nossa direção estratégica.
+## Antes de Contribuir
-## Roteiro do Projeto
+### 1. Código de Conduta
-O Roo Code possui um roteiro de desenvolvimento claro que orienta nossas prioridades e direção futura. Entender nosso roteiro pode ajudar você a:
+Todos os colaboradores devem seguir nosso [Código de Conduta](./CODE_OF_CONDUCT.md).
-- Alinhar suas contribuições com os objetivos do projeto
-- Identificar áreas onde sua expertise seria mais valiosa
-- Entender o contexto por trás de certas decisões de design
-- Encontrar inspiração para novos recursos que apoiem nossa visão
+### 2. Roadmap do Projeto
-Nosso roteiro atual se concentra em seis pilares principais:
+Nosso roadmap orienta a direção do projeto. Alinhe suas contribuições com estes objetivos principais:
-### Suporte a Provedores
+### Confiabilidade em Primeiro Lugar
-Nosso objetivo é oferecer suporte a tantos provedores quanto possível:
+- Garantir que a edição de diferenças e a execução de comandos sejam consistentemente confiáveis
+- Reduzir pontos de atrito que desencorajam o uso regular
+- Garantir operação suave em todos os idiomas e plataformas
+- Expandir o suporte robusto para uma ampla variedade de provedores e modelos de IA
-- Suporte mais versátil para "OpenAI Compatible"
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Suporte aprimorado para Ollama e LM Studio
+### Experiência de Usuário Aprimorada
-### Suporte a Modelos
+- Simplificar a interface do usuário para maior clareza e intuitividade
+- Melhorar continuamente o fluxo de trabalho para atender às altas expectativas dos desenvolvedores
-Queremos que o Roo funcione bem em tantos modelos quanto possível, incluindo modelos locais:
+### Liderança em Desempenho de Agentes
-- Suporte a modelos locais através de prompts de sistema personalizados e fluxos de trabalho
-- Avaliações de benchmark e casos de teste
+- Estabelecer benchmarks de avaliação abrangentes (evals) para medir a produtividade no mundo real
+- Facilitar para que todos possam executar e interpretar essas avaliações
+- Fornecer melhorias que demonstrem aumentos claros nas pontuações de avaliação
-### Suporte a Sistemas
+Mencione o alinhamento com estas áreas em seus PRs.
-Queremos que o Roo funcione bem no computador de todos:
+### 3. Junte-se à Comunidade Roo Code
-- Integração de terminal multiplataforma
-- Suporte forte e consistente para Mac, Windows e Linux
+- **Principal:** Junte-se ao nosso [Discord](https://discord.gg/roocode) e envie um DM para **Hannes Rudolph (`hrudolph`)**.
+- **Alternativa:** Colaboradores experientes podem participar diretamente via [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-### Documentação
+## Encontrando & Planejando sua Contribuição
-Queremos documentação abrangente e acessível para todos os usuários e colaboradores:
+### Tipos de Contribuição
-- Guias de usuário e tutoriais expandidos
-- Documentação clara da API
-- Melhor orientação para colaboradores
-- Recursos de documentação multilíngues
-- Exemplos interativos e amostras de código
+- **Correção de bugs:** Corrigir problemas no código.
+- **Novos recursos:** Adicionar novas funcionalidades.
+- **Documentação:** Melhorar guias e clareza.
-### Estabilidade
+### Abordagem Issue-First
-Queremos diminuir significativamente o número de bugs e aumentar os testes automatizados:
+Todas as contribuições devem começar com uma Issue do GitHub.
-- Interruptor de registro de depuração
-- Botão de cópia "Informações de Máquina/Tarefa" para enviar com solicitações de suporte/bug
+- **Verificar issues existentes:** Procure em [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Criar uma issue:** Use os templates apropriados:
+ - **Bugs:** Template "Bug Report".
+ - **Recursos:** Template "Detailed Feature Proposal". Aprovação necessária antes de começar.
+- **Reivindicar issues:** Comente e aguarde atribuição oficial.
-### Internacionalização
+**PRs sem issues aprovadas podem ser fechados.**
-Queremos que o Roo fale o idioma de todos:
+### Decidindo no que Trabalhar
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- Confira o [Projeto GitHub](https://github.com/orgs/RooVetGit/projects/1) para "Good First Issues" não atribuídas.
+- Para documentação, visite [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Damos especialmente as boas-vindas a contribuições que avançam os objetivos do nosso roteiro. Se você estiver trabalhando em algo que se alinha com esses pilares, por favor mencione isso na descrição do seu PR.
+### Relatando Bugs
-## Configuração de Desenvolvimento
+- Verifique primeiro se já existem relatórios.
+- Crie novos relatórios de bugs usando o [template "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Vulnerabilidades de segurança:** Relate de forma privada via [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-1. **Clone** o repositório:
+## Processo de Desenvolvimento & Submissão
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Configuração de Desenvolvimento
-2. **Instale as dependências**:
+1. **Fork & Clone:**
-```sh
-npm run install:all
```
-
-3. **Inicie o webview (aplicativo Vite/React com HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/SEU_USUÁRIO/Roo-Code.git
```
-4. **Depuração**:
- Pressione `F5` (ou **Executar** → **Iniciar Depuração**) no VSCode para abrir uma nova sessão com o Roo Code carregado.
-
-Alterações no webview aparecerão imediatamente. Alterações na extensão principal exigirão a reinicialização do host da extensão.
-
-Alternativamente, você pode construir um .vsix e instalá-lo diretamente no VSCode:
+2. **Instalar dependências:**
-```sh
-npm run build
```
-
-Um arquivo `.vsix` aparecerá no diretório `bin/` que pode ser instalado com:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Escrevendo e Enviando Código
-
-Qualquer pessoa pode contribuir com código para o Roo Code, mas pedimos que você siga estas diretrizes para garantir que suas contribuições possam ser integradas sem problemas:
-
-1. **Mantenha os Pull Requests Focados**
-
- - Limite os PRs a um único recurso ou correção de bug
- - Divida mudanças maiores em PRs menores e relacionados
- - Divida as mudanças em commits lógicos que possam ser revisados independentemente
-
-2. **Qualidade do Código**
+3. **Depuração:** Abra com VS Code (`F5`).
- - Todos os PRs devem passar nas verificações de CI que incluem tanto linting quanto formatação
- - Resolva quaisquer avisos ou erros do ESLint antes de enviar
- - Responda a todos os feedbacks do Ellipsis, nossa ferramenta automatizada de revisão de código
- - Siga as melhores práticas de TypeScript e mantenha a segurança de tipos
+### Diretrizes para Escrever Código
-3. **Testes**
+- Um PR focado por recurso ou correção.
+- Siga as melhores práticas de ESLint e TypeScript.
+- Escreva commits claros e descritivos referenciando issues (ex: `Fixes #123`).
+- Forneça testes completos (`npm test`).
+- Rebase na branch `main` mais recente antes do envio.
- - Adicione testes para novos recursos
- - Execute `npm test` para garantir que todos os testes passem
- - Atualize os testes existentes se suas mudanças os afetarem
- - Inclua tanto testes unitários quanto de integração quando apropriado
+### Enviando um Pull Request
-4. **Diretrizes de Commit**
+- Comece como **PR em rascunho** se buscar feedback antecipado.
+- Descreva claramente suas alterações seguindo o Template de Pull Request.
+- Forneça capturas de tela/vídeos para alterações de UI.
+- Indique se atualizações de documentação são necessárias.
- - Escreva mensagens de commit claras e descritivas
- - Referencie issues relevantes nos commits usando #número-da-issue
+### Política de Pull Request
-5. **Antes de Enviar**
+- Deve referenciar issues pré-aprovadas e atribuídas.
+- PRs que não seguem a política podem ser fechados.
+- PRs devem passar nos testes de CI, alinhar-se ao roadmap e ter documentação clara.
- - Faça rebase da sua branch na última main
- - Certifique-se de que sua branch é construída com sucesso
- - Verifique novamente se todos os testes estão passando
- - Revise suas mudanças para qualquer código de depuração ou logs de console
+### Processo de Revisão
-6. **Descrição do Pull Request**
- - Descreva claramente o que suas mudanças fazem
- - Inclua passos para testar as mudanças
- - Liste quaisquer mudanças significativas
- - Adicione capturas de tela para mudanças na UI
+- **Triagem diária:** Verificações rápidas pelos mantenedores.
+- **Revisão semanal detalhada:** Avaliação abrangente.
+- **Itere rapidamente** com base no feedback.
-## Acordo de Contribuição
+## Legal
-Ao enviar um pull request, você concorda que suas contribuições serão licenciadas sob a mesma licença do projeto ([Apache 2.0](../LICENSE)).
+Ao enviar um pull request, você concorda que suas contribuições serão licenciadas sob a Licença Apache 2.0, consistente com o licenciamento do Roo Code.
diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md
index 153580a893f..10d827d9583 100644
--- a/locales/pt-BR/README.md
+++ b/locales/pt-BR/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Seja você esteja buscando um parceiro de codificação flexível, um arquiteto de sistema ou funções especializadas como engenheiro de QA ou gerente de produto, o Roo Code pode ajudá-lo a construir software com mais eficiência.
-Confira o [CHANGELOG](../CHANGELOG.md) para atualizações e correções detalhadas.
+Confira o [CHANGELOG](../../CHANGELOG.md) para atualizações e correções detalhadas.
---
-## 🎉 Roo Code 3.15 Lançado
+## 🎉 Roo Code 3.17 Lançado
-O Roo Code 3.15 traz novas funcionalidades e melhorias baseadas no seu feedback!
+O Roo Code 3.17 traz poderosas novas funcionalidades e melhorias baseadas no seu feedback!
-- **Cache para prompts no Vertex** - O Vertex AI agora suporta cache de prompts, melhorando os tempos de resposta e reduzindo custos de API.
-- **Fallback para Terminal** - Implementado um mecanismo de fallback quando a integração do shell do terminal do VSCode falha, garantindo operações de terminal mais confiáveis.
-- **Snippets de Código Aprimorados** - Renderização e interação aprimoradas com snippets de código na interface de chat para melhor legibilidade e usabilidade.
+- **Cache Implícito para Gemini** - Chamadas de API Gemini agora são automaticamente armazenadas em cache, reduzindo custos de API.
+- **Seleção de Modo mais Inteligente** - Definições de modo agora podem incluir orientações sobre quando cada modo deve ser usado, permitindo melhor orquestração.
+- **Condensação Inteligente de Contexto** - Resume de forma inteligente o histórico de conversas quando o contexto se enche, em vez de truncar (ative em Configurações -> Experimental).
---
@@ -178,32 +178,36 @@ Adoramos contribuições da comunidade! Comece lendo nosso [CONTRIBUTING.md](CON
Obrigado a todos os nossos contribuidores que ajudaram a tornar o Roo Code melhor!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Licença
diff --git a/locales/ru/CODE_OF_CONDUCT.md b/locales/ru/CODE_OF_CONDUCT.md
index cfc93a3b73c..203a836d24f 100644
--- a/locales/ru/CODE_OF_CONDUCT.md
+++ b/locales/ru/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • Русский
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Кодекс поведения участников
## Наше обязательство
diff --git a/locales/ru/CONTRIBUTING.md b/locales/ru/CONTRIBUTING.md
index 0c12ef5cd22..38d75b3f9dc 100644
--- a/locales/ru/CONTRIBUTING.md
+++ b/locales/ru/CONTRIBUTING.md
@@ -1,72 +1,129 @@
-# Руководство по участию в проекте
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • Русский
-Спасибо за интерес к участию в развитии Roo Code! Мы рады приветствовать новых участников в нашем сообществе.
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## Присоединяйтесь к сообществу
+# Вклад в Roo Code
-- [Discord](https://discord.gg/roocode)
-- [Reddit](https://www.reddit.com/r/roocode)
+Roo Code — проект, управляемый сообществом, и мы высоко ценим каждый вклад. Для упрощения сотрудничества мы работаем по принципу [Issue-First](#подход-issue-first), что означает, что все [Pull Request (PR)](#отправка-pull-request) должны сначала быть связаны с GitHub Issue. Пожалуйста, внимательно ознакомься с этим руководством.
-## Сообщение об ошибках
+## Содержание
-Если вы обнаружили ошибку, пожалуйста, создайте issue в нашем репозитории. Убедитесь, что:
+- [Перед тем как внести вклад](#перед-тем-как-внести-вклад)
+- [Поиск и планирование вклада](#поиск-и-планирование-вклада)
+- [Процесс разработки и отправки](#процесс-разработки-и-отправки)
+- [Юридическая информация](#юридическая-информация)
-1. Ошибка воспроизводима
-2. Вы предоставили всю необходимую информацию для воспроизведения ошибки
-3. Вы проверили, что подобная проблема еще не была зарегистрирована
+## Перед тем как внести вклад
-## Над чем работать
+### 1. Кодекс поведения
-Есть несколько способов начать участие в проекте:
+Все участники должны соблюдать наш [Кодекс поведения](./CODE_OF_CONDUCT.md).
-1. Просмотрите открытые issues с меткой "good first issue"
-2. Исправьте опечатки в документации
-3. Добавьте тесты для существующего кода
-4. Предложите новые функции через issues
+### 2. Дорожная карта проекта
-## Дорожная карта проекта
+Наша дорожная карта определяет направление проекта. Согласуй свой вклад с этими ключевыми целями:
-Наши текущие приоритеты:
+### Надежность в первую очередь
-- Улучшение производительности и стабильности
-- Расширение поддержки языков программирования
-- Улучшение пользовательского интерфейса
-- Интеграция с популярными инструментами разработки
+- Обеспечение стабильной работы редактирования различий и выполнения команд
+- Сокращение точек трения, препятствующих регулярному использованию
+- Гарантия бесперебойной работы на всех языках и платформах
+- Расширение надежной поддержки для широкого спектра ИИ-провайдеров и моделей
-## Настройка среды разработки
+### Улучшенный пользовательский опыт
-1. Форкните репозиторий
-2. Клонируйте ваш форк:
- ```bash
- git clone https://github.com/YOUR_USERNAME/roo-code.git
- ```
-3. Установите зависимости:
- ```bash
- npm install
- ```
-4. Создайте новую ветку для ваших изменений:
- ```bash
- git checkout -b feature/your-feature-name
- ```
+- Упрощение пользовательского интерфейса для большей ясности и интуитивности
+- Постоянное совершенствование рабочего процесса для соответствия высоким ожиданиям разработчиков
-## Написание и отправка кода
+### Лидерство в производительности агентов
-1. Следуйте существующему стилю кода
-2. Добавляйте тесты для нового кода
-3. Обновляйте документацию при необходимости
-4. Убедитесь, что все тесты проходят
-5. Создайте pull request с описанием ваших изменений
+- Создание комплексных показателей оценки (evals) для измерения реальной продуктивности
+- Упрощение запуска и интерпретации этих оценок для всех пользователей
+- Внедрение улучшений, демонстрирующих явное повышение оценочных показателей
-## Соглашение о сотрудничестве
+Упоминай связь с этими направлениями в своих PR.
-Отправляя pull request, вы соглашаетесь с тем, что ваш код будет распространяться под лицензией проекта. Все участники должны следовать нашему [Кодексу поведения](CODE_OF_CONDUCT.md).
+### 3. Присоединяйся к сообществу Roo Code
-## Получение помощи
+- **Основной способ:** Присоединись к нашему [Discord](https://discord.gg/roocode) и отправь личное сообщение **Hannes Rudolph (`hrudolph`)**.
+- **Альтернатива:** Опытные участники могут взаимодействовать напрямую через [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-Если у вас возникли вопросы или нужна помощь:
+## Поиск и планирование вклада
-1. Проверьте существующую документацию
-2. Спросите в Discord сообществе
-3. Создайте issue с меткой "question"
+### Виды вклада
-Еще раз спасибо за ваш интерес к улучшению Roo Code!
+- **Исправление ошибок:** Решение проблем в коде.
+- **Новые функции:** Добавление функциональности.
+- **Документация:** Улучшение руководств и ясности.
+
+### Подход Issue-First
+
+Весь вклад должен начинаться с GitHub Issue.
+
+- **Проверь существующие issues:** Поищи в [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Создай issue:** Используй подходящие шаблоны:
+ - **Баги:** Шаблон "Bug Report".
+ - **Функции:** Шаблон "Detailed Feature Proposal". Требуется одобрение перед началом.
+- **Заяви issue:** Оставь комментарий и дождись официального назначения.
+
+**PR без одобренных issue могут быть закрыты.**
+
+### Решение, над чем работать
+
+- Проверь [GitHub проект](https://github.com/orgs/RooVetGit/projects/1) на наличие незанятых "Good First Issues".
+- Для документации посети [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
+
+### Сообщение об ошибках
+
+- Сначала проверь существующие сообщения.
+- Создай новые сообщения об ошибках, используя [шаблон "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Уязвимости безопасности:** Сообщай приватно через [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
+
+## Процесс разработки и отправки
+
+### Настройка среды разработки
+
+1. **Fork & Clone:**
+
+```
+git clone https://github.com/ТВОЙ_ПОЛЬЗОВАТЕЛЬ/Roo-Code.git
+```
+
+2. **Установка зависимостей:**
+
+```
+npm run install:all
+```
+
+3. **Отладка:** Открой в VS Code (`F5`).
+
+### Руководство по написанию кода
+
+- Один сфокусированный PR на функцию или исправление.
+- Следуй лучшим практикам ESLint и TypeScript.
+- Пиши ясные, описательные сообщения коммитов с ссылками на issues (например, `Fixes #123`).
+- Обеспечь тщательное тестирование (`npm test`).
+- Перебазируй на последнюю ветку `main` перед отправкой.
+
+### Отправка Pull Request
+
+- Начни с **черновика PR**, если ищешь ранний фидбек.
+- Четко опиши свои изменения, следуя шаблону Pull Request.
+- Предоставь скриншоты/видео для изменений UI.
+- Укажи, нужны ли обновления документации.
+
+### Политика Pull Request
+
+- Должен ссылаться на предварительно одобренные и назначенные issue.
+- PR, не соответствующие политике, могут быть закрыты.
+- PR должны проходить CI-тесты, соответствовать дорожной карте и иметь четкую документацию.
+
+### Процесс проверки
+
+- **Ежедневный отбор:** Быстрые проверки мейнтейнерами.
+- **Еженедельный глубокий обзор:** Комплексная оценка.
+- **Быстро итерируй** на основе полученного фидбека.
+
+## Юридическая информация
+
+Отправляя pull request, ты соглашаешься, что твой вклад будет лицензирован под лицензией Apache 2.0, в соответствии с лицензией Roo Code.
diff --git a/locales/ru/README.md b/locales/ru/README.md
index d61b395731e..d25f9cd861e 100644
--- a/locales/ru/README.md
+++ b/locales/ru/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../ca/README.md) • [Deutsch](../de/README.md) • [Español](../es/README.md) • [Français](../fr/README.md) • [हिन्दी](../hi/README.md) • [Italiano](../it/README.md) • Русский
+[English](../../README.md) • [Català](../ca/README.md) • [Deutsch](../de/README.md) • [Español](../es/README.md) • [Français](../fr/README.md) • [हिन्दी](../hi/README.md) • [Italiano](../it/README.md) • [Nederlands](../nl/README.md) • Русский
@@ -49,13 +49,13 @@
---
-## 🎉 Выпущен Roo Code 3.15
+## 🎉 Выпущен Roo Code 3.17
-Roo Code 3.15 приносит новые функции и улучшения на основе ваших отзывов!
+Roo Code 3.17 предлагает мощные новые функции и улучшения на основе ваших отзывов!
-- **Кэширование промптов для Vertex** - Vertex AI теперь поддерживает кэширование промптов, улучшая время отклика и снижая затраты на API.
-- **Резервный механизм для терминала** - Реализован резервный механизм на случай сбоя интеграции оболочки терминала VSCode, обеспечивающий более надежную работу терминала.
-- **Улучшенные фрагменты кода** - Улучшены отображение и взаимодействие с фрагментами кода в интерфейсе чата для лучшей читаемости и удобства использования.
+- **Неявное кэширование для Gemini** - Вызовы API Gemini теперь автоматически кэшируются, снижая затраты на API.
+- **Более умный выбор режима** - Определения режимов теперь могут включать рекомендации о том, когда следует использовать каждый режим, обеспечивая лучшую оркестровку.
+- **Интеллектуальное сжатие контекста** - Интеллектуально резюмирует историю разговоров, когда контекст заполняется, вместо простого обрезания (включается в Настройки -> Экспериментальные).
---
@@ -180,32 +180,36 @@ code --install-extension bin/roo-cline-.vsix
Спасибо всем нашим участникам, которые помогли сделать Roo Code лучше!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Лицензия
diff --git a/locales/tr/CODE_OF_CONDUCT.md b/locales/tr/CODE_OF_CONDUCT.md
index 6476418f30a..678676a0b43 100644
--- a/locales/tr/CODE_OF_CONDUCT.md
+++ b/locales/tr/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • Türkçe • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Katkıda Bulunan Sözleşmesi Davranış Kuralları
## Taahhüdümüz
diff --git a/locales/tr/CONTRIBUTING.md b/locales/tr/CONTRIBUTING.md
index 39ddb8b1b76..81bbd7f72b0 100644
--- a/locales/tr/CONTRIBUTING.md
+++ b/locales/tr/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Roo Code'a Katkıda Bulunma
-
-Roo Code'a katkıda bulunmakla ilgilendiğiniz için çok mutluyuz. İster bir hatayı düzeltiyor, ister bir özellik ekliyor, ister belgelerimizi geliştiriyor olun, her katkı Roo Code'u daha akıllı hale getirir! Topluluğumuzu canlı ve misafirperver tutmak için tüm üyelerin [Davranış Kuralları](CODE_OF_CONDUCT.md)'na uyması gerekir.
-
-## Topluluğumuza Katılın
-
-Tüm katkıda bulunanları [Discord topluluğumuza](https://discord.gg/roocode) katılmaya şiddetle teşvik ediyoruz! Discord sunucumuzun bir parçası olmak size şu konularda yardımcı olur:
-
-- Katkılarınız hakkında gerçek zamanlı yardım ve rehberlik alın
-- Diğer katkıda bulunanlar ve çekirdek ekip üyeleriyle bağlantı kurun
-- Proje gelişmeleri ve öncelikleri hakkında güncel kalın
-- Roo Code'un geleceğini şekillendiren tartışmalara katılın
-- Diğer geliştiricilerle işbirliği fırsatları bulun
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-## Hataları veya Sorunları Bildirme
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • Türkçe • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-Hata raporları Roo Code'u herkes için daha iyi hale getirmeye yardımcı olur! Yeni bir sorun oluşturmadan önce, lütfen yinelemeleri önlemek için [mevcut olanları arayın](https://github.com/RooVetGit/Roo-Code/issues). Bir hatayı bildirmeye hazır olduğunuzda, ilgili bilgileri doldurmanıza yardımcı olacak bir şablon bulacağınız [sorunlar sayfamıza](https://github.com/RooVetGit/Roo-Code/issues/new/choose) gidin.
-
-
- 🔐 Önemli: Bir güvenlik açığı keşfederseniz, lütfen özel olarak bildirmek için Github güvenlik aracını kullanın.
-
+# Roo Code'a Katkıda Bulunma
-## Ne Üzerinde Çalışacağınıza Karar Verme
+Roo Code, topluluk odaklı bir projedir ve her katkıyı çok önemsiyoruz. İşbirliğini kolaylaştırmak için [Issue-First](#issue-first-yaklaşımı) yaklaşımıyla çalışıyoruz; bu, tüm [Pull Request'lerin (PR'lar)](#pull-request-gönderme) önce bir GitHub Issue'ya bağlanması gerektiği anlamına gelir. Lütfen bu rehberi dikkatlice incele.
-İyi bir ilk katkı mı arıyorsunuz? [Roo Code Sorunları](https://github.com/orgs/RooVetGit/projects/1) Github Projemizin "Issue [Unassigned]" bölümündeki sorunları kontrol edin. Bunlar özellikle yeni katkıda bulunanlar ve biraz yardıma ihtiyaç duyduğumuz alanlar için seçilmiştir!
+## İçindekiler
-[Belgelerimize](https://docs.roocode.com/) katkıları da memnuniyetle karşılıyoruz! İster yazım hatalarını düzeltmek, mevcut kılavuzları geliştirmek veya yeni eğitim içeriği oluşturmak olsun - herkesin Roo Code'dan en iyi şekilde yararlanmasına yardımcı olan topluluk odaklı bir kaynak deposu oluşturmak istiyoruz. Dosyayı düzenlemek için Github'daki doğru yere hızlıca gitmek için herhangi bir sayfada "Edit this page" düğmesine tıklayabilir veya doğrudan https://github.com/RooVetGit/Roo-Code-Docs adresine dalabilirsiniz.
+- [Katkıdan Önce](#katkıdan-önce)
+- [Katkı Bulma & Planlama](#katkı-bulma--planlama)
+- [Geliştirme & Gönderim Süreci](#geliştirme--gönderim-süreci)
+- [Yasal](#yasal)
-Daha büyük bir özellik üzerinde çalışmayı planlıyorsanız, lütfen önce bir [özellik isteği](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) oluşturun, böylece Roo Code'un vizyonuyla uyumlu olup olmadığını tartışabiliriz. Ayrıca, fikrinizin stratejik yönümüze uyup uymadığını görmek için aşağıdaki [Proje Yol Haritası](#proje-yol-haritası)'nı kontrol edebilirsiniz.
+## Katkıdan Önce
-## Proje Yol Haritası
+### 1. Davranış Kuralları
-Roo Code, önceliklerimizi ve gelecekteki yönümüzü yönlendiren net bir geliştirme yol haritasına sahiptir. Yol haritamızı anlamak size şu konularda yardımcı olabilir:
+Tüm katkı sağlayanlar [Davranış Kuralları](./CODE_OF_CONDUCT.md)'na uymalıdır.
-- Katkılarınızı proje hedefleriyle uyumlu hale getirmek
-- Uzmanlığınızın en değerli olacağı alanları belirlemek
-- Belirli tasarım kararlarının arkasındaki bağlamı anlamak
-- Vizyonumuzu destekleyen yeni özellikler için ilham bulmak
+### 2. Proje Yol Haritası
-Mevcut yol haritamız altı temel sütun üzerine odaklanmaktadır:
+Yol haritamız projenin yönünü belirler. Katkılarını bu temel hedeflerle uyumlu hale getir:
-### Sağlayıcı Desteği
+### Güvenilirlik Öncelikli
-Mümkün olduğunca çok sağlayıcıyı desteklemeyi hedefliyoruz:
+- Diff düzenleme ve komut yürütme işlemlerinin sürekli olarak güvenilir olmasını sağlamak
+- Düzenli kullanımı engelleyen sürtünme noktalarını azaltmak
+- Tüm dillerde ve platformlarda sorunsuz çalışmayı garanti etmek
+- Çok çeşitli yapay zeka sağlayıcıları ve modelleri için güçlü desteği genişletmek
-- Daha çok yönlü "OpenAI Uyumlu" destek
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Ollama ve LM Studio için geliştirilmiş destek
+### Geliştirilmiş Kullanıcı Deneyimi
-### Model Desteği
+- Daha fazla netlik ve sezgisellik için kullanıcı arayüzünü basitleştirmek
+- Geliştiricilerin yüksek beklentilerini karşılamak üzere iş akışını sürekli iyileştirmek
-Roo'nun yerel modeller de dahil olmak üzere mümkün olduğunca çok modelde iyi çalışmasını istiyoruz:
+### Ajan Performansında Liderlik
-- Özel sistem yönlendirmesi ve iş akışları aracılığıyla yerel model desteği
-- Kıyaslama değerlendirmeleri ve test vakaları
+- Gerçek dünyadaki üretkenliği ölçmek için kapsamlı değerlendirme kriterleri (evals) oluşturmak
+- Herkesin bu değerlendirmeleri kolayca çalıştırıp yorumlamasını sağlamak
+- Değerlendirme puanlarında net artışlar gösteren iyileştirmeler sunmak
-### Sistem Desteği
+PR'larında bu alanlarla olan bağlantıyı belirt.
-Roo'nun herkesin bilgisayarında iyi çalışmasını istiyoruz:
+### 3. Roo Code Topluluğuna Katıl
-- Çapraz platform terminal entegrasyonu
-- Mac, Windows ve Linux için güçlü ve tutarlı destek
+- **Ana yöntem:** [Discord](https://discord.gg/roocode)'umuza katıl ve **Hannes Rudolph (`hrudolph`)**'a DM gönder.
+- **Alternatif:** Deneyimli katkı sağlayanlar [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1) üzerinden doğrudan katılabilir.
-### Dokümantasyon
+## Katkı Bulma & Planlama
-Tüm kullanıcılar ve katkıda bulunanlar için kapsamlı, erişilebilir dokümantasyon istiyoruz:
+### Katkı Türleri
-- Genişletilmiş kullanıcı kılavuzları ve öğreticiler
-- Net API dokümantasyonu
-- Katkıda bulunanlar için daha iyi rehberlik
-- Çok dilli dokümantasyon kaynakları
-- Etkileşimli örnekler ve kod örnekleri
+- **Hata düzeltmeleri:** Koddaki sorunları çözmek.
+- **Yeni özellikler:** Yeni işlevsellik eklemek.
+- **Dokümantasyon:** Rehberleri geliştirmek ve netleştirmek.
-### Kararlılık
+### Issue-First Yaklaşımı
-Hata sayısını önemli ölçüde azaltmak ve otomatik testleri artırmak istiyoruz:
+Tüm katkılar bir GitHub Issue ile başlamalıdır.
-- Hata ayıklama günlüğü anahtarı
-- Hata/destek istekleriyle birlikte göndermek için "Makine/Görev Bilgisi" kopyalama düğmesi
+- **Mevcut issue'ları kontrol et:** [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues)'da ara.
+- **Issue oluştur:** Uygun şablonları kullan:
+ - **Hatalar:** "Bug Report" şablonu.
+ - **Özellikler:** "Detailed Feature Proposal" şablonu. Başlamadan önce onay gerekir.
+- **Issue'ları sahiplen:** Yorum yap ve resmi atamayı bekle.
-### Uluslararasılaştırma
+**Onaylanmış issue'lara bağlı olmayan PR'lar kapatılabilir.**
-Roo'nun herkesin dilini konuşmasını istiyoruz:
+### Ne Üzerinde Çalışacağına Karar Verme
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+- [GitHub Projesi](https://github.com/orgs/RooVetGit/projects/1)'nde atanmamış "Good First Issues" bak.
+- Dokümantasyon için [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs)'u ziyaret et.
-Özellikle yol haritamızın hedeflerini ileriye taşıyan katkıları memnuniyetle karşılıyoruz. Bu sütunlarla uyumlu bir şey üzerinde çalışıyorsanız, lütfen PR açıklamanızda bundan bahsedin.
+### Hata veya Sorun Bildirme
-## Geliştirme Kurulumu
+- Önce mevcut raporları kontrol et.
+- ["Bug Report" şablonu](https://github.com/RooVetGit/Roo-Code/issues/new/choose) kullanarak yeni hata raporları oluştur.
+- **Güvenlik açıkları:** [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new) aracılığıyla özel olarak bildir.
-1. Depoyu **klonlayın**:
+## Geliştirme & Gönderim Süreci
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
-```
+### Geliştirme Ortamı Kurulumu
-2. **Bağımlılıkları yükleyin**:
+1. **Fork & Clone:**
-```sh
-npm run install:all
```
-
-3. **Webview'ı başlatın (HMR ile Vite/React uygulaması)**:
-
-```sh
-npm run dev
+git clone https://github.com/KULLANICI_ADIN/Roo-Code.git
```
-4. **Hata ayıklama**:
- VSCode'da `F5` tuşuna basın (veya **Run** → **Start Debugging**) Roo Code yüklenmiş yeni bir oturum açmak için.
-
-Webview'daki değişiklikler anında görünecektir. Ana uzantıdaki değişiklikler uzantı ana bilgisayarının yeniden başlatılmasını gerektirecektir.
-
-Alternatif olarak, bir .vsix dosyası oluşturabilir ve doğrudan VSCode'a kurabilirsiniz:
+2. **Bağımlılıkları yükle:**
-```sh
-npm run build
```
-
-`bin/` dizininde bir `.vsix` dosyası görünecek ve şu komutla kurulabilir:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Kod Yazma ve Gönderme
-
-Herkes Roo Code'a kod katkısında bulunabilir, ancak katkılarınızın sorunsuz bir şekilde entegre edilebilmesi için bu kurallara uymanızı rica ediyoruz:
-
-1. **Pull Request'leri Odaklı Tutun**
-
- - PR'leri tek bir özellik veya hata düzeltmesiyle sınırlayın
- - Daha büyük değişiklikleri daha küçük, ilgili PR'lere bölün
- - Değişiklikleri bağımsız olarak incelenebilen mantıklı commitlere bölün
-
-2. **Kod Kalitesi**
+3. **Hata ayıklama:** VS Code'da `F5` ile aç.
- - Tüm PR'ler hem linting hem de formatlama içeren CI kontrollerini geçmelidir
- - Göndermeden önce tüm ESLint uyarılarını veya hatalarını çözün
- - Otomatik kod inceleme aracımız Ellipsis'ten gelen tüm geri bildirimlere yanıt verin
- - TypeScript en iyi uygulamalarını takip edin ve tip güvenliğini koruyun
+### Kod Yazma Rehberi
-3. **Test Etme**
+- Her özellik veya düzeltme için odaklı bir PR.
+- ESLint ve TypeScript en iyi uygulamalarını takip et.
+- Issue'lara referans veren açık, açıklayıcı commit mesajları yaz (örn. `Fixes #123`).
+- Kapsamlı testler sağla (`npm test`).
+- Göndermeden önce en son `main` branch'i üzerine rebase yap.
- - Yeni özellikler için testler ekleyin
- - Tüm testlerin geçtiğinden emin olmak için `npm test` çalıştırın
- - Değişiklikleriniz etkiliyorsa mevcut testleri güncelleyin
- - Uygun olduğunda hem birim testlerini hem de entegrasyon testlerini dahil edin
+### Pull Request Gönderme
-4. **Commit Yönergeleri**
+- Erken geri bildirim istiyorsan **taslak PR** olarak başla.
+- Pull Request Şablonunu takip ederek değişikliklerini açıkça tanımla.
+- UI değişiklikleri için ekran görüntüleri/videolar sağla.
+- Dokümantasyon güncellemeleri gerekip gerekmediğini belirt.
- - Net, açıklayıcı commit mesajları yazın
- - #issue-number kullanarak commitlerdeki ilgili sorunlara atıfta bulunun
+### Pull Request Politikası
-5. **Göndermeden Önce**
+- Önceden onaylanmış ve atanmış issue'lara referans vermelidir.
+- Politikaya uymayan PR'lar kapatılabilir.
+- PR'lar CI testlerini geçmeli, yol haritasıyla uyumlu olmalı ve net dokümantasyona sahip olmalıdır.
- - Dalınızı en son main üzerine rebase edin
- - Dalınızın başarıyla oluşturulduğundan emin olun
- - Tüm testlerin geçtiğini tekrar kontrol edin
- - Değişikliklerinizi hata ayıklama kodu veya konsol günlükleri için gözden geçirin
+### İnceleme Süreci
-6. **Pull Request Açıklaması**
- - Değişikliklerinizin ne yaptığını açıkça açıklayın
- - Değişiklikleri test etmek için adımlar ekleyin
- - Herhangi bir önemli değişikliği listeleyin
- - UI değişiklikleri için ekran görüntüleri ekleyin
+- **Günlük triyaj:** Maintainer'lar tarafından hızlı kontroller.
+- **Haftalık detaylı inceleme:** Kapsamlı değerlendirme.
+- **Geri bildirim temelinde hızla yinele.**
-## Katkı Anlaşması
+## Yasal
-Bir pull request göndererek, katkılarınızın projeyle aynı lisans altında ([Apache 2.0](../LICENSE)) lisanslanacağını kabul edersiniz.
+Pull request göndererek, katkılarının Roo Code'un lisanslamasıyla tutarlı olarak Apache 2.0 Lisansı altında lisanslanacağını kabul etmiş olursun.
diff --git a/locales/tr/README.md b/locales/tr/README.md
index 44b5f286187..2f9632356ae 100644
--- a/locales/tr/README.md
+++ b/locales/tr/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
İster esnek bir kodlama ortağı, ister bir sistem mimarı, isterse QA mühendisi veya ürün yöneticisi gibi uzmanlaşmış roller arıyor olun, Roo Code yazılım geliştirme sürecinizi daha verimli hale getirmenize yardımcı olabilir.
-Detaylı güncellemeler ve düzeltmeler için [CHANGELOG](../CHANGELOG.md) dosyasını kontrol edin.
+Detaylı güncellemeler ve düzeltmeler için [CHANGELOG](../../CHANGELOG.md) dosyasını kontrol edin.
---
-## 🎉 Roo Code 3.15 Yayınlandı
+## 🎉 Roo Code 3.17 Yayınlandı
-Roo Code 3.15 geri bildirimlerinize dayanarak yeni özellikler ve iyileştirmeler getiriyor!
+Roo Code 3.17 geri bildirimlerinize dayanarak güçlü yeni özellikler ve iyileştirmeler getiriyor!
-- **Vertex için Prompt Önbelleği** - Vertex AI artık prompt önbelleklemeyi destekliyor, yanıt sürelerini iyileştiriyor ve API maliyetlerini azaltıyor.
-- **Terminal Yedek Mekanizması** - VSCode terminal kabuk entegrasyonu başarısız olduğunda devreye giren bir yedek mekanizma uygulandı, daha güvenilir terminal işlemleri sağlanıyor.
-- **Geliştirilmiş Kod Parçacıkları** - Daha iyi okunabilirlik ve kullanılabilirlik için sohbet arayüzünde kod parçacıklarının görüntülenmesi ve etkileşimi geliştirildi.
+- **Gemini için Örtük Önbelleğe Alma** - Gemini API çağrıları artık otomatik olarak önbelleğe alınarak API maliyetleri azaltılıyor.
+- **Daha Akıllı Mod Seçimi** - Mod tanımları artık her modun ne zaman kullanılması gerektiği konusunda yönlendirme içerebiliyor, daha iyi orkestrasyon sağlıyor.
+- **Akıllı Bağlam Yoğunlaştırma** - Bağlam dolduğunda, kırpmak yerine konuşma geçmişini akıllıca özetliyor (Ayarlar -> Deneysel bölümünden etkinleştirin).
---
@@ -178,32 +178,36 @@ Topluluk katkılarını seviyoruz! [CONTRIBUTING.md](CONTRIBUTING.md) dosyasın
Roo Code'u daha iyi hale getirmeye yardımcı olan tüm katkıda bulunanlara teşekkür ederiz!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Lisans
diff --git a/locales/vi/CODE_OF_CONDUCT.md b/locales/vi/CODE_OF_CONDUCT.md
index 78496b66c78..79e0094b9ea 100644
--- a/locales/vi/CODE_OF_CONDUCT.md
+++ b/locales/vi/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • Tiếng Việt • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# Quy Tắc Ứng Xử theo Giao Ước Người Đóng Góp
## Cam Kết Của Chúng Tôi
diff --git a/locales/vi/CONTRIBUTING.md b/locales/vi/CONTRIBUTING.md
index 6f4c2c74709..d8f9374b091 100644
--- a/locales/vi/CONTRIBUTING.md
+++ b/locales/vi/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# Đóng Góp cho Roo Code
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-Chúng tôi rất vui mừng vì bạn quan tâm đến việc đóng góp cho Roo Code. Cho dù bạn đang sửa lỗi, thêm tính năng, hay cải thiện tài liệu của chúng tôi, mỗi đóng góp đều làm cho Roo Code thông minh hơn! Để giữ cho cộng đồng của chúng tôi sôi động và thân thiện, tất cả thành viên phải tuân thủ [Quy Tắc Ứng Xử](CODE_OF_CONDUCT.md) của chúng tôi.
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • Tiếng Việt • [简体中文](../zh-CN/CONTRIBUTING.md) • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## Tham Gia Cộng Đồng của Chúng Tôi
+# Đóng góp cho Roo Code
-Chúng tôi mạnh mẽ khuyến khích tất cả người đóng góp tham gia [cộng đồng Discord](https://discord.gg/roocode) của chúng tôi! Việc là một phần của máy chủ Discord của chúng tôi giúp bạn:
+Roo Code là một dự án do cộng đồng dẫn dắt và chúng mình rất trân trọng mọi đóng góp. Để đơn giản hóa quy trình hợp tác, chúng mình áp dụng cách tiếp cận [Issue-First](#cách-tiếp-cận-issue-first), nghĩa là tất cả [Pull Request (PR)](#gửi-pull-request) phải được liên kết với một GitHub Issue trước. Vui lòng đọc kỹ hướng dẫn này.
-- Nhận hỗ trợ và hướng dẫn thời gian thực về đóng góp của bạn
-- Kết nối với những người đóng góp khác và các thành viên nhóm cốt lõi
-- Cập nhật về sự phát triển và ưu tiên của dự án
-- Tham gia vào các cuộc thảo luận định hình tương lai của Roo Code
-- Tìm cơ hội hợp tác với các nhà phát triển khác
+## Mục lục
-## Báo Cáo Lỗi hoặc Vấn Đề
+- [Trước khi đóng góp](#trước-khi-đóng-góp)
+- [Tìm kiếm & lên kế hoạch đóng góp](#tìm-kiếm--lên-kế-hoạch-đóng-góp)
+- [Quy trình phát triển & gửi bài](#quy-trình-phát-triển--gửi-bài)
+- [Pháp lý](#pháp-lý)
-Báo cáo lỗi giúp cải thiện Roo Code cho mọi người! Trước khi tạo một vấn đề mới, vui lòng [tìm kiếm những vấn đề hiện có](https://github.com/RooVetGit/Roo-Code/issues) để tránh trùng lặp. Khi bạn đã sẵn sàng báo cáo lỗi, hãy truy cập [trang vấn đề](https://github.com/RooVetGit/Roo-Code/issues/new/choose) của chúng tôi, nơi bạn sẽ tìm thấy một mẫu để giúp bạn điền thông tin liên quan.
+## Trước khi đóng góp
-
- 🔐 Quan trọng: Nếu bạn phát hiện lỗ hổng bảo mật, vui lòng sử dụng công cụ bảo mật Github để báo cáo riêng tư.
-
+### 1. Quy tắc ứng xử
-## Quyết Định Làm Việc trên Cái Gì
+Tất cả thành viên đóng góp phải tuân thủ [Quy tắc ứng xử](./CODE_OF_CONDUCT.md) của chúng mình.
-Tìm kiếm đóng góp đầu tiên tốt? Kiểm tra các vấn đề trong phần "Issue [Unassigned]" của [Dự án Github Roo Code](https://github.com/orgs/RooVetGit/projects/1) của chúng tôi. Những vấn đề này được chọn lọc đặc biệt cho người đóng góp mới và các lĩnh vực mà chúng tôi muốn nhận được sự giúp đỡ!
+### 2. Lộ trình phát triển dự án
-Chúng tôi cũng hoan nghênh đóng góp cho [tài liệu](https://docs.roocode.com/) của chúng tôi! Dù là sửa lỗi chính tả, cải thiện hướng dẫn hiện có, hay tạo nội dung giáo dục mới - chúng tôi muốn xây dựng một kho tài nguyên do cộng đồng thúc đẩy giúp mọi người tận dụng tối đa Roo Code. Bạn có thể nhấp vào "Edit this page" trên bất kỳ trang nào để nhanh chóng đến đúng vị trí trong Github để chỉnh sửa tệp, hoặc bạn có thể đi trực tiếp vào https://github.com/RooVetGit/Roo-Code-Docs.
+Lộ trình của chúng mình định hướng dự án. Hãy điều chỉnh đóng góp của bạn theo các mục tiêu chính:
-Nếu bạn đang lên kế hoạch làm việc trên một tính năng lớn hơn, vui lòng tạo [yêu cầu tính năng](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop) trước để chúng tôi có thể thảo luận xem nó có phù hợp với tầm nhìn của Roo Code không. Bạn cũng có thể kiểm tra [Lộ Trình Dự Án](#lộ-trình-dự-án) bên dưới để xem liệu ý tưởng của bạn có phù hợp với định hướng chiến lược của chúng tôi không.
+### Độ tin cậy là ưu tiên hàng đầu
-## Lộ Trình Dự Án
+- Đảm bảo việc chỉnh sửa diff và thực thi lệnh luôn đáng tin cậy
+- Giảm thiểu các điểm cản trở khiến người dùng ngại sử dụng thường xuyên
+- Đảm bảo hoạt động mượt mà trên mọi ngôn ngữ và nền tảng
+- Mở rộng hỗ trợ mạnh mẽ cho nhiều nhà cung cấp và mô hình AI đa dạng
-Roo Code có một lộ trình phát triển rõ ràng hướng dẫn các ưu tiên và định hướng tương lai của chúng tôi. Hiểu lộ trình của chúng tôi có thể giúp bạn:
+### Nâng cao trải nghiệm người dùng
-- Điều chỉnh đóng góp của bạn với mục tiêu của dự án
-- Xác định các lĩnh vực mà chuyên môn của bạn sẽ có giá trị nhất
-- Hiểu bối cảnh đằng sau một số quyết định thiết kế
-- Tìm cảm hứng cho các tính năng mới hỗ trợ tầm nhìn của chúng tôi
+- Đơn giản hóa giao diện người dùng để tăng tính rõ ràng và trực quan
+- Liên tục cải thiện quy trình làm việc để đáp ứng kỳ vọng cao của các nhà phát triển
-Lộ trình hiện tại của chúng tôi tập trung vào sáu trụ cột chính:
+### Dẫn đầu về hiệu suất agent
-### Hỗ Trợ Nhà Cung Cấp
+- Thiết lập các tiêu chuẩn đánh giá toàn diện (evals) để đo lường năng suất trong thực tế
+- Giúp mọi người dễ dàng chạy và hiểu các đánh giá này
+- Cung cấp các cải tiến thể hiện rõ sự tăng trưởng trong điểm đánh giá
-Chúng tôi hướng đến việc hỗ trợ càng nhiều nhà cung cấp càng tốt:
+Đề cập đến sự liên quan với các lĩnh vực này trong PR của bạn.
-- Hỗ trợ "OpenAI Compatible" linh hoạt hơn
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- Hỗ trợ nâng cao cho Ollama và LM Studio
+### 3. Tham gia cộng đồng Roo Code
-### Hỗ Trợ Mô Hình
+- **Cách chính:** Tham gia [Discord](https://discord.gg/roocode) của chúng mình và nhắn tin trực tiếp cho **Hannes Rudolph (`hrudolph`)**.
+- **Cách thay thế:** Cộng tác viên có kinh nghiệm có thể tham gia trực tiếp qua [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1).
-Chúng tôi muốn Roo hoạt động tốt trên càng nhiều mô hình càng tốt, bao gồm cả mô hình cục bộ:
+## Tìm kiếm & lên kế hoạch đóng góp
-- Hỗ trợ mô hình cục bộ thông qua prompting hệ thống tùy chỉnh và quy trình làm việc
-- Đánh giá hiệu suất và các trường hợp thử nghiệm
+### Các loại đóng góp
-### Hỗ Trợ Hệ Thống
+- **Sửa lỗi:** Khắc phục vấn đề trong mã nguồn.
+- **Tính năng mới:** Thêm chức năng mới.
+- **Tài liệu:** Cải thiện hướng dẫn và độ rõ ràng.
-Chúng tôi muốn Roo chạy tốt trên máy tính của mọi người:
+### Cách tiếp cận Issue-First
-- Tích hợp terminal đa nền tảng
-- Hỗ trợ mạnh mẽ và nhất quán cho Mac, Windows và Linux
+Mọi đóng góp đều phải bắt đầu bằng một GitHub Issue.
-### Tài Liệu
+- **Kiểm tra issue hiện có:** Tìm kiếm trong [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues).
+- **Tạo issue mới:** Sử dụng mẫu phù hợp:
+ - **Lỗi:** Mẫu "Bug Report".
+ - **Tính năng:** Mẫu "Detailed Feature Proposal". Cần được phê duyệt trước khi bắt đầu.
+- **Nhận issue:** Bình luận và chờ được gán chính thức.
-Chúng tôi muốn tài liệu toàn diện, dễ tiếp cận cho tất cả người dùng và người đóng góp:
+**PR không có issue đã duyệt có thể bị đóng.**
-- Hướng dẫn người dùng và hướng dẫn mở rộng
-- Tài liệu API rõ ràng
-- Hướng dẫn tốt hơn cho người đóng góp
-- Tài nguyên tài liệu đa ngôn ngữ
-- Ví dụ tương tác và mẫu mã
+### Quyết định việc cần làm
-### Ổn Định
+- Xem [Dự án GitHub](https://github.com/orgs/RooVetGit/projects/1) để tìm "Good First Issues" chưa được gán.
+- Về tài liệu, hãy xem [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs).
-Chúng tôi muốn giảm đáng kể số lượng lỗi và tăng kiểm tra tự động:
+### Báo cáo lỗi
-- Công tắc ghi nhật ký gỡ lỗi
-- Nút sao chép "Thông Tin Máy/Nhiệm Vụ" để gửi kèm với yêu cầu hỗ trợ/lỗi
+- Kiểm tra báo cáo hiện có trước.
+- Tạo báo cáo lỗi mới bằng [mẫu "Bug Report"](https://github.com/RooVetGit/Roo-Code/issues/new/choose).
+- **Lỗ hổng bảo mật:** Báo cáo riêng qua [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new).
-### Quốc Tế Hóa
+## Quy trình phát triển & gửi bài
-Chúng tôi muốn Roo nói ngôn ngữ của mọi người:
+### Thiết lập môi trường phát triển
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-Chúng tôi đặc biệt hoan nghênh những đóng góp thúc đẩy mục tiêu lộ trình của chúng tôi. Nếu bạn đang làm việc trên điều gì đó phù hợp với những trụ cột này, vui lòng đề cập đến điều đó trong mô tả PR của bạn.
-
-## Thiết Lập Phát Triển
-
-1. **Clone** kho lưu trữ:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **Cài đặt các phụ thuộc**:
-
-```sh
-npm run install:all
-```
-
-3. **Khởi động webview (ứng dụng Vite/React với HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/TEN_TAI_KHOAN/Roo-Code.git
```
-4. **Gỡ lỗi**:
- Nhấn `F5` (hoặc **Run** → **Start Debugging**) trong VSCode để mở phiên mới với Roo Code được tải.
+2. **Cài đặt phụ thuộc:**
-Các thay đổi đối với webview sẽ xuất hiện ngay lập tức. Các thay đổi đối với phần mở rộng cốt lõi sẽ yêu cầu khởi động lại máy chủ phần mở rộng.
-
-Hoặc bạn có thể xây dựng một tệp .vsix và cài đặt nó trực tiếp trong VSCode:
-
-```sh
-npm run build
```
-
-Một tệp `.vsix` sẽ xuất hiện trong thư mục `bin/` có thể được cài đặt bằng:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## Viết và Gửi Mã
-
-Bất kỳ ai cũng có thể đóng góp mã cho Roo Code, nhưng chúng tôi yêu cầu bạn tuân theo những hướng dẫn này để đảm bảo đóng góp của bạn có thể được tích hợp suôn sẻ:
-
-1. **Giữ Pull Request Tập Trung**
-
- - Giới hạn PR vào một tính năng hoặc sửa lỗi duy nhất
- - Chia các thay đổi lớn hơn thành các PR nhỏ hơn, có liên quan
- - Chia các thay đổi thành các commit hợp lý có thể được xem xét độc lập
-
-2. **Chất Lượng Mã**
+3. **Debug:** Mở bằng VS Code (`F5`).
- - Tất cả PR phải vượt qua kiểm tra CI bao gồm cả linting và định dạng
- - Giải quyết mọi cảnh báo hoặc lỗi ESLint trước khi gửi
- - Phản hồi tất cả phản hồi từ Ellipsis, công cụ đánh giá mã tự động của chúng tôi
- - Tuân theo các thực hành tốt nhất của TypeScript và duy trì an toàn kiểu
+### Hướng dẫn viết mã
-3. **Kiểm Tra**
+- Mỗi PR chỉ tập trung vào một tính năng hoặc sửa lỗi.
+- Tuân thủ các thực hành tốt nhất của ESLint và TypeScript.
+- Viết thông điệp commit rõ ràng, tham chiếu đến issue (ví dụ: `Fixes #123`).
+- Cung cấp bài kiểm tra đầy đủ (`npm test`).
+- Rebase trên nhánh `main` mới nhất trước khi gửi.
- - Thêm kiểm tra cho các tính năng mới
- - Chạy `npm test` để đảm bảo tất cả các kiểm tra đều vượt qua
- - Cập nhật các bài kiểm tra hiện có nếu thay đổi của bạn ảnh hưởng đến chúng
- - Bao gồm cả kiểm tra đơn vị và kiểm tra tích hợp khi thích hợp
+### Gửi Pull Request
-4. **Hướng Dẫn Commit**
+- Bắt đầu với **PR nháp** nếu muốn nhận phản hồi sớm.
+- Mô tả rõ ràng các thay đổi, tuân theo Mẫu Pull Request.
+- Cung cấp ảnh chụp/video cho thay đổi UI.
+- Chỉ rõ nếu cần cập nhật tài liệu.
- - Viết thông điệp commit rõ ràng, mô tả
- - Tham chiếu các vấn đề có liên quan trong commit bằng cách sử dụng #số-vấn-đề
+### Chính sách Pull Request
-5. **Trước Khi Gửi**
+- Phải tham chiếu đến issue đã được phê duyệt và gán.
+- PR không tuân thủ chính sách có thể bị đóng.
+- PR cần vượt qua kiểm tra CI, phù hợp với lộ trình và có tài liệu rõ ràng.
- - Rebase nhánh của bạn trên main mới nhất
- - Đảm bảo nhánh của bạn xây dựng thành công
- - Kiểm tra lại rằng tất cả các bài kiểm tra đều vượt qua
- - Xem xét các thay đổi của bạn cho bất kỳ mã gỡ lỗi hoặc bản ghi console nào
+### Quy trình đánh giá
-6. **Mô Tả Pull Request**
- - Mô tả rõ ràng những gì thay đổi của bạn làm
- - Bao gồm các bước để kiểm tra các thay đổi
- - Liệt kê bất kỳ thay đổi đáng kể nào
- - Thêm ảnh chụp màn hình cho các thay đổi UI
+- **Phân loại hàng ngày:** Kiểm tra nhanh bởi maintainer.
+- **Đánh giá chi tiết hàng tuần:** Đánh giá toàn diện.
+- **Lặp lại nhanh chóng** dựa trên phản hồi.
-## Thỏa Thuận Đóng Góp
+## Pháp lý
-Bằng cách gửi một pull request, bạn đồng ý rằng đóng góp của bạn sẽ được cấp phép theo cùng giấy phép với dự án ([Apache 2.0](../LICENSE)).
+Khi gửi pull request, bạn đồng ý rằng đóng góp của mình sẽ được cấp phép theo Giấy phép Apache 2.0, phù hợp với giấy phép của Roo Code.
diff --git a/locales/vi/README.md b/locales/vi/README.md
index 5a63bd65348..b9249666333 100644
--- a/locales/vi/README.md
+++ b/locales/vi/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
Cho dù bạn đang tìm kiếm một đối tác lập trình linh hoạt, một kiến trúc sư hệ thống, hay các vai trò chuyên biệt như kỹ sư QA hoặc quản lý sản phẩm, Roo Code có thể giúp bạn xây dựng phần mềm hiệu quả hơn.
-Kiểm tra [CHANGELOG](../CHANGELOG.md) để biết thông tin chi tiết về các cập nhật và sửa lỗi.
+Kiểm tra [CHANGELOG](../../CHANGELOG.md) để biết thông tin chi tiết về các cập nhật và sửa lỗi.
---
-## 🎉 Đã Phát Hành Roo Code 3.15
+## 🎉 Đã Phát Hành Roo Code 3.17
-Roo Code 3.15 mang đến những tính năng mới và cải tiến dựa trên phản hồi của bạn!
+Roo Code 3.17 mang đến những tính năng mạnh mẽ mới và cải tiến dựa trên phản hồi của bạn!
-- **Bộ nhớ đệm cho prompt trên Vertex** - Vertex AI giờ đây hỗ trợ bộ nhớ đệm prompt, cải thiện thời gian phản hồi và giảm chi phí API.
-- **Cơ chế dự phòng cho Terminal** - Đã triển khai cơ chế dự phòng khi tích hợp shell terminal VSCode thất bại, đảm bảo hoạt động terminal đáng tin cậy hơn.
-- **Cải thiện đoạn mã (code snippets)** - Nâng cao hiển thị và tương tác với đoạn mã trong giao diện trò chuyện để dễ đọc và sử dụng hơn.
+- **Bộ nhớ đệm ngầm cho Gemini** - Các cuộc gọi API Gemini hiện được tự động lưu vào bộ nhớ đệm, giảm chi phí API.
+- **Lựa chọn chế độ thông minh hơn** - Định nghĩa chế độ giờ đây có thể bao gồm hướng dẫn về thời điểm mỗi chế độ nên được sử dụng, cho phép điều phối tốt hơn.
+- **Nén ngữ cảnh thông minh** - Tóm tắt thông minh lịch sử hội thoại khi ngữ cảnh đầy thay vì cắt bớt (bật trong Cài đặt -> Thử nghiệm).
---
@@ -178,32 +178,36 @@ Chúng tôi rất hoan nghênh đóng góp từ cộng đồng! Bắt đầu b
Cảm ơn tất cả những người đóng góp đã giúp cải thiện Roo Code!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## Giấy Phép
diff --git a/locales/zh-CN/CODE_OF_CONDUCT.md b/locales/zh-CN/CODE_OF_CONDUCT.md
index 411d38865df..d37b644535a 100644
--- a/locales/zh-CN/CODE_OF_CONDUCT.md
+++ b/locales/zh-CN/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • 简体中文 • [繁體中文](../zh-TW/CODE_OF_CONDUCT.md)
+
# 贡献者契约行为准则
## 我们的承诺
diff --git a/locales/zh-CN/CONTRIBUTING.md b/locales/zh-CN/CONTRIBUTING.md
index b5c0429bd31..24e13fd9f22 100644
--- a/locales/zh-CN/CONTRIBUTING.md
+++ b/locales/zh-CN/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# 为 Roo Code 做贡献
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-我们很高兴您有兴趣为 Roo Code 做贡献。无论您是修复错误、添加功能,还是改进我们的文档,每一个贡献都让 Roo Code 变得更智能!为了保持我们的社区充满活力和欢迎,所有成员必须遵守我们的[行为准则](CODE_OF_CONDUCT.md)。
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • 简体中文 • [繁體中文](../zh-TW/CONTRIBUTING.md)
-## 加入我们的社区
+# 参与 Roo Code 贡献
-我们强烈鼓励所有贡献者加入我们的 [Discord 社区](https://discord.gg/roocode)!成为我们 Discord 服务器的一部分可以帮助您:
+Roo Code 是一个由社区驱动的项目,我们高度重视每一份贡献。为了简化协作流程,我们采用 [Issue-First](#issue-first-方式) 原则,这意味着所有 [Pull Request (PR)](#提交-pull-request) 必须首先关联到 GitHub Issue。请仔细阅读本指南。
-- 获得关于您贡献的实时帮助和指导
-- 与其他贡献者和核心团队成员建立联系
-- 了解项目发展和优先事项的最新信息
-- 参与塑造 Roo Code 未来的讨论
-- 寻找与其他开发者的合作机会
+## 目录
-## 报告错误或问题
+- [贡献前须知](#贡献前须知)
+- [寻找与规划你的贡献](#寻找与规划你的贡献)
+- [开发与提交流程](#开发与提交流程)
+- [法律声明](#法律声明)
-错误报告有助于使 Roo Code 对每个人都更好!在创建新问题之前,请[搜索现有问题](https://github.com/RooVetGit/Roo-Code/issues)以避免重复。当您准备报告错误时,前往我们的[问题页面](https://github.com/RooVetGit/Roo-Code/issues/new/choose),那里有模板可以帮助您填写相关信息。
+## 贡献前须知
-
- 🔐 重要提示:如果您发现安全漏洞,请使用 Github 安全工具私下报告它。
-
+### 1. 行为准则
-## 决定做什么
+所有贡献者必须遵守我们的[行为准则](./CODE_OF_CONDUCT.md)。
-寻找一个好的首次贡献?查看我们 [Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1) Github 项目中"Issue [Unassigned]"部分的问题。这些是专门为新贡献者精心挑选的,也是我们希望得到一些帮助的领域!
+### 2. 项目路线图
-我们也欢迎对我们的[文档](https://docs.roocode.com/)做贡献!无论是修复错别字、改进现有指南,还是创建新的教育内容 - 我们希望建立一个由社区驱动的资源库,帮助每个人充分利用 Roo Code。您可以点击任何页面上的"Edit this page"快速进入 Github 中编辑文件的正确位置,或者直接访问 https://github.com/RooVetGit/Roo-Code-Docs。
+我们的路线图指引项目方向。请将你的贡献与这些关键目标保持一致:
-如果您计划处理更大的功能,请先创建一个[功能请求](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop),以便我们讨论它是否符合 Roo Code 的愿景。您还可以查看下面的[项目路线图](#项目路线图),看看您的想法是否符合我们的战略方向。
+### 可靠性优先
-## 项目路线图
+- 确保差异编辑和命令执行始终可靠
+- 减少阻碍常规使用的摩擦点
+- 确保在所有语言环境和平台上流畅运行
+- 扩展对各种 AI 提供商和模型的强大支持
-Roo Code 有一个明确的开发路线图,指导我们的优先事项和未来方向。了解我们的路线图可以帮助您:
+### 增强用户体验
-- 使您的贡献与项目目标保持一致
-- 确定您的专业知识最有价值的领域
-- 理解某些设计决策背后的背景
-- 为支持我们愿景的新功能找到灵感
+- 简化用户界面,提高清晰度和直观性
+- 持续改进工作流程,满足开发者对日常工具的高期望
-我们当前的路线图专注于六个关键支柱:
+### 引领代理性能
-### 提供商支持
+- 建立全面的评估基准(evals)衡量实际工作中的生产力
+- 让每个人都能轻松运行和解读这些评估
+- 提供明显提升评分的改进
-我们的目标是尽可能支持更多的提供商:
+在 PR 中请提及与这些领域的关联。
-- 更加多功能的 "OpenAI Compatible" 支持
-- xAI, Microsoft Azure AI, Alibaba Cloud Qwen, IBM Watsonx, Together AI, DeepInfra, Fireworks AI, Cohere, Perplexity AI, FriendliAI, Replicate
-- 增强对 Ollama 和 LM Studio 的支持
+### 3. 加入 Roo Code 社区
-### 模型支持
+- **主要方式:** 加入我们的 [Discord](https://discord.gg/roocode) 并私信 **Hannes Rudolph (`hrudolph`)**。
+- **替代方式:** 有经验的贡献者可通过 [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1) 直接参与。
-我们希望 Roo 在尽可能多的模型上运行良好,包括本地模型:
+## 寻找与规划你的贡献
-- 通过自定义系统提示和工作流程支持本地模型
-- 基准评估和测试案例
+### 贡献类型
-### 系统支持
+- **Bug 修复:** 解决代码问题。
+- **新功能:** 添加新功能。
+- **文档:** 完善指南和提高清晰度。
-我们希望 Roo 在每个人的计算机上都能良好运行:
+### Issue-First 方式
-- 跨平台终端集成
-- 对 Mac、Windows 和 Linux 的强大一致支持
+所有贡献必须从 GitHub Issue 开始。
-### 文档
+- **检查现有 issue:** 搜索 [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues)。
+- **创建 issue:** 使用适当模板:
+ - **Bug:** "Bug Report" 模板。
+ - **功能:** "Detailed Feature Proposal" 模板。开始前需获得批准。
+- **认领 issue:** 评论并等待正式分配。
-我们希望为所有用户和贡献者提供全面、易于访问的文档:
+**未关联已批准 issue 的 PR 可能会被关闭。**
-- 扩展的用户指南和教程
-- 清晰的 API 文档
-- 更好的贡献者指导
-- 多语言文档资源
-- 交互式示例和代码示例
+### 决定要做什么
-### 稳定性
+- 查看 [GitHub 项目](https://github.com/orgs/RooVetGit/projects/1) 中未分配的 "Good First Issues"。
+- 文档相关,请访问 [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs)。
-我们希望显著减少错误数量并增加自动化测试:
+### 报告 Bug
-- 调试日志开关
-- 用于发送错误/支持请求的"机器/任务信息"复制按钮
+- 先检查是否已有相关报告。
+- 使用 ["Bug Report" 模板](https://github.com/RooVetGit/Roo-Code/issues/new/choose) 创建新 bug 报告。
+- **安全问题:** 通过 [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new) 私下报告。
-### 国际化
+## 开发与提交流程
-我们希望 Roo 能说每个人的语言:
+### 开发环境配置
-- 我们希望 Roo Code 说每个人的语言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-我们特别欢迎推进我们路线图目标的贡献。如果您正在处理符合这些支柱的内容,请在您的 PR 描述中提及。
-
-## 开发设置
-
-1. **克隆**仓库:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **安装依赖**:
-
-```sh
-npm run install:all
-```
-
-3. **启动 webview(Vite/React 应用,具有热模块替换)**:
-
-```sh
-npm run dev
+git clone https://github.com/你的用户名/Roo-Code.git
```
-4. **调试**:
- 在 VSCode 中按 `F5`(或**运行** → **开始调试**)打开一个加载了 Roo Code 的新会话。
+2. **安装依赖:**
-对 webview 的更改将立即显示。对核心扩展的更改将需要重新启动扩展主机。
-
-或者,您可以构建一个 .vsix 文件并直接在 VSCode 中安装:
-
-```sh
-npm run build
```
-
-`bin/` 目录中将出现一个 `.vsix` 文件,可以用以下命令安装:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## 编写和提交代码
-
-任何人都可以为 Roo Code 贡献代码,但我们要求您遵循这些指导方针,以确保您的贡献能够顺利集成:
-
-1. **保持 Pull Requests 聚焦**
-
- - 将 PR 限制在单一功能或错误修复
- - 将较大的更改分割成更小的相关 PR
- - 将更改分解为可以独立审查的逻辑提交
-
-2. **代码质量**
+3. **调试:** 在 VS Code 中按 `F5` 打开。
- - 所有 PR 必须通过包括 linting 和格式化的 CI 检查
- - 在提交之前解决任何 ESLint 警告或错误
- - 回应 Ellipsis(我们的自动代码审查工具)的所有反馈
- - 遵循 TypeScript 最佳实践并保持类型安全
+### 编码规范
-3. **测试**
+- 每个 PR 专注于一个功能或修复。
+- 遵循 ESLint 和 TypeScript 最佳实践。
+- 编写清晰的提交信息,引用相关 issue(如 `Fixes #123`)。
+- 提供完整测试(`npm test`)。
+- 提交前先在最新 `main` 分支上进行 rebase。
- - 为新功能添加测试
- - 运行 `npm test` 确保所有测试通过
- - 如果您的更改影响现有测试,请更新它们
- - 在适当的情况下包括单元测试和集成测试
+### 提交 Pull Request
-4. **提交指南**
+- 如需早期反馈,可先提交**草稿 PR**。
+- 清晰描述你的更改,遵循 Pull Request 模板。
+- 为 UI 变更提供截图/视频。
+- 说明是否需要更新文档。
- - 编写清晰、描述性的提交消息
- - 在提交中使用 #issue-number 引用相关问题
+### Pull Request 政策
-5. **提交前**
+- 必须引用已批准并分配的 issue。
+- 不遵守政策的 PR 可能会被关闭。
+- PR 应通过 CI 测试,符合路线图,并有清晰文档。
- - 在最新的 main 分支上变基您的分支
- - 确保您的分支成功构建
- - 再次检查所有测试是否通过
- - 检查您的更改中是否有任何调试代码或控制台日志
+### 审查流程
-6. **Pull Request 描述**
- - 清晰描述您的更改做了什么
- - 包括测试更改的步骤
- - 列出任何破坏性更改
- - 为 UI 更改添加截图
+- **每日筛查:** 维护者快速检查。
+- **每周深入审查:** 全面评估。
+- **根据反馈快速迭代**。
-## 贡献协议
+## 法律声明
-通过提交 pull request,您同意您的贡献将在与项目相同的许可下获得许可([Apache 2.0](../LICENSE))。
+提交贡献即表示你同意你的贡献将基于 Apache 2.0 许可证,与 Roo Code 的许可一致。
diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md
index 98e29ac8102..deeb6e189d2 100644
--- a/locales/zh-CN/README.md
+++ b/locales/zh-CN/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -43,17 +43,17 @@
无论您是寻找灵活的编码伙伴、系统架构师,还是像 QA 工程师或产品经理这样的专业角色,Roo Code 都可以帮助您更高效地构建软件。
-查看 [CHANGELOG](../CHANGELOG.md) 获取详细更新和修复信息。
+查看 [CHANGELOG](../../CHANGELOG.md) 获取详细更新和修复信息。
---
-## 🎉 Roo Code 3.15 已发布
+## 🎉 Roo Code 3.17 已发布
-Roo Code 3.15 基于您的反馈带来新功能和改进!
+Roo Code 3.17 基于您的反馈带来强大的新功能和改进!
-- **Vertex 提示词缓存** - Vertex AI 现已支持提示词缓存,改善响应时间并降低 API 费用。
-- **终端回退机制** - 实现了 VSCode 终端 shell 集成失败时的回退机制,确保更可靠的终端操作。
-- **代码片段优化** - 增强了聊天界面中代码片段的渲染和交互,提高了可读性和易用性。
+- **Gemini 隐式缓存** - Gemini API 调用现在会自动缓存,降低 API 成本。
+- **更智能的模式选择** - 模式定义现在可以包含何时应使用各模式的指导,实现更好的编排。
+- **智能上下文压缩** - 当上下文填满时,智能摘要对话历史而非简单截断(在"设置 -> 实验性"中启用)。
---
@@ -178,32 +178,36 @@ code --install-extension bin/roo-cline-.vsix
感谢所有帮助改进 Roo Code 的贡献者!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## 许可证
diff --git a/locales/zh-TW/CODE_OF_CONDUCT.md b/locales/zh-TW/CODE_OF_CONDUCT.md
index b83928b01b7..1a01171ad03 100644
--- a/locales/zh-TW/CODE_OF_CONDUCT.md
+++ b/locales/zh-TW/CODE_OF_CONDUCT.md
@@ -1,3 +1,7 @@
+[English](../../CODE_OF_CONDUCT.md) • [Català](../ca/CODE_OF_CONDUCT.md) • [Deutsch](../de/CODE_OF_CONDUCT.md) • [Español](../es/CODE_OF_CONDUCT.md) • [Français](../fr/CODE_OF_CONDUCT.md) • [हिंदी](../hi/CODE_OF_CONDUCT.md) • [Italiano](../it/CODE_OF_CONDUCT.md) • [Nederlands](../nl/CODE_OF_CONDUCT.md) • [Русский](../ru/CODE_OF_CONDUCT.md)
+
+[日本語](../ja/CODE_OF_CONDUCT.md) • [한국어](../ko/CODE_OF_CONDUCT.md) • [Polski](../pl/CODE_OF_CONDUCT.md) • [Português (BR)](../pt-BR/CODE_OF_CONDUCT.md) • [Türkçe](../tr/CODE_OF_CONDUCT.md) • [Tiếng Việt](../vi/CODE_OF_CONDUCT.md) • [简体中文](../zh-CN/CODE_OF_CONDUCT.md) • 繁體中文
+
# 貢獻者公約行為準則
## 我們的承諾
diff --git a/locales/zh-TW/CONTRIBUTING.md b/locales/zh-TW/CONTRIBUTING.md
index d42ea003e5a..e676900abfe 100644
--- a/locales/zh-TW/CONTRIBUTING.md
+++ b/locales/zh-TW/CONTRIBUTING.md
@@ -1,173 +1,129 @@
-# 參與貢獻 Roo Code
+[English](../../CONTRIBUTING.md) • [Català](../ca/CONTRIBUTING.md) • [Deutsch](../de/CONTRIBUTING.md) • [Español](../es/CONTRIBUTING.md) • [Français](../fr/CONTRIBUTING.md) • [हिंदी](../hi/CONTRIBUTING.md) • [Italiano](../it/CONTRIBUTING.md) • [Nederlands](../nl/CONTRIBUTING.md) • [Русский](../ru/CONTRIBUTING.md)
-我們非常歡迎您參與貢獻 Roo Code。無論是修正錯誤、新增功能或改善文件,每一份貢獻都能讓 Roo Code 變得更加出色!為了維持社群的活力與友善氛圍,所有成員皆須遵守我們的[行為準則](CODE_OF_CONDUCT.md)。
+[日本語](../ja/CONTRIBUTING.md) • [한국어](../ko/CONTRIBUTING.md) • [Polski](../pl/CONTRIBUTING.md) • [Português (BR)](../pt-BR/CONTRIBUTING.md) • [Türkçe](../tr/CONTRIBUTING.md) • [Tiếng Việt](../vi/CONTRIBUTING.md) • [简体中文](../zh-CN/CONTRIBUTING.md) • 繁體中文
-## 加入我們的社群
+# 參與 Roo Code 貢獻
-我們強烈建議所有貢獻者加入我們的 [Discord 社群](https://discord.gg/roocode)!加入 Discord 伺服器後,您可以:
+Roo Code 是一個由社群驅動的專案,我們深深重視每一份貢獻。為了簡化協作流程,我們採用 [Issue-First](#issue-first-方式) 原則,這表示所有 [Pull Request (PR)](#提交-pull-request) 必須先關聯至 GitHub Issue。請仔細閱讀本指南。
-- 即時取得貢獻相關的協助與指引
-- 與其他貢獻者及核心團隊成員交流
-- 掌握專案的最新進展與優先事項
-- 參與討論,共同塑造 Roo Code 的未來
-- 尋找與其他開發者合作的機會
+## 目錄
-## 回報錯誤或問題
+- [貢獻前須知](#貢獻前須知)
+- [尋找與規劃你的貢獻](#尋找與規劃你的貢獻)
+- [開發與提交流程](#開發與提交流程)
+- [法律聲明](#法律聲明)
-回報錯誤能幫助我們改善 Roo Code!在建立新議題前,請先[搜尋現有議題](https://github.com/RooVetGit/Roo-Code/issues),避免重複回報。當您準備好回報錯誤時,請前往我們的 [議題頁面](https://github.com/RooVetGit/Roo-Code/issues/new/choose),您將找到協助填寫相關資訊的範本。
+## 貢獻前須知
-
- 🔐 重要: 若您發現安全性漏洞,請透過 GitHub 安全性通報工具進行私密回報。
-
+### 1. 行為準則
-## 決定貢獻方向
+所有貢獻者必須遵守我們的[行為準則](./CODE_OF_CONDUCT.md)。
-正在尋找適合新手的貢獻機會嗎?請查看我們 [Roo Code Issues](https://github.com/orgs/RooVetGit/projects/1) GitHub 專案中的「Issue [Unassigned]」區塊。這些議題特別適合新進貢獻者,也是我們最需要協助的領域!
+### 2. 專案藍圖
-我們也歡迎您對[文件](https://docs.roocode.com/)提出貢獻!無論是修正錯字、改善現有指南,或建立新的教學內容,我們都希望打造一個由社群推動的知識庫,協助每個人充分運用 Roo Code。您可以點選任何頁面上的「編輯此頁面」按鈕,快速前往 GitHub 上的檔案編輯介面,或直接造訪 https://github.com/RooVetGit/Roo-Code-Docs。
+我們的藍圖指引專案方向。請將你的貢獻與這些關鍵目標保持一致:
-若您計畫開發較大型的功能,請先建立一個[功能請求](https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop),讓我們能討論該功能是否符合 Roo Code 的願景。您也可以參考下方的[專案藍圖](#專案藍圖),確認您的想法是否符合我們的策略方向。
+### 可靠性優先
-## 專案藍圖
+- 確保差異編輯和命令執行始終可靠
+- 減少阻礙常規使用的摩擦點
+- 確保在所有語言環境和平台上順暢運行
+- 擴展對各種 AI 供應商和模型的強大支援
-Roo Code 擁有明確的開發藍圖,指引我們的優先事項與未來方向。了解我們的藍圖能協助您:
+### 增強使用者體驗
-- 讓您的貢獻與專案目標保持一致
-- 找到最能發揮您專長的領域
-- 理解特定設計決策的脈絡
-- 為支援我們願景的新功能尋找靈感
+- 簡化使用者介面,提高清晰度和直覺性
+- 持續改進工作流程,滿足開發者對日常工具的高期望
-目前的藍圖聚焦於六大核心支柱:
+### 引領代理效能
-### 供應商支援
+- 建立全面的評估基準(evals)衡量實際工作中的生產力
+- 讓每個人都能輕鬆執行和解讀這些評估
+- 提供明顯提升評分的改進
-我們致力於完善各家供應商的支援:
+在 PR 中請提及與這些領域的關聯。
-- 對於「OpenAI 相容」API 的更全面支援
-- xAI、Microsoft Azure AI、Alibaba Cloud Qwen、IBM Watsonx、Together AI、DeepInfra、Fireworks AI、Cohere、Perplexity AI、FriendliAI、Replicate
-- 強化對 Ollama 與 LM Studio 的支援
+### 3. 加入 Roo Code 社群
-### 模型支援
+- **主要方式:** 加入我們的 [Discord](https://discord.gg/roocode) 並私訊 **Hannes Rudolph (`hrudolph`)**。
+- **替代方式:** 有經驗的貢獻者可透過 [GitHub Projects](https://github.com/orgs/RooVetGit/projects/1) 直接參與。
-我們希望 Roo 能在更多模型上順暢運作,包括本機模型:
+## 尋找與規劃你的貢獻
-- 透過自訂系統提示與工作流程支援本機模型
-- 基準測試評估與測試案例
+### 貢獻類型
-### 系統支援
+- **Bug 修正:** 解決程式碼問題。
+- **新功能:** 新增功能。
+- **文件:** 完善指南和提高清晰度。
-我們希望 Roo 能在每個人的電腦上順暢運作:
+### Issue-First 方式
-- 跨平台終端機整合
-- 為 Mac、Windows 與 Linux 提供穩定且一致的支援
+所有貢獻必須從 GitHub Issue 開始。
-### 文件
+- **檢查現有 issue:** 搜尋 [GitHub Issues](https://github.com/RooVetGit/Roo-Code/issues)。
+- **建立 issue:** 使用適當範本:
+ - **Bug:** 「Bug Report」範本。
+ - **功能:** 「Detailed Feature Proposal」範本。開始前需獲得批准。
+- **認領 issue:** 留言並等待正式分配。
-我們希望為所有使用者與貢獻者提供完整且易於取得的文件:
+**未關聯已批准 issue 的 PR 可能會被關閉。**
-- 擴充使用者指南與教學
-- 清晰的 API 文件
-- 更完善的貢獻者指引
-- 多語言文件資源
-- 互動式範例與程式碼範例
+### 決定要做什麼
-### 穩定性
+- 查看 [GitHub 專案](https://github.com/orgs/RooVetGit/projects/1) 中未分配的「Good First Issues」。
+- 文件相關,請訪問 [Roo Code Docs](https://github.com/RooVetGit/Roo-Code-Docs)。
-我們希望顯著降低錯誤數量並增加自動化測試:
+### 回報 Bug
-- 除錯記錄開關
-- 用於傳送錯誤/支援請求的「機器/工作資訊」複製按鈕
+- 先檢查是否已有相關報告。
+- 使用 [「Bug Report」範本](https://github.com/RooVetGit/Roo-Code/issues/new/choose) 建立新 bug 報告。
+- **安全問題:** 透過 [security advisories](https://github.com/RooVetGit/Roo-Code/security/advisories/new) 私下回報。
-### 國際化
+## 開發與提交流程
-我們希望 Roo 能說每個人的語言:
+### 開發環境設定
-- 我們希望 Roo Code 說每個人的語言
-- Queremos que Roo Code hable el idioma de todos
-- हम चाहते हैं कि Roo Code हर किसी की भाषा बोले
-- نريد أن يتحدث Roo Code لغة الجميع
+1. **Fork & Clone:**
-我們特別歡迎推動藍圖目標的貢獻。如果您的貢獻符合這些核心支柱,請在 PR 描述中提及。
-
-## 開發環境設定
-
-1. **複製**儲存庫:
-
-```sh
-git clone https://github.com/RooVetGit/Roo-Code.git
```
-
-2. **安裝相依套件**:
-
-```sh
-npm run install:all
-```
-
-3. **啟動網頁檢視(Vite/React 應用程式,支援 HMR)**:
-
-```sh
-npm run dev
+git clone https://github.com/你的帳號/Roo-Code.git
```
-4. **除錯**:
- 在 VSCode 中按下 `F5`(或選擇**執行** → **開始除錯**)以開啟載入 Roo Code 的新工作階段。
+2. **安裝相依套件:**
-網頁檢視的變更會立即顯示。核心擴充功能的變更則需要重新啟動擴充主機。
-
-或者,您也可以建置 .vsix 檔案並直接在 VSCode 中安裝:
-
-```sh
-npm run build
```
-
-建置完成後,`.vsix` 檔案會出現在 `bin/` 目錄中,可使用以下指令安裝:
-
-```sh
-code --install-extension bin/roo-cline-.vsix
+npm run install:all
```
-## 撰寫與提交程式碼
-
-任何人都能為 Roo Code 貢獻程式碼,但請遵守以下準則,確保您的貢獻能順利整合:
-
-1. **保持 Pull Request 聚焦**
-
- - 每個 PR 限制在單一功能或錯誤修正
- - 將較大的變更拆分成較小且相關的 PR
- - 將變更拆分成可獨立審查的邏輯提交
-
-2. **程式碼品質**
+3. **除錯:** 在 VS Code 中按 `F5` 開啟。
- - 所有 PR 必須通過包含程式碼檢查與格式化的 CI 檢查
- - 提交前解決所有 ESLint 警告或錯誤
- - 回應 Ellipsis(我們的自動化程式碼審查工具)的所有建議
- - 遵循 TypeScript 最佳實務並維持型別安全
+### 程式碼規範
-3. **測試**
+- 每個 PR 專注於一個功能或修正。
+- 遵循 ESLint 和 TypeScript 最佳實踐。
+- 撰寫清晰的提交訊息,引用相關 issue(如 `Fixes #123`)。
+- 提供完整測試(`npm test`)。
+- 提交前先在最新 `main` 分支上進行 rebase。
- - 為新功能新增測試
- - 執行 `npm test` 確保所有測試通過
- - 如果變更影響現有測試,請更新測試
- - 在適當情況下包含單元測試和整合測試
+### 提交 Pull Request
-4. **提交準則**
+- 如需早期回饋,可先提交**草稿 PR**。
+- 清晰描述你的更改,遵循 Pull Request 範本。
+- 為 UI 變更提供截圖/影片。
+- 說明是否需要更新文件。
- - 撰寫清晰、具描述性的提交訊息
- - 使用 #issue-number 在提交中引用相關議題
+### Pull Request 政策
-5. **提交前**
+- 必須引用已批准並分配的 issue。
+- 不遵守政策的 PR 可能會被關閉。
+- PR 應通過 CI 測試,符合藍圖,並有清晰文件。
- - 將您的分支重新基於最新的 main
- - 確保您的分支能成功建置
- - 再次檢查所有測試是否通過
- - 檢查您的變更中是否有任何除錯程式碼或主控台記錄
+### 審查流程
-6. **PR 描述**
- - 清楚描述您的變更內容
- - 包含測試變更的步驟
- - 列出任何重大變更
- - 為使用者介面變更附上截圖
+- **每日篩查:** 維護者快速檢查。
+- **每週深入審查:** 全面評估。
+- **根據回饋快速迭代**。
-## 貢獻協議
+## 法律聲明
-透過提交 Pull Request,您同意您的貢獻將依照與專案相同的授權條款([Apache 2.0](../LICENSE))進行授權。
+提交貢獻即表示你同意你的貢獻將基於 Apache 2.0 授權條款,與 Roo Code 的授權一致。
diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md
index 91151e07638..7ad8d5d1c1c 100644
--- a/locales/zh-TW/README.md
+++ b/locales/zh-TW/README.md
@@ -1,7 +1,7 @@
-[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Русский](../../locales/ru/README.md)
+[English](../../README.md) • [Català](../../locales/ca/README.md) • [Deutsch](../../locales/de/README.md) • [Español](../../locales/es/README.md) • [Français](../../locales/fr/README.md) • [हिन्दी](../../locales/hi/README.md) • [Italiano](../../locales/it/README.md) • [Nederlands](../../locales/nl/README.md) • [Русский](../../locales/ru/README.md)
@@ -44,17 +44,17 @@
無論您需要的是一位靈活的程式設計夥伴、系統架構師,或是 QA 工程師、產品經理等特定角色,Roo Code 都能協助您更有效率地開發軟體。
-請檢視 [CHANGELOG](../CHANGELOG.md) 了解詳細的更新與修正內容。
+請檢視 [CHANGELOG](../../CHANGELOG.md) 了解詳細的更新與修正內容。
---
-## 🎉 Roo Code 3.15 已發布
+## 🎉 Roo Code 3.17 已發布
-Roo Code 3.15 根據您的回饋帶來新功能和改進!
+Roo Code 3.17 根據您的回饋帶來強大的新功能和改進!
-- **Vertex 提示詞快取** - Vertex AI 現已支援提示詞快取,改善回應時間並降低 API 成本。
-- **終端機備用機制** - 實作了 VSCode 終端機 shell 整合失敗時的備用機制,確保更可靠的終端機操作。
-- **程式碼片段優化** - 增強了聊天介面中程式碼片段的渲染和互動,提高了可讀性和易用性。
+- **Gemini 的隱式快取** - Gemini API 呼叫現在會自動快取,降低 API 成本。
+- **更智慧的模式選擇** - 模式定義現在可以包含何時應使用各模式的指引,實現更好的協調運作。
+- **智慧型上下文壓縮** - 當上下文填滿時,智慧地摘要對話歷史而非簡單截斷(在「設定 -> 實驗性」中啟用)。
---
@@ -179,32 +179,36 @@ code --install-extension bin/roo-cline-.vsix
感謝所有幫助改進 Roo Code 的貢獻者!
-|
mrubens|
saoudrizwan|
cte|
samhvw8|
daniel-lxs|
a8trejo|
-|:---:|:---:|:---:|:---:|:---:|:---:|
-|
ColemanRoo|
stea9499|
joemanley201|
System233|
hannesrudolph|
KJ7LNW|
-|
nissa-seru|
jquanton|
NyxJae|
MuriloFP|
d-oit|
punkpeye|
-|
Smartsheet-JB-Brown|
monotykamary|
wkordalski|
feifei325|
lloydchang|
cannuri|
-|
vigneshsubbiah16|
Szpadel|
sachasayan|
qdaxb|
zhangtony239|
lupuletic|
-|
Premshay|
psv2522|
elianiva|
diarmidmackenzie|
olweraltuve|
afshawnlotfi|
-|
pugazhendhi-m|
aheizi|
RaySinner|
PeterDaveHello|
nbihan-mediware|
dtrugman|
-|
emshvac|
kyle-apex|
pdecat|
Lunchb0ne|
arthurauffray|
upamune|
-|
StevenTCramer|
sammcj|
p12tic|
gtaylor|
aitoroses|
anton-otee|
-|
philfung|
ross|
heyseth|
taisukeoe|
eonghk|
teddyOOXX|
-|
vagadiya|
vincentsong|
yongjer|
ashktn|
franekp|
yt3trees|
-|
benzntech|
axkirillov|
bramburn|
snoyiatk|
GitlyHallows|
jcbdev|
-|
Chenjiayuan195|
jr|
julionav|
SplittyDev|
mdp|
napter|
-|
nevermorec|
mecab|
olup|
lightrabbit|
kohii|
kinandan|
-|
jwcraig|
shoopapa|
im47cn|
hongzio|
GOODBOY008|
dqroid|
-|
dlab-anton|
dairui1|
bannzai|
axmo|
asychin|
PretzelVector|
-|
cdlliuy|
student20880|
shohei-ihaya|
shaybc|
shariqriazz|
seedlord|
-|
samir-nimbly|
ronyblum|
refactorthis|
pokutuna|
philipnext|
oprstchn|
-|
nobu007|
mosleyit|
moqimoqidea|
mlopezr|
Jdo300|
hesara|
-|
DeXtroTip|
celestial-vault|
linegel|
dbasclpy|
dleen|
chadgauth|
-|
olearycrew|
bogdan0083|
Atlogit|
atlasgong|
andreastempsch|
QuinsZouls|
-|
alarno|
adamwlarson|
AMHesch|
amittell|
Yoshino-Yukitaro|
Yikai-Liao|
-|
vladstudio|
NamesMT|
tmsjngx0|
tgfjt|
maekawataiki|
samsilveira|
-|
mr-ryan-james|
01Rian|
Sarke|
kvokka|
marvijo-code|
mamertofabian|
-|
libertyteeth|
shtse8| | | | |
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
hannesrudolph | 
KJ7LNW | 
stea9499 | 
joemanley201 | 
System233 |
+| 
nissa-seru | 
jquanton | 
NyxJae | 
MuriloFP | 
d-oit | 
punkpeye |
+| 
wkordalski | 
Smartsheet-JB-Brown | 
monotykamary | 
elianiva | 
cannuri | 
feifei325 |
+| 
zhangtony239 | 
sachasayan | 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
qdaxb |
+| 
lupuletic | 
Premshay | 
psv2522 | 
diarmidmackenzie | 
aheizi | 
olweraltuve |
+| 
jr | 
dtrugman | 
nbihan-mediware | 
PeterDaveHello | 
RaySinner | 
pugazhendhi-m |
+| 
afshawnlotfi | 
shariqriazz | 
pdecat | 
kyle-apex | 
emshvac | 
Lunchb0ne |
+| 
xyOz-dev | 
arthurauffray | 
upamune | 
StevenTCramer | 
sammcj | 
p12tic |
+| 
gtaylor | 
aitoroses | 
benzntech | 
ross | 
heyseth | 
taisukeoe |
+| 
dlab-anton | 
eonghk | 
teddyOOXX | 
vagadiya | 
vincentsong | 
yongjer |
+| 
ashktn | 
franekp | 
yt3trees | 
anton-otee | 
axkirillov | 
bramburn |
+| 
snoyiatk | 
GitlyHallows | 
jcbdev | 
Chenjiayuan195 | 
julionav | 
SplittyDev |
+| 
mdp | 
napter | 
philfung | 
im47cn | 
shoopapa | 
jwcraig |
+| 
kinandan | 
kohii | 
lightrabbit | 
olup | 
mecab | 
nevermorec |
+| 
hongzio | 
GOODBOY008 | 
dqroid | 
dairui1 | 
bannzai | 
axmo |
+| 
asychin | 
amittell | 
Yoshino-Yukitaro | 
Yikai-Liao | 
SmartManoj | 
PretzelVector |
+| 
zetaloop | 
cdlliuy | 
student20880 | 
shohei-ihaya | 
shaybc | 
seedlord |
+| 
samir-nimbly | 
ronyblum | 
robertheadley | 
refactorthis | 
pokutuna | 
philipnext |
+| 
oprstchn | 
nobu007 | 
mosleyit | 
moqimoqidea | 
mlopezr | 
zxdvd |
+| 
DeXtroTip | 
pfitz | 
celestial-vault | 
linegel | 
dbasclpy | 
Deon588 |
+| 
dleen | 
chadgauth | 
olearycrew | 
bogdan0083 | 
Atlogit | 
atlasgong |
+| 
andreastempsch | 
alasano | 
QuinsZouls | 
HadesArchitect | 
alarno | 
adamwlarson |
+| 
AMHesch | 
vladstudio | 
NamesMT | 
tmsjngx0 | 
tgfjt | 
maekawataiki |
+| 
samsilveira | 
mr-ryan-james | 
01Rian | 
Sarke | 
kvokka | 
ecmasx |
+| 
marvijo-code | 
mamertofabian | 
monkeyDluffy6017 | 
libertyteeth | 
shtse8 | 
ksze |
+| 
Jdo300 | 
hesara | | | | |
+
## 授權
diff --git a/package-lock.json b/package-lock.json
index 526bae528ac..2d36ceb4bdf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,20 +1,20 @@
{
"name": "pearai-roo-cline",
- "version": "3.15.3",
+ "version": "3.17.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pearai-roo-cline",
- "version": "3.15.3",
+ "version": "3.17.2",
"dependencies": {
"@anthropic-ai/bedrock-sdk": "^0.10.2",
"@anthropic-ai/sdk": "^0.37.0",
"@anthropic-ai/vertex-sdk": "^0.7.0",
"@aws-sdk/client-bedrock-runtime": "^3.779.0",
- "@google/genai": "^0.9.0",
+ "@google/genai": "^0.13.0",
"@mistralai/mistralai": "^1.3.6",
- "@modelcontextprotocol/sdk": "^1.7.0",
+ "@modelcontextprotocol/sdk": "^1.9.0",
"@pearai/core": "file:./../pearai-submodule/core",
"@types/clone-deep": "^4.0.4",
"@types/pdf-parse": "^1.1.4",
@@ -53,6 +53,7 @@
"puppeteer-core": "^23.4.0",
"react-tooltip": "^5.28.0",
"reconnecting-eventsource": "^1.6.4",
+ "sanitize-filename": "^1.6.3",
"say": "^0.16.0",
"serialize-error": "^11.0.3",
"simple-git": "^3.27.0",
@@ -67,7 +68,7 @@
"vscode-material-icons": "^0.1.1",
"web-tree-sitter": "^0.22.6",
"workerpool": "^9.2.0",
- "zod": "^3.23.8"
+ "zod": "^3.24.2"
},
"devDependencies": {
"@changesets/cli": "^2.27.10",
@@ -87,8 +88,8 @@
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.11.0",
"@vscode/test-electron": "^2.5.2",
- "@vscode/vsce": "^3.3.2",
- "esbuild": "^0.24.0",
+ "@vscode/vsce": "3.3.2",
+ "esbuild": "^0.25.0",
"eslint": "^8.57.0",
"execa": "^9.5.2",
"glob": "^11.0.1",
@@ -99,13 +100,15 @@
"lint-staged": "^15.2.11",
"mkdirp": "^3.0.1",
"nock": "^14.0.4",
- "npm-run-all": "^4.1.5",
+ "npm-run-all2": "^8.0.1",
+ "ovsx": "0.10.2",
"prettier": "^3.4.2",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.5",
"tsup": "^8.4.0",
"tsx": "^4.19.3",
- "typescript": "^5.4.5",
+ "typescript": "5.8.3",
+ "vitest": "^3.1.3",
"zod-to-ts": "^1.2.0"
},
"engines": {
@@ -449,26 +452,28 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime": {
- "version": "3.779.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.779.0.tgz",
- "integrity": "sha512-MyzZks8XxWwdsA4VlyPW4IekUjpgDI91VwMvEtOITHD8w+9nTGJtD32HcCKNQQCHWYfSoOj7yIoHRisVatR8yw==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.808.0.tgz",
+ "integrity": "sha512-OzjqAlevqurwAPiBGO++90pvpJCyjK6UrQH2av7oTwAwWYpY/wqVCGjch/pkme6G2+o76FjPvUKxfEcBu+5pKQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/credential-provider-node": "3.777.0",
- "@aws-sdk/middleware-host-header": "3.775.0",
- "@aws-sdk/middleware-logger": "3.775.0",
- "@aws-sdk/middleware-recursion-detection": "3.775.0",
- "@aws-sdk/middleware-user-agent": "3.775.0",
- "@aws-sdk/region-config-resolver": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@aws-sdk/util-endpoints": "3.775.0",
- "@aws-sdk/util-user-agent-browser": "3.775.0",
- "@aws-sdk/util-user-agent-node": "3.775.0",
- "@smithy/config-resolver": "^4.1.0",
- "@smithy/core": "^3.2.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/credential-provider-node": "3.808.0",
+ "@aws-sdk/eventstream-handler-node": "3.804.0",
+ "@aws-sdk/middleware-eventstream": "3.804.0",
+ "@aws-sdk/middleware-host-header": "3.804.0",
+ "@aws-sdk/middleware-logger": "3.804.0",
+ "@aws-sdk/middleware-recursion-detection": "3.804.0",
+ "@aws-sdk/middleware-user-agent": "3.808.0",
+ "@aws-sdk/region-config-resolver": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@aws-sdk/util-endpoints": "3.808.0",
+ "@aws-sdk/util-user-agent-browser": "3.804.0",
+ "@aws-sdk/util-user-agent-node": "3.808.0",
+ "@smithy/config-resolver": "^4.1.2",
+ "@smithy/core": "^3.3.1",
"@smithy/eventstream-serde-browser": "^4.0.2",
"@smithy/eventstream-serde-config-resolver": "^4.1.0",
"@smithy/eventstream-serde-node": "^4.0.2",
@@ -476,24 +481,24 @@
"@smithy/hash-node": "^4.0.2",
"@smithy/invalid-dependency": "^4.0.2",
"@smithy/middleware-content-length": "^4.0.2",
- "@smithy/middleware-endpoint": "^4.1.0",
- "@smithy/middleware-retry": "^4.1.0",
+ "@smithy/middleware-endpoint": "^4.1.4",
+ "@smithy/middleware-retry": "^4.1.5",
"@smithy/middleware-serde": "^4.0.3",
"@smithy/middleware-stack": "^4.0.2",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/node-http-handler": "^4.0.4",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
"@smithy/util-base64": "^4.0.0",
"@smithy/util-body-length-browser": "^4.0.0",
"@smithy/util-body-length-node": "^4.0.0",
- "@smithy/util-defaults-mode-browser": "^4.0.8",
- "@smithy/util-defaults-mode-node": "^4.0.8",
- "@smithy/util-endpoints": "^3.0.2",
+ "@smithy/util-defaults-mode-browser": "^4.0.12",
+ "@smithy/util-defaults-mode-node": "^4.0.12",
+ "@smithy/util-endpoints": "^3.0.4",
"@smithy/util-middleware": "^4.0.2",
- "@smithy/util-retry": "^4.0.2",
+ "@smithy/util-retry": "^4.0.3",
"@smithy/util-stream": "^4.2.0",
"@smithy/util-utf8": "^4.0.0",
"@types/uuid": "^9.0.1",
@@ -508,6 +513,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
"integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
+ "license": "Apache-2.0",
"dependencies": {
"@aws-crypto/util": "^5.2.0",
"@aws-sdk/types": "^3.222.0",
@@ -521,16 +527,30 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz",
"integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==",
+ "license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.222.0",
"@smithy/util-utf8": "^2.0.0",
"tslib": "^2.6.2"
}
},
+ "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
+ "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz",
"integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==",
+ "license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^2.2.0",
"tslib": "^2.6.2"
@@ -543,6 +563,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
+ "license": "Apache-2.0",
"dependencies": {
"@smithy/util-buffer-from": "^2.2.0",
"tslib": "^2.6.2"
@@ -552,47 +573,47 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sso": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.777.0.tgz",
- "integrity": "sha512-0+z6CiAYIQa7s6FJ+dpBYPi9zr9yY5jBg/4/FGcwYbmqWPXwL9Thdtr0FearYRZgKl7bhL3m3dILCCfWqr3teQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.808.0.tgz",
+ "integrity": "sha512-NxGomD0x9q30LPOXf4x7haOm6l2BJdLEzpiC/bPEXUkf2+4XudMQumMA/hDfErY5hCE19mFAouoO465m3Gl3JQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/middleware-host-header": "3.775.0",
- "@aws-sdk/middleware-logger": "3.775.0",
- "@aws-sdk/middleware-recursion-detection": "3.775.0",
- "@aws-sdk/middleware-user-agent": "3.775.0",
- "@aws-sdk/region-config-resolver": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@aws-sdk/util-endpoints": "3.775.0",
- "@aws-sdk/util-user-agent-browser": "3.775.0",
- "@aws-sdk/util-user-agent-node": "3.775.0",
- "@smithy/config-resolver": "^4.1.0",
- "@smithy/core": "^3.2.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/middleware-host-header": "3.804.0",
+ "@aws-sdk/middleware-logger": "3.804.0",
+ "@aws-sdk/middleware-recursion-detection": "3.804.0",
+ "@aws-sdk/middleware-user-agent": "3.808.0",
+ "@aws-sdk/region-config-resolver": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@aws-sdk/util-endpoints": "3.808.0",
+ "@aws-sdk/util-user-agent-browser": "3.804.0",
+ "@aws-sdk/util-user-agent-node": "3.808.0",
+ "@smithy/config-resolver": "^4.1.2",
+ "@smithy/core": "^3.3.1",
"@smithy/fetch-http-handler": "^5.0.2",
"@smithy/hash-node": "^4.0.2",
"@smithy/invalid-dependency": "^4.0.2",
"@smithy/middleware-content-length": "^4.0.2",
- "@smithy/middleware-endpoint": "^4.1.0",
- "@smithy/middleware-retry": "^4.1.0",
+ "@smithy/middleware-endpoint": "^4.1.4",
+ "@smithy/middleware-retry": "^4.1.5",
"@smithy/middleware-serde": "^4.0.3",
"@smithy/middleware-stack": "^4.0.2",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/node-http-handler": "^4.0.4",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
"@smithy/util-base64": "^4.0.0",
"@smithy/util-body-length-browser": "^4.0.0",
"@smithy/util-body-length-node": "^4.0.0",
- "@smithy/util-defaults-mode-browser": "^4.0.8",
- "@smithy/util-defaults-mode-node": "^4.0.8",
- "@smithy/util-endpoints": "^3.0.2",
+ "@smithy/util-defaults-mode-browser": "^4.0.12",
+ "@smithy/util-defaults-mode-node": "^4.0.12",
+ "@smithy/util-endpoints": "^3.0.4",
"@smithy/util-middleware": "^4.0.2",
- "@smithy/util-retry": "^4.0.2",
+ "@smithy/util-retry": "^4.0.3",
"@smithy/util-utf8": "^4.0.0",
"tslib": "^2.6.2"
},
@@ -601,18 +622,18 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/core": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz",
- "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.808.0.tgz",
+ "integrity": "sha512-+nTmxJVIPtAarGq9Fd/uU2qU/Ngfb9EntT0/kwXdKKMI0wU9fQNWi10xSTVeqOtzWERbQpOJgBAdta+v3W7cng==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
- "@smithy/core": "^3.2.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/core": "^3.3.1",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/signature-v4": "^5.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/signature-v4": "^5.1.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/util-middleware": "^4.0.2",
"fast-xml-parser": "4.4.1",
@@ -623,13 +644,13 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-env": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz",
- "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.808.0.tgz",
+ "integrity": "sha512-snPRQnwG9PV4kYHQimo1tenf7P974RcdxkHUThzWSxPEV7HpjxTFYNWGlKbOKBhL4AcgeCVeiZ/j+zveF2lEPA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -639,18 +660,18 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-http": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz",
- "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.808.0.tgz",
+ "integrity": "sha512-gNXjlx3BIUeX7QpVqxbjBxG6zm45lC39QvUIo92WzEJd2OTPcR8TU0OTTsgq/lpn2FrKcISj5qXvhWykd41+CA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/fetch-http-handler": "^5.0.2",
"@smithy/node-http-handler": "^4.0.4",
"@smithy/property-provider": "^4.0.2",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/util-stream": "^4.2.0",
"tslib": "^2.6.2"
@@ -660,19 +681,19 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-ini": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.777.0.tgz",
- "integrity": "sha512-1X9mCuM9JSQPmQ+D2TODt4THy6aJWCNiURkmKmTIPRdno7EIKgAqrr/LLN++K5mBf54DZVKpqcJutXU2jwo01A==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.808.0.tgz",
+ "integrity": "sha512-Y53CW0pCvFQQEvtVFwExCCMbTg+6NOl8b3YOuZVzPmVmDoW7M1JIn9IScesqoGERXL3VoXny6nYTsZj+vfpp7Q==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/credential-provider-env": "3.775.0",
- "@aws-sdk/credential-provider-http": "3.775.0",
- "@aws-sdk/credential-provider-process": "3.775.0",
- "@aws-sdk/credential-provider-sso": "3.777.0",
- "@aws-sdk/credential-provider-web-identity": "3.777.0",
- "@aws-sdk/nested-clients": "3.777.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/credential-provider-env": "3.808.0",
+ "@aws-sdk/credential-provider-http": "3.808.0",
+ "@aws-sdk/credential-provider-process": "3.808.0",
+ "@aws-sdk/credential-provider-sso": "3.808.0",
+ "@aws-sdk/credential-provider-web-identity": "3.808.0",
+ "@aws-sdk/nested-clients": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/credential-provider-imds": "^4.0.2",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
@@ -684,18 +705,18 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-node": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.777.0.tgz",
- "integrity": "sha512-ZD66ywx1Q0KyUSuBXZIQzBe3Q7MzX8lNwsrCU43H3Fww+Y+HB3Ncws9grhSdNhKQNeGmZ+MgKybuZYaaeLwJEQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.808.0.tgz",
+ "integrity": "sha512-lASHlXJ6U5Cpnt9Gs+mWaaSmWcEibr1AFGhp+5UNvfyd+UU2Oiwgbo7rYXygmaVDGkbfXEiTkgYtoNOBSddnWQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/credential-provider-env": "3.775.0",
- "@aws-sdk/credential-provider-http": "3.775.0",
- "@aws-sdk/credential-provider-ini": "3.777.0",
- "@aws-sdk/credential-provider-process": "3.775.0",
- "@aws-sdk/credential-provider-sso": "3.777.0",
- "@aws-sdk/credential-provider-web-identity": "3.777.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/credential-provider-env": "3.808.0",
+ "@aws-sdk/credential-provider-http": "3.808.0",
+ "@aws-sdk/credential-provider-ini": "3.808.0",
+ "@aws-sdk/credential-provider-process": "3.808.0",
+ "@aws-sdk/credential-provider-sso": "3.808.0",
+ "@aws-sdk/credential-provider-web-identity": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/credential-provider-imds": "^4.0.2",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
@@ -707,13 +728,13 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-process": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz",
- "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.808.0.tgz",
+ "integrity": "sha512-ZLqp+xsQUatoo8pMozcfLwf/pwfXeIk0w3n0Lo/rWBgT3RcdECmmPCRcnkYBqxHQyE66aS9HiJezZUwMYPqh6w==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
"@smithy/types": "^4.2.0",
@@ -724,15 +745,15 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-sso": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.777.0.tgz",
- "integrity": "sha512-9mPz7vk9uE4PBVprfINv4tlTkyq1OonNevx2DiXC1LY4mCUCNN3RdBwAY0BTLzj0uyc3k5KxFFNbn3/8ZDQP7w==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.808.0.tgz",
+ "integrity": "sha512-gWZByAokHX+aps1+syIW/hbKUBrjE2RpPRd/RGQvrBbVVgwsJzsHKsW0zy1B6mgARPG6IahmSUMjNkBCVsiAgw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/client-sso": "3.777.0",
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/token-providers": "3.777.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/client-sso": "3.808.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/token-providers": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
"@smithy/types": "^4.2.0",
@@ -743,14 +764,14 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-web-identity": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.777.0.tgz",
- "integrity": "sha512-uGCqr47fnthkqwq5luNl2dksgcpHHjSXz2jUra7TXtFOpqvnhOW8qXjoa1ivlkq8qhqlaZwCzPdbcN0lXpmLzQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.808.0.tgz",
+ "integrity": "sha512-SsGa1Gfa05aJM/qYOtHmfg0OKKW6Fl6kyMCcai63jWDVDYy0QSHcesnqRayJolISkdsVK6bqoWoFcPxiopcFcg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/nested-clients": "3.777.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/nested-clients": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -760,12 +781,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-host-header": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz",
- "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.804.0.tgz",
+ "integrity": "sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -775,12 +796,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-logger": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz",
- "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.804.0.tgz",
+ "integrity": "sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -789,12 +810,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-recursion-detection": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz",
- "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.804.0.tgz",
+ "integrity": "sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -804,15 +825,15 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-user-agent": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.775.0.tgz",
- "integrity": "sha512-7Lffpr1ptOEDE1ZYH1T78pheEY1YmeXWBfFt/amZ6AGsKSLG+JPXvof3ltporTGR2bhH/eJPo7UHCglIuXfzYg==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.808.0.tgz",
+ "integrity": "sha512-VckV6l5cf/rL3EtgzSHVTTD4mI0gd8UxDDWbKJsxbQ2bpNPDQG2L1wWGLaolTSzjEJ5f3ijDwQrNDbY9l85Mmg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@aws-sdk/util-endpoints": "3.775.0",
- "@smithy/core": "^3.2.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@aws-sdk/util-endpoints": "3.808.0",
+ "@smithy/core": "^3.3.1",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -822,13 +843,13 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/region-config-resolver": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz",
- "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.808.0.tgz",
+ "integrity": "sha512-9x2QWfphkARZY5OGkl9dJxZlSlYM2l5inFeo2bKntGuwg4A4YUe5h7d5yJ6sZbam9h43eBrkOdumx03DAkQF9A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"@smithy/util-config-provider": "^4.0.0",
"@smithy/util-middleware": "^4.0.2",
@@ -839,13 +860,13 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/token-providers": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.777.0.tgz",
- "integrity": "sha512-Yc2cDONsHOa4dTSGOev6Ng2QgTKQUEjaUnsyKd13pc/nLLz/WLqHiQ/o7PcnKERJxXGs1g1C6l3sNXiX+kbnFQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.808.0.tgz",
+ "integrity": "sha512-PsfKanHmnyO7FxowXqxbLQ+QjURCdSGxyhUiSdZbfvlvme/wqaMyIoMV/i4jppndksoSdPbW2kZXjzOqhQF+ew==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/nested-clients": "3.777.0",
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/nested-clients": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/property-provider": "^4.0.2",
"@smithy/shared-ini-file-loader": "^4.0.2",
"@smithy/types": "^4.2.0",
@@ -856,9 +877,9 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/types": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz",
- "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz",
+ "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.2.0",
@@ -869,14 +890,14 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-endpoints": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.775.0.tgz",
- "integrity": "sha512-yjWmUgZC9tUxAo8Uaplqmq0eUh0zrbZJdwxGRKdYxfm4RG6fMw1tj52+KkatH7o+mNZvg1GDcVp/INktxonJLw==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.808.0.tgz",
+ "integrity": "sha512-N6Lic98uc4ADB7fLWlzx+1uVnq04VgVjngZvwHoujcRg9YDhIg9dUDiTzD5VZv13g1BrPYmvYP1HhsildpGV6w==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
- "@smithy/util-endpoints": "^3.0.2",
+ "@smithy/util-endpoints": "^3.0.4",
"tslib": "^2.6.2"
},
"engines": {
@@ -884,26 +905,26 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-browser": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz",
- "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.804.0.tgz",
+ "integrity": "sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-node": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.775.0.tgz",
- "integrity": "sha512-N9yhTevbizTOMo3drH7Eoy6OkJ3iVPxhV7dwb6CMAObbLneS36CSfA6xQXupmHWcRvZPTz8rd1JGG3HzFOau+g==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.808.0.tgz",
+ "integrity": "sha512-5UmB6u7RBSinXZAVP2iDgqyeVA/odO2SLEcrXaeTCw8ICXEoqF0K+GL36T4iDbzCBOAIugOZ6OcQX5vH3ck5UA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-user-agent": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/middleware-user-agent": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -933,12 +954,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/config-resolver": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz",
- "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.2.tgz",
+ "integrity": "sha512-7r6mZGwb5LmLJ+zPtkLoznf2EtwEuSWdtid10pjGl/7HefCE4mueOkrfki8JCUm99W6UfP47/r3tbxx9CfBN5A==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"@smithy/util-config-provider": "^4.0.0",
"@smithy/util-middleware": "^4.0.2",
@@ -949,12 +970,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/core": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz",
- "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.3.2.tgz",
+ "integrity": "sha512-GlLv+syoWolhtjX12XplL9BXBu10cjjD8iQC69fiKTrVNOB3Fjt8CVI9ccm6G3bLbMNe1gzrLD7yyMkYo4hchw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/middleware-serde": "^4.0.3",
+ "@smithy/middleware-serde": "^4.0.4",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"@smithy/util-body-length-browser": "^4.0.0",
@@ -968,12 +989,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/credential-provider-imds": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz",
- "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.4.tgz",
+ "integrity": "sha512-jN6M6zaGVyB8FmNGG+xOPQB4N89M1x97MMdMnm1ESjljLS3Qju/IegQizKujaNcy2vXAvrz0en8bobe6E55FEA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
@@ -1042,14 +1063,15 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/is-array-buffer": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz",
- "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz",
+ "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==",
+ "license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=18.0.0"
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-content-length": {
@@ -1067,14 +1089,14 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-endpoint": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz",
- "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.5.tgz",
+ "integrity": "sha512-WlpC9KVkajQf7RaGwi3n6lhHZzYTgm2PyX/2JjcwSHG417gFloNmYqN8rzDRXjT527/ZxZuvCsqq1gWZPW8lag==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.2.0",
- "@smithy/middleware-serde": "^4.0.3",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/core": "^3.3.2",
+ "@smithy/middleware-serde": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/shared-ini-file-loader": "^4.0.2",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
@@ -1086,18 +1108,18 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-retry": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz",
- "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==",
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.6.tgz",
+ "integrity": "sha512-bl8q95nvCf7d22spxsBfs2giUDFf7prWLAxF5tmfgGBYHbUNW+OfnwMnabC15GMLA2AoE4HOtQR18a59lx6Blw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/service-error-classification": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/service-error-classification": "^4.0.3",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"@smithy/util-middleware": "^4.0.2",
- "@smithy/util-retry": "^4.0.2",
+ "@smithy/util-retry": "^4.0.3",
"tslib": "^2.6.2",
"uuid": "^9.0.1"
},
@@ -1106,11 +1128,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-serde": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz",
- "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.4.tgz",
+ "integrity": "sha512-CaLvBtz+Xgs7eOwoinTXhZ02/9u8b28RT8lQAaDh7Q59nygeYYp1UiJjwl6zsay+lp0qVT/S7qLVI5RgcxjyfQ==",
"license": "Apache-2.0",
"dependencies": {
+ "@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1132,9 +1155,9 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/node-config-provider": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz",
- "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.1.tgz",
+ "integrity": "sha512-1slS5jf5icHETwl5hxEVBj+mh6B+LbVW4yRINsGtUKH+nxM5Pw2H59+qf+JqYFCHp9jssG4vX81f5WKnjMN3Vw==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/property-provider": "^4.0.2",
@@ -1216,9 +1239,9 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/service-error-classification": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz",
- "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.3.tgz",
+ "integrity": "sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.2.0"
@@ -1241,9 +1264,9 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/signature-v4": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz",
- "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.0.tgz",
+ "integrity": "sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^4.0.0",
@@ -1259,26 +1282,14 @@
"node": ">=18.0.0"
}
},
- "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/signature-v4/node_modules/@smithy/is-array-buffer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz",
- "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==",
- "license": "Apache-2.0",
- "dependencies": {
- "tslib": "^2.6.2"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/smithy-client": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz",
- "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==",
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.5.tgz",
+ "integrity": "sha512-T3gA/TShe52Ln0ywWGVoDiqRvaxqvrU0CKRRmzT71/I1rRBD8mY85rvMMME6vw5RpBLJC9ADmXSLmpohF7RRhA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.2.0",
- "@smithy/middleware-endpoint": "^4.1.0",
+ "@smithy/core": "^3.3.2",
+ "@smithy/middleware-endpoint": "^4.1.5",
"@smithy/middleware-stack": "^4.0.2",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
@@ -1366,18 +1377,6 @@
"node": ">=18.0.0"
}
},
- "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz",
- "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==",
- "license": "Apache-2.0",
- "dependencies": {
- "tslib": "^2.6.2"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-config-provider": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz",
@@ -1391,13 +1390,13 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-defaults-mode-browser": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz",
- "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==",
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.13.tgz",
+ "integrity": "sha512-HCLfXAyTEpVWLuyxDABg8UQukeRwChL1UErpSQ4KJK2ZoadmXuQY68pTL9KcuEtasTkIjnzyLUL9vhLdJ3VFHQ==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/property-provider": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
@@ -1407,16 +1406,16 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-defaults-mode-node": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz",
- "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==",
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.13.tgz",
+ "integrity": "sha512-lu8E2RyzKzzFbNu4ICmY/2HltMZlJxMNg3saJ+r8I9vWbWbwdX7GOWUJdP4fbjEOm6aa52mnnd+uIRrT3dNEyA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/config-resolver": "^4.1.0",
- "@smithy/credential-provider-imds": "^4.0.2",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/config-resolver": "^4.1.2",
+ "@smithy/credential-provider-imds": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1425,12 +1424,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-endpoints": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz",
- "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.4.tgz",
+ "integrity": "sha512-VfFATC1bmZLV2858B/O1NpMcL32wYo8DPPhHxYxDCodDl3f3mSZ5oJheW1IF91A0EeAADz2WsakM/hGGPGNKLg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1464,12 +1463,12 @@
}
},
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-retry": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz",
- "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.3.tgz",
+ "integrity": "sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/service-error-classification": "^4.0.2",
+ "@smithy/service-error-classification": "^4.0.3",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1546,7 +1545,8 @@
"node_modules/@aws-sdk/client-bedrock-runtime/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
},
"node_modules/@aws-sdk/client-cognito-identity": {
"version": "3.699.0",
@@ -2872,6 +2872,111 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
},
+ "node_modules/@aws-sdk/eventstream-handler-node": {
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.804.0.tgz",
+ "integrity": "sha512-LZddQVBUCB86tZtLJRhqiDyIqr4hfRxZCcUp1fZSfpBMcf419lgcFRGWMR3J/kCWHQ0G05aor7fSeoeaxskuNQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/eventstream-codec": "^4.0.2",
+ "@smithy/types": "^4.2.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/eventstream-handler-node/node_modules/@aws-sdk/types": {
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz",
+ "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@smithy/types": "^4.2.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/eventstream-handler-node/node_modules/@smithy/types": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz",
+ "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/eventstream-handler-node/node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/@aws-sdk/middleware-eventstream": {
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.804.0.tgz",
+ "integrity": "sha512-3lPxZshOJoKSxIMUq8FCiIre+FZ1g/t+O7DHwOMB6EuzJ8lp5QyUeh1wE5iD/gB8VhWZoj90rGIaWCmT8ccEuA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/protocol-http": "^5.1.0",
+ "@smithy/types": "^4.2.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/middleware-eventstream/node_modules/@aws-sdk/types": {
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz",
+ "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@smithy/types": "^4.2.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/middleware-eventstream/node_modules/@smithy/protocol-http": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz",
+ "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@smithy/types": "^4.2.0",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/middleware-eventstream/node_modules/@smithy/types": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz",
+ "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/middleware-eventstream/node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/@aws-sdk/middleware-host-header": {
"version": "3.696.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.696.0.tgz",
@@ -3031,47 +3136,47 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
},
"node_modules/@aws-sdk/nested-clients": {
- "version": "3.777.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.777.0.tgz",
- "integrity": "sha512-bmmVRsCjuYlStYPt06hr+f8iEyWg7+AklKCA8ZLDEJujXhXIowgUIqXmqpTkXwkVvDQ9tzU7hxaONjyaQCGybA==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.808.0.tgz",
+ "integrity": "sha512-NparPojwoBul7XPCasy4psFMJbw7Ys4bz8lVB93ljEUD4VV7mM7zwK27Uhz20B8mBFGmFEoAprPsVymJcK9Vcw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/middleware-host-header": "3.775.0",
- "@aws-sdk/middleware-logger": "3.775.0",
- "@aws-sdk/middleware-recursion-detection": "3.775.0",
- "@aws-sdk/middleware-user-agent": "3.775.0",
- "@aws-sdk/region-config-resolver": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@aws-sdk/util-endpoints": "3.775.0",
- "@aws-sdk/util-user-agent-browser": "3.775.0",
- "@aws-sdk/util-user-agent-node": "3.775.0",
- "@smithy/config-resolver": "^4.1.0",
- "@smithy/core": "^3.2.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/middleware-host-header": "3.804.0",
+ "@aws-sdk/middleware-logger": "3.804.0",
+ "@aws-sdk/middleware-recursion-detection": "3.804.0",
+ "@aws-sdk/middleware-user-agent": "3.808.0",
+ "@aws-sdk/region-config-resolver": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@aws-sdk/util-endpoints": "3.808.0",
+ "@aws-sdk/util-user-agent-browser": "3.804.0",
+ "@aws-sdk/util-user-agent-node": "3.808.0",
+ "@smithy/config-resolver": "^4.1.2",
+ "@smithy/core": "^3.3.1",
"@smithy/fetch-http-handler": "^5.0.2",
"@smithy/hash-node": "^4.0.2",
"@smithy/invalid-dependency": "^4.0.2",
"@smithy/middleware-content-length": "^4.0.2",
- "@smithy/middleware-endpoint": "^4.1.0",
- "@smithy/middleware-retry": "^4.1.0",
+ "@smithy/middleware-endpoint": "^4.1.4",
+ "@smithy/middleware-retry": "^4.1.5",
"@smithy/middleware-serde": "^4.0.3",
"@smithy/middleware-stack": "^4.0.2",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/node-http-handler": "^4.0.4",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
"@smithy/util-base64": "^4.0.0",
"@smithy/util-body-length-browser": "^4.0.0",
"@smithy/util-body-length-node": "^4.0.0",
- "@smithy/util-defaults-mode-browser": "^4.0.8",
- "@smithy/util-defaults-mode-node": "^4.0.8",
- "@smithy/util-endpoints": "^3.0.2",
+ "@smithy/util-defaults-mode-browser": "^4.0.12",
+ "@smithy/util-defaults-mode-node": "^4.0.12",
+ "@smithy/util-endpoints": "^3.0.4",
"@smithy/util-middleware": "^4.0.2",
- "@smithy/util-retry": "^4.0.2",
+ "@smithy/util-retry": "^4.0.3",
"@smithy/util-utf8": "^4.0.0",
"tslib": "^2.6.2"
},
@@ -3143,18 +3248,18 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/core": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz",
- "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.808.0.tgz",
+ "integrity": "sha512-+nTmxJVIPtAarGq9Fd/uU2qU/Ngfb9EntT0/kwXdKKMI0wU9fQNWi10xSTVeqOtzWERbQpOJgBAdta+v3W7cng==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
- "@smithy/core": "^3.2.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/core": "^3.3.1",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/signature-v4": "^5.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/signature-v4": "^5.1.0",
+ "@smithy/smithy-client": "^4.2.4",
"@smithy/types": "^4.2.0",
"@smithy/util-middleware": "^4.0.2",
"fast-xml-parser": "4.4.1",
@@ -3165,12 +3270,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-host-header": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz",
- "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.804.0.tgz",
+ "integrity": "sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -3180,12 +3285,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-logger": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz",
- "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.804.0.tgz",
+ "integrity": "sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -3194,12 +3299,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-recursion-detection": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz",
- "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.804.0.tgz",
+ "integrity": "sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -3209,15 +3314,15 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-user-agent": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.775.0.tgz",
- "integrity": "sha512-7Lffpr1ptOEDE1ZYH1T78pheEY1YmeXWBfFt/amZ6AGsKSLG+JPXvof3ltporTGR2bhH/eJPo7UHCglIuXfzYg==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.808.0.tgz",
+ "integrity": "sha512-VckV6l5cf/rL3EtgzSHVTTD4mI0gd8UxDDWbKJsxbQ2bpNPDQG2L1wWGLaolTSzjEJ5f3ijDwQrNDbY9l85Mmg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@aws-sdk/util-endpoints": "3.775.0",
- "@smithy/core": "^3.2.0",
+ "@aws-sdk/core": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@aws-sdk/util-endpoints": "3.808.0",
+ "@smithy/core": "^3.3.1",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
@@ -3227,13 +3332,13 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/region-config-resolver": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz",
- "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.808.0.tgz",
+ "integrity": "sha512-9x2QWfphkARZY5OGkl9dJxZlSlYM2l5inFeo2bKntGuwg4A4YUe5h7d5yJ6sZbam9h43eBrkOdumx03DAkQF9A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"@smithy/util-config-provider": "^4.0.0",
"@smithy/util-middleware": "^4.0.2",
@@ -3244,9 +3349,9 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/types": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz",
- "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.804.0.tgz",
+ "integrity": "sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.2.0",
@@ -3257,14 +3362,14 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-endpoints": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.775.0.tgz",
- "integrity": "sha512-yjWmUgZC9tUxAo8Uaplqmq0eUh0zrbZJdwxGRKdYxfm4RG6fMw1tj52+KkatH7o+mNZvg1GDcVp/INktxonJLw==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.808.0.tgz",
+ "integrity": "sha512-N6Lic98uc4ADB7fLWlzx+1uVnq04VgVjngZvwHoujcRg9YDhIg9dUDiTzD5VZv13g1BrPYmvYP1HhsildpGV6w==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
- "@smithy/util-endpoints": "^3.0.2",
+ "@smithy/util-endpoints": "^3.0.4",
"tslib": "^2.6.2"
},
"engines": {
@@ -3272,26 +3377,26 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-browser": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz",
- "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==",
+ "version": "3.804.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.804.0.tgz",
+ "integrity": "sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.775.0",
+ "@aws-sdk/types": "3.804.0",
"@smithy/types": "^4.2.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-node": {
- "version": "3.775.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.775.0.tgz",
- "integrity": "sha512-N9yhTevbizTOMo3drH7Eoy6OkJ3iVPxhV7dwb6CMAObbLneS36CSfA6xQXupmHWcRvZPTz8rd1JGG3HzFOau+g==",
+ "version": "3.808.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.808.0.tgz",
+ "integrity": "sha512-5UmB6u7RBSinXZAVP2iDgqyeVA/odO2SLEcrXaeTCw8ICXEoqF0K+GL36T4iDbzCBOAIugOZ6OcQX5vH3ck5UA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-user-agent": "3.775.0",
- "@aws-sdk/types": "3.775.0",
- "@smithy/node-config-provider": "^4.0.2",
+ "@aws-sdk/middleware-user-agent": "3.808.0",
+ "@aws-sdk/types": "3.804.0",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -3321,12 +3426,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/config-resolver": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz",
- "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.2.tgz",
+ "integrity": "sha512-7r6mZGwb5LmLJ+zPtkLoznf2EtwEuSWdtid10pjGl/7HefCE4mueOkrfki8JCUm99W6UfP47/r3tbxx9CfBN5A==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"@smithy/util-config-provider": "^4.0.0",
"@smithy/util-middleware": "^4.0.2",
@@ -3337,12 +3442,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/core": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz",
- "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.3.2.tgz",
+ "integrity": "sha512-GlLv+syoWolhtjX12XplL9BXBu10cjjD8iQC69fiKTrVNOB3Fjt8CVI9ccm6G3bLbMNe1gzrLD7yyMkYo4hchw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/middleware-serde": "^4.0.3",
+ "@smithy/middleware-serde": "^4.0.4",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"@smithy/util-body-length-browser": "^4.0.0",
@@ -3356,12 +3461,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/credential-provider-imds": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz",
- "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.4.tgz",
+ "integrity": "sha512-jN6M6zaGVyB8FmNGG+xOPQB4N89M1x97MMdMnm1ESjljLS3Qju/IegQizKujaNcy2vXAvrz0en8bobe6E55FEA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
@@ -3442,14 +3547,14 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-endpoint": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz",
- "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.5.tgz",
+ "integrity": "sha512-WlpC9KVkajQf7RaGwi3n6lhHZzYTgm2PyX/2JjcwSHG417gFloNmYqN8rzDRXjT527/ZxZuvCsqq1gWZPW8lag==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.2.0",
- "@smithy/middleware-serde": "^4.0.3",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/core": "^3.3.2",
+ "@smithy/middleware-serde": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/shared-ini-file-loader": "^4.0.2",
"@smithy/types": "^4.2.0",
"@smithy/url-parser": "^4.0.2",
@@ -3461,18 +3566,18 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-retry": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz",
- "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==",
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.6.tgz",
+ "integrity": "sha512-bl8q95nvCf7d22spxsBfs2giUDFf7prWLAxF5tmfgGBYHbUNW+OfnwMnabC15GMLA2AoE4HOtQR18a59lx6Blw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/protocol-http": "^5.1.0",
- "@smithy/service-error-classification": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/service-error-classification": "^4.0.3",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"@smithy/util-middleware": "^4.0.2",
- "@smithy/util-retry": "^4.0.2",
+ "@smithy/util-retry": "^4.0.3",
"tslib": "^2.6.2",
"uuid": "^9.0.1"
},
@@ -3481,11 +3586,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-serde": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz",
- "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.4.tgz",
+ "integrity": "sha512-CaLvBtz+Xgs7eOwoinTXhZ02/9u8b28RT8lQAaDh7Q59nygeYYp1UiJjwl6zsay+lp0qVT/S7qLVI5RgcxjyfQ==",
"license": "Apache-2.0",
"dependencies": {
+ "@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -3507,9 +3613,9 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-config-provider": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz",
- "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.1.tgz",
+ "integrity": "sha512-1slS5jf5icHETwl5hxEVBj+mh6B+LbVW4yRINsGtUKH+nxM5Pw2H59+qf+JqYFCHp9jssG4vX81f5WKnjMN3Vw==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/property-provider": "^4.0.2",
@@ -3591,9 +3697,9 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/service-error-classification": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz",
- "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.3.tgz",
+ "integrity": "sha512-FTbcajmltovWMjj3tksDQdD23b2w6gH+A0DYA1Yz3iSpjDj8fmkwy62UnXcWMy4d5YoMoSyLFHMfkEVEzbiN8Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.2.0"
@@ -3616,9 +3722,9 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/signature-v4": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz",
- "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.0.tgz",
+ "integrity": "sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^4.0.0",
@@ -3635,13 +3741,13 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/smithy-client": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz",
- "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==",
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.5.tgz",
+ "integrity": "sha512-T3gA/TShe52Ln0ywWGVoDiqRvaxqvrU0CKRRmzT71/I1rRBD8mY85rvMMME6vw5RpBLJC9ADmXSLmpohF7RRhA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.2.0",
- "@smithy/middleware-endpoint": "^4.1.0",
+ "@smithy/core": "^3.3.2",
+ "@smithy/middleware-endpoint": "^4.1.5",
"@smithy/middleware-stack": "^4.0.2",
"@smithy/protocol-http": "^5.1.0",
"@smithy/types": "^4.2.0",
@@ -3742,13 +3848,13 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-browser": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz",
- "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==",
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.13.tgz",
+ "integrity": "sha512-HCLfXAyTEpVWLuyxDABg8UQukeRwChL1UErpSQ4KJK2ZoadmXuQY68pTL9KcuEtasTkIjnzyLUL9vhLdJ3VFHQ==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/property-provider": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
@@ -3758,16 +3864,16 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-node": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz",
- "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==",
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.13.tgz",
+ "integrity": "sha512-lu8E2RyzKzzFbNu4ICmY/2HltMZlJxMNg3saJ+r8I9vWbWbwdX7GOWUJdP4fbjEOm6aa52mnnd+uIRrT3dNEyA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/config-resolver": "^4.1.0",
- "@smithy/credential-provider-imds": "^4.0.2",
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/config-resolver": "^4.1.2",
+ "@smithy/credential-provider-imds": "^4.0.4",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/property-provider": "^4.0.2",
- "@smithy/smithy-client": "^4.2.0",
+ "@smithy/smithy-client": "^4.2.5",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -3776,12 +3882,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-endpoints": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz",
- "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.4.tgz",
+ "integrity": "sha512-VfFATC1bmZLV2858B/O1NpMcL32wYo8DPPhHxYxDCodDl3f3mSZ5oJheW1IF91A0EeAADz2WsakM/hGGPGNKLg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.0.2",
+ "@smithy/node-config-provider": "^4.1.1",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -3815,12 +3921,12 @@
}
},
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-retry": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz",
- "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.3.tgz",
+ "integrity": "sha512-DPuYjZQDXmKr/sNvy9Spu8R/ESa2e22wXZzSAY6NkjOLj6spbIje/Aq8rT97iUMdDj0qHMRIe+bTxvlU74d9Ng==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/service-error-classification": "^4.0.2",
+ "@smithy/service-error-classification": "^4.0.3",
"@smithy/types": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -4861,16 +4967,17 @@
"dev": true
},
"node_modules/@changesets/apply-release-plan": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.6.tgz",
- "integrity": "sha512-TKhVLtiwtQOgMAC0fCJfmv93faiViKSDqr8oMEqrnNs99gtSC1sZh/aEMS9a+dseU1ESZRCK+ofLgGY7o0fw/Q==",
+ "version": "7.0.12",
+ "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.12.tgz",
+ "integrity": "sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/config": "^3.0.4",
+ "@changesets/config": "^3.1.1",
"@changesets/get-version-range-type": "^0.4.0",
- "@changesets/git": "^3.0.2",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
+ "@changesets/git": "^3.0.4",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3",
"detect-indent": "^6.0.0",
"fs-extra": "^7.0.1",
@@ -4906,52 +5013,55 @@
}
},
"node_modules/@changesets/assemble-release-plan": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.5.tgz",
- "integrity": "sha512-IgvBWLNKZd6k4t72MBTBK3nkygi0j3t3zdC1zrfusYo0KpdsvnDjrMM9vPnTCLCMlfNs55jRL4gIMybxa64FCQ==",
+ "version": "6.0.8",
+ "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.8.tgz",
+ "integrity": "sha512-y8+8LvZCkKJdbUlpXFuqcavpzJR80PN0OIfn8HZdwK7Sh6MgLXm4hKY5vu6/NDoKp8lAlM4ERZCqRMLxP4m+MQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
+ "@changesets/get-dependents-graph": "^2.1.3",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3",
"semver": "^7.5.3"
}
},
"node_modules/@changesets/changelog-git": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.0.tgz",
- "integrity": "sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==",
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz",
+ "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/types": "^6.0.0"
+ "@changesets/types": "^6.1.0"
}
},
"node_modules/@changesets/cli": {
- "version": "2.27.10",
- "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.27.10.tgz",
- "integrity": "sha512-PfeXjvs9OfQJV8QSFFHjwHX3QnUL9elPEQ47SgkiwzLgtKGyuikWjrdM+lO9MXzOE22FO9jEGkcs4b+B6D6X0Q==",
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.29.4.tgz",
+ "integrity": "sha512-VW30x9oiFp/un/80+5jLeWgEU6Btj8IqOgI+X/zAYu4usVOWXjPIK5jSSlt5jsCU7/6Z7AxEkarxBxGUqkAmNg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/apply-release-plan": "^7.0.6",
- "@changesets/assemble-release-plan": "^6.0.5",
- "@changesets/changelog-git": "^0.2.0",
- "@changesets/config": "^3.0.4",
+ "@changesets/apply-release-plan": "^7.0.12",
+ "@changesets/assemble-release-plan": "^6.0.8",
+ "@changesets/changelog-git": "^0.2.1",
+ "@changesets/config": "^3.1.1",
"@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
- "@changesets/get-release-plan": "^4.0.5",
- "@changesets/git": "^3.0.2",
+ "@changesets/get-dependents-graph": "^2.1.3",
+ "@changesets/get-release-plan": "^4.0.12",
+ "@changesets/git": "^3.0.4",
"@changesets/logger": "^0.1.1",
- "@changesets/pre": "^2.0.1",
- "@changesets/read": "^0.6.2",
- "@changesets/should-skip-package": "^0.1.1",
- "@changesets/types": "^6.0.0",
- "@changesets/write": "^0.3.2",
+ "@changesets/pre": "^2.0.2",
+ "@changesets/read": "^0.6.5",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
+ "@changesets/write": "^0.4.0",
"@manypkg/get-packages": "^1.1.3",
"ansi-colors": "^4.1.3",
"ci-info": "^3.7.0",
- "enquirer": "^2.3.0",
+ "enquirer": "^2.4.1",
"external-editor": "^3.1.0",
"fs-extra": "^7.0.1",
"mri": "^1.2.0",
@@ -4972,6 +5082,7 @@
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
@@ -4987,20 +5098,22 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@changesets/config": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.0.4.tgz",
- "integrity": "sha512-+DiIwtEBpvvv1z30f8bbOsUQGuccnZl9KRKMM/LxUHuDu5oEjmN+bJQ1RIBKNJjfYMQn8RZzoPiX0UgPaLQyXw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.1.tgz",
+ "integrity": "sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@changesets/errors": "^0.2.0",
- "@changesets/get-dependents-graph": "^2.1.2",
+ "@changesets/get-dependents-graph": "^2.1.3",
"@changesets/logger": "^0.1.1",
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3",
"fs-extra": "^7.0.1",
"micromatch": "^4.0.8"
@@ -5016,28 +5129,30 @@
}
},
"node_modules/@changesets/get-dependents-graph": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.2.tgz",
- "integrity": "sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz",
+ "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3",
"picocolors": "^1.1.0",
"semver": "^7.5.3"
}
},
"node_modules/@changesets/get-release-plan": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.5.tgz",
- "integrity": "sha512-E6wW7JoSMcctdVakut0UB76FrrN3KIeJSXvB+DHMFo99CnC3ZVnNYDCVNClMlqAhYGmLmAj77QfApaI3ca4Fkw==",
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.12.tgz",
+ "integrity": "sha512-KukdEgaafnyGryUwpHG2kZ7xJquOmWWWk5mmoeQaSvZTWH1DC5D/Sw6ClgGFYtQnOMSQhgoEbDxAbpIIayKH1g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/assemble-release-plan": "^6.0.5",
- "@changesets/config": "^3.0.4",
- "@changesets/pre": "^2.0.1",
- "@changesets/read": "^0.6.2",
- "@changesets/types": "^6.0.0",
+ "@changesets/assemble-release-plan": "^6.0.8",
+ "@changesets/config": "^3.1.1",
+ "@changesets/pre": "^2.0.2",
+ "@changesets/read": "^0.6.5",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3"
}
},
@@ -5048,10 +5163,11 @@
"dev": true
},
"node_modules/@changesets/git": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.2.tgz",
- "integrity": "sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz",
+ "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@changesets/errors": "^0.2.0",
"@manypkg/get-packages": "^1.1.3",
@@ -5070,12 +5186,13 @@
}
},
"node_modules/@changesets/parse": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.0.tgz",
- "integrity": "sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.1.tgz",
+ "integrity": "sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"js-yaml": "^3.13.1"
}
},
@@ -5084,6 +5201,7 @@
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
@@ -5093,6 +5211,7 @@
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -5105,60 +5224,66 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true
+ "dev": true,
+ "license": "BSD-3-Clause"
},
"node_modules/@changesets/pre": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.1.tgz",
- "integrity": "sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz",
+ "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@changesets/errors": "^0.2.0",
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3",
"fs-extra": "^7.0.1"
}
},
"node_modules/@changesets/read": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.2.tgz",
- "integrity": "sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==",
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.5.tgz",
+ "integrity": "sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/git": "^3.0.2",
+ "@changesets/git": "^3.0.4",
"@changesets/logger": "^0.1.1",
- "@changesets/parse": "^0.4.0",
- "@changesets/types": "^6.0.0",
+ "@changesets/parse": "^0.4.1",
+ "@changesets/types": "^6.1.0",
"fs-extra": "^7.0.1",
"p-filter": "^2.1.0",
"picocolors": "^1.1.0"
}
},
"node_modules/@changesets/should-skip-package": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.1.tgz",
- "integrity": "sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==",
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz",
+ "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"@manypkg/get-packages": "^1.1.3"
}
},
"node_modules/@changesets/types": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.0.0.tgz",
- "integrity": "sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==",
- "dev": true
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz",
+ "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@changesets/write": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.3.2.tgz",
- "integrity": "sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz",
+ "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@changesets/types": "^6.0.0",
+ "@changesets/types": "^6.1.0",
"fs-extra": "^7.0.1",
- "human-id": "^1.0.2",
+ "human-id": "^4.1.1",
"prettier": "^2.7.1"
}
},
@@ -5178,9 +5303,9 @@
}
},
"node_modules/@dotenvx/dotenvx": {
- "version": "1.34.0",
- "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.34.0.tgz",
- "integrity": "sha512-+Dp/xaI3IZ4eKv+b2vg4V89VnqLKbmJ7UZ7unnZxMu9SNLOSc2jYaXey1YHCJM+67T0pOr2Gbej3TewnuoqTWQ==",
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.44.0.tgz",
+ "integrity": "sha512-18Aa+7KP/L2Kj9lxmT4EJZnsCq/xGIHgzU26rdzsKMhjpeT3YY+qin/dNAnIaVHPZnee7kXpZL55M9htd30r7Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -5237,9 +5362,9 @@
}
},
"node_modules/@dotenvx/dotenvx/node_modules/fdir": {
- "version": "6.4.3",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
- "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@@ -5359,9 +5484,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
- "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
+ "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
"cpu": [
"ppc64"
],
@@ -5376,9 +5501,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
- "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
+ "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
"cpu": [
"arm"
],
@@ -5393,9 +5518,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
- "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
+ "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
"cpu": [
"arm64"
],
@@ -5410,9 +5535,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
- "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
+ "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
"cpu": [
"x64"
],
@@ -5427,9 +5552,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
- "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
+ "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
"cpu": [
"arm64"
],
@@ -5444,9 +5569,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
- "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
+ "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
"cpu": [
"x64"
],
@@ -5461,9 +5586,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
- "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
"cpu": [
"arm64"
],
@@ -5478,9 +5603,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
- "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
+ "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
"cpu": [
"x64"
],
@@ -5495,9 +5620,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
- "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
+ "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
"cpu": [
"arm"
],
@@ -5512,9 +5637,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
- "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
+ "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
"cpu": [
"arm64"
],
@@ -5529,9 +5654,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
- "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
+ "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
"cpu": [
"ia32"
],
@@ -5546,9 +5671,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
- "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
+ "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
"cpu": [
"loong64"
],
@@ -5563,9 +5688,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
- "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
+ "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
"cpu": [
"mips64el"
],
@@ -5580,9 +5705,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
- "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
+ "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
"cpu": [
"ppc64"
],
@@ -5597,9 +5722,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
- "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
+ "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
"cpu": [
"riscv64"
],
@@ -5614,9 +5739,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
- "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
+ "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
"cpu": [
"s390x"
],
@@ -5631,9 +5756,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
- "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
+ "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
"cpu": [
"x64"
],
@@ -5648,9 +5773,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
- "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
"cpu": [
"arm64"
],
@@ -5665,9 +5790,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
- "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
+ "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
"cpu": [
"x64"
],
@@ -5682,9 +5807,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
- "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
+ "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
"cpu": [
"arm64"
],
@@ -5699,9 +5824,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
- "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
+ "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
"cpu": [
"x64"
],
@@ -5716,9 +5841,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
- "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
+ "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
"cpu": [
"x64"
],
@@ -5733,9 +5858,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
- "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
+ "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
"cpu": [
"arm64"
],
@@ -5750,9 +5875,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
- "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
+ "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
"cpu": [
"ia32"
],
@@ -5767,9 +5892,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
- "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
+ "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
"cpu": [
"x64"
],
@@ -5890,9 +6015,9 @@
"license": "MIT"
},
"node_modules/@google/genai": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/@google/genai/-/genai-0.9.0.tgz",
- "integrity": "sha512-FD2RizYGInsvfjeaN6O+wQGpRnGVglS1XWrGQr8K7D04AfMmvPodDSw94U9KyFtsVLzWH9kmlPyFM+G4jbmkqg==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@google/genai/-/genai-0.13.0.tgz",
+ "integrity": "sha512-eaEncWt875H7046T04mOpxpHJUM+jLIljEf+5QctRyOeChylE/nhpwm1bZWTRWoOu/t46R9r+PmgsJFhTpE7tQ==",
"license": "Apache-2.0",
"dependencies": {
"google-auth-library": "^9.14.2",
@@ -5904,24 +6029,6 @@
"node": ">=18.0.0"
}
},
- "node_modules/@google/genai/node_modules/zod": {
- "version": "3.24.3",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz",
- "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
- },
- "node_modules/@google/genai/node_modules/zod-to-json-schema": {
- "version": "3.24.5",
- "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
- "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
- "license": "ISC",
- "peerDependencies": {
- "zod": "^3.24.1"
- }
- },
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@@ -6743,17 +6850,18 @@
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
},
"node_modules/@modelcontextprotocol/sdk": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz",
- "integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.9.0.tgz",
+ "integrity": "sha512-Jq2EUCQpe0iyO5FGpzVYDNFR6oR53AIrwph9yWl7uSc7IWUMsrmpmSaTGra5hQNunXpM+9oit85p924jWuHzUA==",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
"cors": "^2.8.5",
+ "cross-spawn": "^7.0.3",
"eventsource": "^3.0.2",
"express": "^5.0.1",
"express-rate-limit": "^7.5.0",
- "pkce-challenge": "^4.1.0",
+ "pkce-challenge": "^5.0.0",
"raw-body": "^3.0.0",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.24.1"
@@ -6762,22 +6870,13 @@
"node": ">=18"
}
},
- "node_modules/@modelcontextprotocol/sdk/node_modules/zod": {
- "version": "3.24.2",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
- "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
+ "node_modules/@modelcontextprotocol/sdk/node_modules/pkce-challenge": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
+ "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
"license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
- },
- "node_modules/@modelcontextprotocol/sdk/node_modules/zod-to-json-schema": {
- "version": "3.24.3",
- "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz",
- "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==",
- "license": "ISC",
- "peerDependencies": {
- "zod": "^3.24.1"
+ "engines": {
+ "node": ">=16.20.0"
}
},
"node_modules/@mswjs/interceptors": {
@@ -7229,6 +7328,19 @@
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
"dev": true
},
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@sinonjs/commons": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
@@ -8910,47 +9022,6 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
},
- "node_modules/@snyk/github-codeowners": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz",
- "integrity": "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==",
- "dev": true,
- "dependencies": {
- "commander": "^4.1.1",
- "ignore": "^5.1.8",
- "p-map": "^4.0.0"
- },
- "bin": {
- "github-codeowners": "dist/cli.js"
- },
- "engines": {
- "node": ">=8.10"
- }
- },
- "node_modules/@snyk/github-codeowners/node_modules/commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/@snyk/github-codeowners/node_modules/p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
- "dev": true,
- "dependencies": {
- "aggregate-error": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/@tootallnate/quickjs-emscripten": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
@@ -9109,21 +9180,23 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.17.9",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.9.tgz",
- "integrity": "sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw==",
+ "version": "20.17.46",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.46.tgz",
+ "integrity": "sha512-0PQHLhZPWOxGW4auogW0eOQAuNIlCYvibIpG67ja0TOJ6/sehu+1en7sfceUn+QQtx4Rk3GxbLNwPh0Cav7TWw==",
+ "license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/@types/node-cache": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/@types/node-cache/-/node-cache-4.1.3.tgz",
- "integrity": "sha512-3hsqnv3H1zkOhjygJaJUYmgz5+FcPO3vejBX7cE9/cnuINOJYrzkfOnUCvpwGe9kMZANIHJA7J5pOdeyv52OEw==",
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@types/node-cache/-/node-cache-4.2.5.tgz",
+ "integrity": "sha512-faK2Owokboz53g8ooq2dw3iDJ6/HMTCIa2RvMte5WMTiABy+wA558K+iuyRtlR67Un5q9gEKysSDtqZYbSa0Pg==",
+ "deprecated": "This is a stub types definition. node-cache provides its own type definitions, so you do not need this installed.",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/node": "*"
+ "node-cache": "*"
}
},
"node_modules/@types/node-fetch": {
@@ -9146,9 +9219,13 @@
}
},
"node_modules/@types/pdf-parse": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@types/pdf-parse/-/pdf-parse-1.1.4.tgz",
- "integrity": "sha512-+gbBHbNCVGGYw1S9lAIIvrHW47UYOhMIFUsJcMkMrzy1Jf0vulBN3XQIjPgnoOXveMuHnF3b57fXROnY/Or7eg=="
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@types/pdf-parse/-/pdf-parse-1.1.5.tgz",
+ "integrity": "sha512-kBfrSXsloMnUJOKi25s3+hRmkycHfLK6A09eRGqF/N8BkQoPUmaCr+q8Cli5FnfohEz/rsv82zAiPz/LXtOGhA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
},
"node_modules/@types/ps-tree": {
"version": "1.1.6",
@@ -9435,6 +9512,119 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
+ "node_modules/@vitest/expect": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.3.tgz",
+ "integrity": "sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "3.1.3",
+ "@vitest/utils": "3.1.3",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.3.tgz",
+ "integrity": "sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "3.1.3",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.17"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0 || ^6.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/pretty-format": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.3.tgz",
+ "integrity": "sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.3.tgz",
+ "integrity": "sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "3.1.3",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.3.tgz",
+ "integrity": "sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.1.3",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.3.tgz",
+ "integrity": "sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^3.0.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.3.tgz",
+ "integrity": "sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.1.3",
+ "loupe": "^3.1.3",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
"node_modules/@vscode/codicons": {
"version": "0.0.36",
"resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.36.tgz",
@@ -9939,19 +10129,6 @@
"node": ">= 8.0.0"
}
},
- "node_modules/aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
- "dev": true,
- "dependencies": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -10060,22 +10237,6 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
- "node_modules/array-buffer-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
- "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.5",
- "is-array-buffer": "^3.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -10085,26 +10246,14 @@
"node": ">=8"
}
},
- "node_modules/arraybuffer.prototype.slice": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
- "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.2.1",
- "get-intrinsic": "^1.2.3",
- "is-array-buffer": "^3.0.4",
- "is-shared-array-buffer": "^1.0.2"
- },
+ "license": "MIT",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=12"
}
},
"node_modules/ast-types": {
@@ -10134,25 +10283,10 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
- "node_modules/available-typed-arrays": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
- "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
- "dev": true,
- "dependencies": {
- "possible-typed-array-names": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/axios": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
- "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
+ "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -10402,6 +10536,7 @@
"resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
"integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-windows": "^1.0.0"
},
@@ -10676,24 +10811,6 @@
"node": ">=8"
}
},
- "node_modules/call-bind": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
- "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
- "dev": true,
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.0",
- "es-define-property": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "set-function-length": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -10761,6 +10878,23 @@
}
]
},
+ "node_modules/chai": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+ "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -10804,6 +10938,16 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "node_modules/check-error": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+ "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
"node_modules/cheerio": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
@@ -10880,6 +11024,15 @@
"devtools-protocol": "*"
}
},
+ "node_modules/chromium-bidi/node_modules/zod": {
+ "version": "3.23.8",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
+ "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/ci-info": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
@@ -10907,15 +11060,6 @@
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
"license": "MIT"
},
- "node_modules/clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/cli-cursor": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
@@ -11050,16 +11194,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=0.8"
- }
- },
"node_modules/clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -11469,57 +11603,6 @@
"node": ">= 14"
}
},
- "node_modules/data-view-buffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
- "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
- "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-offset": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
- "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@@ -11567,10 +11650,20 @@
}
}
},
- "node_modules/deep-extend": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
- "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -11634,36 +11727,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/defaults": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
- "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "clone": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/define-data-property": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
- "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
- "dev": true,
- "dependencies": {
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/define-lazy-prop": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -11677,23 +11740,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/define-properties": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
- "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
- "dev": true,
- "dependencies": {
- "define-data-property": "^1.0.1",
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/degenerator": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
@@ -11947,27 +11993,6 @@
"node": ">=6.0.0"
}
},
- "node_modules/easy-table": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz",
- "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "optionalDependencies": {
- "wcwidth": "^1.0.1"
- }
- },
- "node_modules/easy-table/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -12153,66 +12178,6 @@
"is-arrayish": "^0.2.1"
}
},
- "node_modules/es-abstract": {
- "version": "1.23.5",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz",
- "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==",
- "dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "arraybuffer.prototype.slice": "^1.0.3",
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "data-view-buffer": "^1.0.1",
- "data-view-byte-length": "^1.0.1",
- "data-view-byte-offset": "^1.0.0",
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-set-tostringtag": "^2.0.3",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.6",
- "get-intrinsic": "^1.2.4",
- "get-symbol-description": "^1.0.2",
- "globalthis": "^1.0.4",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.2",
- "internal-slot": "^1.0.7",
- "is-array-buffer": "^3.0.4",
- "is-callable": "^1.2.7",
- "is-data-view": "^1.0.1",
- "is-negative-zero": "^2.0.3",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.3",
- "is-string": "^1.0.7",
- "is-typed-array": "^1.1.13",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.13.3",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.5",
- "regexp.prototype.flags": "^1.5.3",
- "safe-array-concat": "^1.1.2",
- "safe-regex-test": "^1.0.3",
- "string.prototype.trim": "^1.2.9",
- "string.prototype.trimend": "^1.0.8",
- "string.prototype.trimstart": "^1.0.8",
- "typed-array-buffer": "^1.0.2",
- "typed-array-byte-length": "^1.0.1",
- "typed-array-byte-offset": "^1.0.2",
- "typed-array-length": "^1.0.6",
- "unbox-primitive": "^1.0.2",
- "which-typed-array": "^1.1.15"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
@@ -12229,6 +12194,13 @@
"node": ">= 0.4"
}
},
+ "node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
@@ -12241,41 +12213,10 @@
"node": ">= 0.4"
}
},
- "node_modules/es-set-tostringtag": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
- "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.2.4",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
- "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.2.7",
- "is-date-object": "^1.0.5",
- "is-symbol": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/esbuild": {
- "version": "0.24.2",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
- "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
+ "version": "0.25.4",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
+ "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -12286,31 +12227,31 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.24.2",
- "@esbuild/android-arm": "0.24.2",
- "@esbuild/android-arm64": "0.24.2",
- "@esbuild/android-x64": "0.24.2",
- "@esbuild/darwin-arm64": "0.24.2",
- "@esbuild/darwin-x64": "0.24.2",
- "@esbuild/freebsd-arm64": "0.24.2",
- "@esbuild/freebsd-x64": "0.24.2",
- "@esbuild/linux-arm": "0.24.2",
- "@esbuild/linux-arm64": "0.24.2",
- "@esbuild/linux-ia32": "0.24.2",
- "@esbuild/linux-loong64": "0.24.2",
- "@esbuild/linux-mips64el": "0.24.2",
- "@esbuild/linux-ppc64": "0.24.2",
- "@esbuild/linux-riscv64": "0.24.2",
- "@esbuild/linux-s390x": "0.24.2",
- "@esbuild/linux-x64": "0.24.2",
- "@esbuild/netbsd-arm64": "0.24.2",
- "@esbuild/netbsd-x64": "0.24.2",
- "@esbuild/openbsd-arm64": "0.24.2",
- "@esbuild/openbsd-x64": "0.24.2",
- "@esbuild/sunos-x64": "0.24.2",
- "@esbuild/win32-arm64": "0.24.2",
- "@esbuild/win32-ia32": "0.24.2",
- "@esbuild/win32-x64": "0.24.2"
+ "@esbuild/aix-ppc64": "0.25.4",
+ "@esbuild/android-arm": "0.25.4",
+ "@esbuild/android-arm64": "0.25.4",
+ "@esbuild/android-x64": "0.25.4",
+ "@esbuild/darwin-arm64": "0.25.4",
+ "@esbuild/darwin-x64": "0.25.4",
+ "@esbuild/freebsd-arm64": "0.25.4",
+ "@esbuild/freebsd-x64": "0.25.4",
+ "@esbuild/linux-arm": "0.25.4",
+ "@esbuild/linux-arm64": "0.25.4",
+ "@esbuild/linux-ia32": "0.25.4",
+ "@esbuild/linux-loong64": "0.25.4",
+ "@esbuild/linux-mips64el": "0.25.4",
+ "@esbuild/linux-ppc64": "0.25.4",
+ "@esbuild/linux-riscv64": "0.25.4",
+ "@esbuild/linux-s390x": "0.25.4",
+ "@esbuild/linux-x64": "0.25.4",
+ "@esbuild/netbsd-arm64": "0.25.4",
+ "@esbuild/netbsd-x64": "0.25.4",
+ "@esbuild/openbsd-arm64": "0.25.4",
+ "@esbuild/openbsd-x64": "0.25.4",
+ "@esbuild/sunos-x64": "0.25.4",
+ "@esbuild/win32-arm64": "0.25.4",
+ "@esbuild/win32-ia32": "0.25.4",
+ "@esbuild/win32-x64": "0.25.4"
}
},
"node_modules/escalade": {
@@ -12559,6 +12500,16 @@
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -12659,9 +12610,9 @@
}
},
"node_modules/execa": {
- "version": "9.5.2",
- "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz",
- "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==",
+ "version": "9.5.3",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.3.tgz",
+ "integrity": "sha512-QFNnTvU3UjgWFy8Ef9iDHvIdcgZ344ebkwYx4/KLbR+CKQA4xBaHzv+iRpp86QfMHP8faFQLh8iOc57215y4Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12685,19 +12636,6 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "node_modules/execa/node_modules/@sindresorhus/merge-streams": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
- "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/execa/node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
@@ -12747,6 +12685,16 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/expect-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
+ "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/express": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.0.1.tgz",
@@ -12971,22 +12919,18 @@
"dev": true
},
"node_modules/fast-xml-parser": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz",
- "integrity": "sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w==",
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz",
+ "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/naturalintelligence"
}
],
"license": "MIT",
"dependencies": {
- "strnum": "^1.0.5"
+ "strnum": "^1.1.1"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -13019,6 +12963,16 @@
"bser": "2.1.1"
}
},
+ "node_modules/fd-package-json": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz",
+ "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "walk-up-path": "^3.0.1"
+ }
+ },
"node_modules/fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@@ -13219,15 +13173,6 @@
}
}
},
- "node_modules/for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.1.3"
- }
- },
"node_modules/foreground-child": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
@@ -13262,6 +13207,22 @@
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="
},
+ "node_modules/formatly": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.2.3.tgz",
+ "integrity": "sha512-WH01vbXEjh9L3bqn5V620xUAWs32CmK4IzWRRY6ep5zpa/mrisL4d9+pRVuETORVDTQw8OycSO1WC68PL51RaA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fd-package-json": "^1.2.0"
+ },
+ "bin": {
+ "formatly": "bin/index.mjs"
+ },
+ "engines": {
+ "node": ">=18.3.0"
+ }
+ },
"node_modules/formdata-node": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
@@ -13346,33 +13307,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/function.prototype.name": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
- "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "functions-have-names": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/fzf": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz",
@@ -13578,23 +13512,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/get-symbol-description": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
- "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/get-tsconfig": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
@@ -13630,9 +13547,9 @@
"optional": true
},
"node_modules/glob": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
- "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
+ "version": "11.0.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz",
+ "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -13696,22 +13613,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/globalthis": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
- "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
- "dev": true,
- "dependencies": {
- "define-properties": "^1.2.1",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/google-auth-library": {
"version": "9.15.0",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz",
@@ -13762,15 +13663,6 @@
"node": ">=14.0.0"
}
},
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -13780,33 +13672,6 @@
"node": ">=8"
}
},
- "node_modules/has-property-descriptors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
- "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
- "dev": true,
- "dependencies": {
- "es-define-property": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-proto": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
- "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
- "dev": true,
- "dependencies": {
- "dunder-proto": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -13818,21 +13683,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "dev": true,
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@@ -13849,12 +13699,6 @@
"node": ">= 0.4"
}
},
- "node_modules/hosted-git-info": {
- "version": "2.8.9",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
- "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
- "dev": true
- },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -13920,10 +13764,14 @@
}
},
"node_modules/human-id": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz",
- "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==",
- "dev": true
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz",
+ "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "human-id": "dist/cli.js"
+ }
},
"node_modules/human-signals": {
"version": "8.0.0",
@@ -14076,15 +13924,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -14108,20 +13947,6 @@
"license": "ISC",
"optional": true
},
- "node_modules/internal-slot": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
- "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
- "dev": true,
- "dependencies": {
- "es-errors": "^1.3.0",
- "hasown": "^2.0.0",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
@@ -14143,85 +13968,31 @@
"node": ">= 0.10"
}
},
- "node_modules/is-array-buffer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
- "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true
+ },
+ "node_modules/is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
+ "ci-info": "^2.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "bin": {
+ "is-ci": "bin.js"
}
},
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true
- },
- "node_modules/is-async-function": {
+ "node_modules/is-ci/node_modules/ci-info": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
- "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
- "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
- "dev": true,
- "dependencies": {
- "has-bigints": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz",
- "integrity": "sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
"dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
+ "license": "MIT"
},
"node_modules/is-core-module": {
"version": "2.15.1",
@@ -14238,36 +14009,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-data-view": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
- "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
- "dev": true,
- "dependencies": {
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-docker": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
@@ -14293,21 +14034,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-finalizationregistry": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz",
- "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -14325,21 +14051,6 @@
"node": ">=6"
}
},
- "node_modules/is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -14384,30 +14095,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-map": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
- "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
- "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-node-process": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
@@ -14424,22 +14111,6 @@
"node": ">=0.12.0"
}
},
- "node_modules/is-number-object": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz",
- "integrity": "sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -14479,51 +14150,6 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
- "node_modules/is-regex": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz",
- "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "gopd": "^1.1.0",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-set": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
- "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -14535,27 +14161,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-string": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz",
- "integrity": "sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-subdir": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz",
"integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"better-path-resolve": "1.0.0"
},
@@ -14563,38 +14174,6 @@
"node": ">=4"
}
},
- "node_modules/is-symbol": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.0.tgz",
- "integrity": "sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "has-symbols": "^1.0.3",
- "safe-regex-test": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-typed-array": {
- "version": "1.1.13",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
- "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
- "dev": true,
- "dependencies": {
- "which-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-unicode-supported": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
@@ -14608,51 +14187,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-weakmap": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
- "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakset": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
- "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -15704,12 +15244,6 @@
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true
},
- "node_modules/json-parse-better-errors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
- "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
- "dev": true
- },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -15878,9 +15412,9 @@
}
},
"node_modules/knip": {
- "version": "5.44.4",
- "resolved": "https://registry.npmjs.org/knip/-/knip-5.44.4.tgz",
- "integrity": "sha512-Ryn8LwWHLId8jSK1DgtT0hmg5DbzkqAtH+Gg3vZJpmSMgGHMspej9Ag+qKTm8wsPLDjVetuEz/lIsobo0XCMvQ==",
+ "version": "5.55.1",
+ "resolved": "https://registry.npmjs.org/knip/-/knip-5.55.1.tgz",
+ "integrity": "sha512-NYXjgGrXgMdabUKCP2TlBH/e83m9KnLc1VLyWHUtoRrCEJ/C15YtbafrpTvm3td+jE4VdDPgudvXT1IMtCx8lw==",
"dev": true,
"funding": [
{
@@ -15896,21 +15430,19 @@
"url": "https://polar.sh/webpro-nl"
}
],
+ "license": "ISC",
"dependencies": {
- "@nodelib/fs.walk": "3.0.1",
- "@snyk/github-codeowners": "1.1.0",
- "easy-table": "1.2.0",
- "enhanced-resolve": "^5.18.0",
+ "@nodelib/fs.walk": "^1.2.3",
+ "enhanced-resolve": "^5.18.1",
"fast-glob": "^3.3.3",
+ "formatly": "^0.2.3",
"jiti": "^2.4.2",
"js-yaml": "^4.1.0",
"minimist": "^1.2.8",
"picocolors": "^1.1.0",
"picomatch": "^4.0.1",
- "pretty-ms": "^9.0.0",
"smol-toml": "^1.3.1",
"strip-json-comments": "5.0.1",
- "summary": "2.1.0",
"zod": "^3.22.4",
"zod-validation-error": "^3.0.3"
},
@@ -15926,46 +15458,12 @@
"typescript": ">=5.0.4"
}
},
- "node_modules/knip/node_modules/@nodelib/fs.scandir": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-4.0.1.tgz",
- "integrity": "sha512-vAkI715yhnmiPupY+dq+xenu5Tdf2TBQ66jLvBIcCddtz+5Q8LbMKaf9CIJJreez8fQ8fgaY+RaywQx8RJIWpw==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "4.0.0",
- "run-parallel": "^1.2.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/knip/node_modules/@nodelib/fs.stat": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-4.0.0.tgz",
- "integrity": "sha512-ctr6bByzksKRCV0bavi8WoQevU6plSp2IkllIsEqaiKe2mwNNnaluhnRhcsgGZHrrHk57B3lf95MkLMO3STYcg==",
- "dev": true,
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/knip/node_modules/@nodelib/fs.walk": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-3.0.1.tgz",
- "integrity": "sha512-nIh/M6Kh3ZtOmlY00DaUYB4xeeV6F3/ts1l29iwl3/cfyY/OuCfUx+v08zgx8TKPTifXRcjjqVQ4KB2zOYSbyw==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "4.0.1",
- "fastq": "^1.15.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
"node_modules/knip/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -15978,6 +15476,7 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
"integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.16"
},
@@ -16034,21 +15533,22 @@
"dev": true
},
"node_modules/lint-staged": {
- "version": "15.2.11",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.11.tgz",
- "integrity": "sha512-Ev6ivCTYRTGs9ychvpVw35m/bcNDuBN+mnTeObCL5h+boS5WzBEC6LHI4I9F/++sZm1m+J2LEiy0gxL/R9TBqQ==",
- "dev": true,
- "dependencies": {
- "chalk": "~5.3.0",
- "commander": "~12.1.0",
- "debug": "~4.4.0",
- "execa": "~8.0.1",
- "lilconfig": "~3.1.3",
- "listr2": "~8.2.5",
- "micromatch": "~4.0.8",
- "pidtree": "~0.6.0",
- "string-argv": "~0.3.2",
- "yaml": "~2.6.1"
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz",
+ "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.4.1",
+ "commander": "^13.1.0",
+ "debug": "^4.4.0",
+ "execa": "^8.0.1",
+ "lilconfig": "^3.1.3",
+ "listr2": "^8.2.5",
+ "micromatch": "^4.0.8",
+ "pidtree": "^0.6.0",
+ "string-argv": "^0.3.2",
+ "yaml": "^2.7.0"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
@@ -16061,10 +15561,11 @@
}
},
"node_modules/lint-staged/node_modules/chalk": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
- "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
- "dev": true,
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+ "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
@@ -16073,10 +15574,11 @@
}
},
"node_modules/lint-staged/node_modules/commander": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
- "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
+ "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=18"
}
@@ -16086,6 +15588,7 @@
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^8.0.1",
@@ -16109,6 +15612,7 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=16"
},
@@ -16121,6 +15625,7 @@
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=16.17.0"
}
@@ -16130,6 +15635,7 @@
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -16142,6 +15648,7 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -16154,6 +15661,7 @@
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^4.0.0"
},
@@ -16169,6 +15677,7 @@
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mimic-fn": "^4.0.0"
},
@@ -16184,6 +15693,7 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -16191,23 +15701,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lint-staged/node_modules/pidtree": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
- "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
- "dev": true,
- "bin": {
- "pidtree": "bin/pidtree.js"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
"node_modules/lint-staged/node_modules/strip-final-newline": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -16284,43 +15783,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/load-json-file": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
- "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "parse-json": "^4.0.0",
- "pify": "^3.0.0",
- "strip-bom": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/load-json-file/node_modules/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dev": true,
- "dependencies": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/load-json-file/node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/load-tsconfig": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz",
@@ -16590,6 +16052,13 @@
"underscore": "^1.13.1"
}
},
+ "node_modules/loupe": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
+ "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -16610,6 +16079,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/magic-string": {
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
"node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
@@ -16641,9 +16120,10 @@
}
},
"node_modules/mammoth": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.8.0.tgz",
- "integrity": "sha512-pJNfxSk9IEGVpau+tsZFz22ofjUsl2mnA5eT8PjPs2n0BP+rhVte4Nez6FdgEuxv3IGI3afiV46ImKqTGDVlbA==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.9.0.tgz",
+ "integrity": "sha512-F+0NxzankQV9XSUAuVKvkdQK0GbtGGuqVnND9aVf9VSeUA82LQa29GjLqYU6Eez8LHqSJG3eGiDW3224OKdpZg==",
+ "license": "BSD-2-Clause",
"dependencies": {
"@xmldom/xmldom": "^0.8.6",
"argparse": "~1.0.3",
@@ -16651,7 +16131,7 @@
"bluebird": "~3.4.0",
"dingbat-to-unicode": "^1.0.1",
"jszip": "^3.7.1",
- "lop": "^0.4.1",
+ "lop": "^0.4.2",
"path-is-absolute": "^1.0.0",
"underscore": "^1.13.1",
"xmlbuilder": "^10.0.0"
@@ -16667,6 +16147,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
@@ -16674,7 +16155,8 @@
"node_modules/mammoth/node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
},
"node_modules/map-stream": {
"version": "0.1.0",
@@ -16941,6 +16423,25 @@
"thenify-all": "^1.0.0"
}
},
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/napi-build-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
@@ -16972,12 +16473,6 @@
"node": ">= 0.4.0"
}
},
- "node_modules/nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
- "dev": true
- },
"node_modules/nock": {
"version": "14.0.4",
"resolved": "https://registry.npmjs.org/nock/-/nock-14.0.4.tgz",
@@ -17139,27 +16634,6 @@
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
"license": "MIT"
},
- "node_modules/normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
- "dev": true,
- "dependencies": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "node_modules/normalize-package-data/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -17169,169 +16643,96 @@
"node": ">=0.10.0"
}
},
- "node_modules/npm-run-all": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
- "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
+ "node_modules/npm-normalize-package-bin": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
+ "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/npm-run-all2": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.1.tgz",
+ "integrity": "sha512-jkhE0AsELQeCtScrcJ/7mSIdk+ZsnWjvKk3KwE96HZ6+OFVB74XhxQtHT1W6kdUfn92fRnBb29Mz82j9bV2XEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ansi-styles": "^3.2.1",
- "chalk": "^2.4.1",
- "cross-spawn": "^6.0.5",
+ "ansi-styles": "^6.2.1",
+ "cross-spawn": "^7.0.6",
"memorystream": "^0.3.1",
- "minimatch": "^3.0.4",
- "pidtree": "^0.3.0",
- "read-pkg": "^3.0.0",
- "shell-quote": "^1.6.1",
- "string.prototype.padend": "^3.0.0"
+ "minimatch": "^10.0.1",
+ "pidtree": "^0.6.0",
+ "read-package-json-fast": "^4.0.0",
+ "shell-quote": "^1.7.3",
+ "which": "^5.0.0"
},
"bin": {
"npm-run-all": "bin/npm-run-all/index.js",
+ "npm-run-all2": "bin/npm-run-all/index.js",
"run-p": "bin/run-p/index.js",
"run-s": "bin/run-s/index.js"
},
"engines": {
- "node": ">= 4"
- }
- },
- "node_modules/npm-run-all/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/npm-run-all/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "node": "^20.5.0 || >=22.0.0",
+ "npm": ">= 10"
}
},
- "node_modules/npm-run-all/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "node_modules/npm-run-all2/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=4"
- }
- },
- "node_modules/npm-run-all/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/npm-run-all/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/npm-run-all/node_modules/cross-spawn": {
- "version": "6.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
- "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
- "dev": true,
- "dependencies": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
+ "node": ">=12"
},
- "engines": {
- "node": ">=4.8"
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/npm-run-all/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "node_modules/npm-run-all2/node_modules/isexe": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+ "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
"dev": true,
+ "license": "ISC",
"engines": {
- "node": ">=0.8.0"
+ "node": ">=16"
}
},
- "node_modules/npm-run-all/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "node_modules/npm-run-all2/node_modules/minimatch": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
+ "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
- }
- },
- "node_modules/npm-run-all/node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/npm-run-all/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/npm-run-all/node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^1.0.0"
+ "node": "20 || >=22"
},
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/npm-run-all/node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/npm-run-all/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "node_modules/npm-run-all2/node_modules/which": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
+ "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "isexe": "^2.0.0"
+ "isexe": "^3.1.1"
},
"bin": {
- "which": "bin/which"
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/npm-run-path": {
@@ -17408,15 +16809,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/object-treeify": {
"version": "1.1.33",
"resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz",
@@ -17427,24 +16819,6 @@
"node": ">= 10"
}
},
- "node_modules/object.assign": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
- "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -17665,25 +17039,73 @@
"dev": true,
"license": "MIT"
},
- "node_modules/p-filter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
- "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
+ "node_modules/ovsx": {
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.2.tgz",
+ "integrity": "sha512-osLwIOz5Uu1ePvYYSjKw05bkCZo2j/ydQLjm3uO7bCfstyFFzmWyzMGTAL3wJpI4qpo1S47Y52+q09h9A2ZRkQ==",
"dev": true,
+ "license": "EPL-2.0",
"dependencies": {
- "p-map": "^2.0.0"
+ "@vscode/vsce": "^3.2.1",
+ "commander": "^6.2.1",
+ "follow-redirects": "^1.14.6",
+ "is-ci": "^2.0.0",
+ "leven": "^3.1.0",
+ "semver": "^7.6.0",
+ "tmp": "^0.2.3",
+ "yauzl": "^3.1.3"
+ },
+ "bin": {
+ "ovsx": "lib/ovsx"
},
"engines": {
- "node": ">=8"
+ "node": ">= 20"
}
},
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "node_modules/ovsx/node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/ovsx/node_modules/yauzl": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz",
+ "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "pend": "~1.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/p-filter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
+ "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-map": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
@@ -17712,6 +17134,7 @@
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -17969,6 +17392,23 @@
"node": ">=16"
}
},
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathval": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+ "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
"node_modules/pause-stream": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
@@ -18025,10 +17465,11 @@
}
},
"node_modules/pidtree": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
- "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
+ "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
"dev": true,
+ "license": "MIT",
"bin": {
"pidtree": "bin/pidtree.js"
},
@@ -18036,15 +17477,6 @@
"node": ">=0.10"
}
},
- "node_modules/pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/pirates": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
@@ -18127,13 +17559,33 @@
"node": ">=8"
}
},
- "node_modules/possible-typed-array-names": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
- "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "node_modules/postcss": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
+ "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"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-load-config": {
@@ -18180,11 +17632,12 @@
}
},
"node_modules/posthog-node": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.7.0.tgz",
- "integrity": "sha512-RgdUKSW8MfMOkjUa8cYVqWndNjPePNuuxlGbrZC6z1WRBsVc6TdGl8caidmC10RW8mu/BOfmrGbP4cRTo2jARg==",
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.17.1.tgz",
+ "integrity": "sha512-cVlQPOwOPjakUnrueKRCQe1m2Ku+XzKaOos7Tn/zDZkkZFeBT/byP7tbNf7LiwhaBRWFBRowZZb/MsTtSRaorg==",
+ "license": "MIT",
"dependencies": {
- "axios": "^1.7.4"
+ "axios": "^1.8.2"
},
"engines": {
"node": ">=15.0.0"
@@ -18276,10 +17729,11 @@
}
},
"node_modules/prettier": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
- "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -18658,30 +18112,28 @@
"node": ">=0.8"
}
},
- "node_modules/read-pkg": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
- "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
+ "node_modules/read-package-json-fast": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz",
+ "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "load-json-file": "^4.0.0",
- "normalize-package-data": "^2.3.2",
- "path-type": "^3.0.0"
+ "json-parse-even-better-errors": "^4.0.0",
+ "npm-normalize-package-bin": "^4.0.0"
},
"engines": {
- "node": ">=4"
+ "node": "^18.17.0 || >=20.5.0"
}
},
- "node_modules/read-pkg/node_modules/path-type": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
- "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz",
+ "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==",
"dev": true,
- "dependencies": {
- "pify": "^3.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=4"
+ "node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/read-yaml-file": {
@@ -18785,51 +18237,11 @@
"node": ">=12.0.0"
}
},
- "node_modules/reflect.getprototypeof": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz",
- "integrity": "sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "dunder-proto": "^1.0.0",
- "es-abstract": "^1.23.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.2.0",
- "which-builtin-type": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
- "node_modules/regexp.prototype.flags": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
- "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-errors": "^1.3.0",
- "set-function-name": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -19062,30 +18474,6 @@
"queue-microtask": "^1.2.2"
}
},
- "node_modules/safe-array-concat": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
- "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4",
- "has-symbols": "^1.0.3",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">=0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safe-array-concat/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -19105,28 +18493,20 @@
}
]
},
- "node_modules/safe-regex-test": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
- "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-regex": "^1.1.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "node_modules/sanitize-filename": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
+ "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
+ "license": "WTFPL OR ISC",
+ "dependencies": {
+ "truncate-utf8-bytes": "^1.0.0"
+ }
+ },
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
@@ -19153,9 +18533,10 @@
"peer": true
},
"node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -19235,38 +18616,6 @@
"node": ">= 18"
}
},
- "node_modules/set-function-length": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
- "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
- "dev": true,
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-function-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
- "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
- "dev": true,
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "functions-have-names": "^1.2.3",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
@@ -19392,6 +18741,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
@@ -19574,6 +18930,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-support": {
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
@@ -19594,38 +18960,6 @@
"signal-exit": "^4.0.1"
}
},
- "node_modules/spdx-correct": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
- "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
- "dev": true,
- "dependencies": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-exceptions": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
- "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
- "dev": true
- },
- "node_modules/spdx-expression-parse": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
- "dev": true,
- "dependencies": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "node_modules/spdx-license-ids": {
- "version": "3.0.20",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz",
- "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==",
- "dev": true
- },
"node_modules/split": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
@@ -19664,6 +18998,13 @@
"node": ">=8"
}
},
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -19673,6 +19014,13 @@
"node": ">= 0.8"
}
},
+ "node_modules/std-env": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
+ "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/stdin-discarder": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
@@ -19853,73 +19201,6 @@
"node": ">=8"
}
},
- "node_modules/string.prototype.padend": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz",
- "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trim": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
- "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
- "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
- "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
@@ -19995,9 +19276,16 @@
}
},
"node_modules/strnum": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
- "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz",
+ "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
},
"node_modules/strong-type": {
"version": "1.1.0",
@@ -20102,12 +19390,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/summary": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz",
- "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==",
- "dev": true
- },
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -20303,6 +19585,13 @@
"integrity": "sha512-/kqtlepLMptX0OgbYD9aMYbM7EFrMZCL7EoHM8Psmg2FuhXoo/bH64KqOiZGGwa6oS9TPdSEDKBnV2LuB8+5vQ==",
"license": "MIT"
},
+ "node_modules/tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/tinyexec": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
@@ -20311,13 +19600,13 @@
"license": "MIT"
},
"node_modules/tinyglobby": {
- "version": "0.2.12",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
- "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
+ "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "fdir": "^6.4.3",
+ "fdir": "^6.4.4",
"picomatch": "^4.0.2"
},
"engines": {
@@ -20328,9 +19617,9 @@
}
},
"node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.4.3",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
- "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@@ -20355,6 +19644,36 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/tinypool": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+ "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/tmp": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
@@ -20414,6 +19733,15 @@
"tree-sitter-wasms": "^0.1.11"
}
},
+ "node_modules/truncate-utf8-bytes": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
+ "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==",
+ "license": "WTFPL",
+ "dependencies": {
+ "utf8-byte-length": "^1.0.1"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
@@ -20434,10 +19762,11 @@
"license": "Apache-2.0"
},
"node_modules/ts-jest": {
- "version": "29.2.5",
- "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz",
- "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==",
+ "version": "29.3.2",
+ "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.2.tgz",
+ "integrity": "sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"bs-logger": "^0.2.6",
"ejs": "^3.1.10",
@@ -20446,7 +19775,8 @@
"json5": "^2.2.3",
"lodash.memoize": "^4.1.2",
"make-error": "^1.3.6",
- "semver": "^7.6.3",
+ "semver": "^7.7.1",
+ "type-fest": "^4.39.1",
"yargs-parser": "^21.1.1"
},
"bin": {
@@ -20481,6 +19811,19 @@
}
}
},
+ "node_modules/ts-jest/node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -20538,516 +19881,50 @@
}
}
},
- "node_modules/tsup/node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
- "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/android-arm": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
- "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/android-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
- "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/android-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
- "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
- "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/darwin-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
- "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
- "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
- "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/linux-arm": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
- "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/linux-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
- "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/linux-ia32": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
- "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/linux-loong64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
- "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
- "cpu": [
- "loong64"
- ],
+ "node_modules/tsup/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
"engines": {
- "node": ">=18"
+ "node": ">=8"
}
},
- "node_modules/tsup/node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
- "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
- "cpu": [
- "mips64el"
- ],
+ "node_modules/tsup/node_modules/source-map": {
+ "version": "0.8.0-beta.0",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
+ "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "whatwg-url": "^7.0.0"
+ },
"engines": {
- "node": ">=18"
+ "node": ">= 8"
}
},
- "node_modules/tsup/node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
- "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
- "cpu": [
- "ppc64"
- ],
+ "node_modules/tsup/node_modules/tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "punycode": "^2.1.0"
}
},
- "node_modules/tsup/node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
- "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
- "cpu": [
- "riscv64"
- ],
+ "node_modules/tsup/node_modules/webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
+ "license": "BSD-2-Clause"
},
- "node_modules/tsup/node_modules/@esbuild/linux-s390x": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
- "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/linux-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
- "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
- "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
- "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
- "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
- "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/sunos-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
- "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/win32-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
- "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/win32-ia32": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
- "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/@esbuild/win32-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
- "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsup/node_modules/esbuild": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
- "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.1",
- "@esbuild/android-arm": "0.25.1",
- "@esbuild/android-arm64": "0.25.1",
- "@esbuild/android-x64": "0.25.1",
- "@esbuild/darwin-arm64": "0.25.1",
- "@esbuild/darwin-x64": "0.25.1",
- "@esbuild/freebsd-arm64": "0.25.1",
- "@esbuild/freebsd-x64": "0.25.1",
- "@esbuild/linux-arm": "0.25.1",
- "@esbuild/linux-arm64": "0.25.1",
- "@esbuild/linux-ia32": "0.25.1",
- "@esbuild/linux-loong64": "0.25.1",
- "@esbuild/linux-mips64el": "0.25.1",
- "@esbuild/linux-ppc64": "0.25.1",
- "@esbuild/linux-riscv64": "0.25.1",
- "@esbuild/linux-s390x": "0.25.1",
- "@esbuild/linux-x64": "0.25.1",
- "@esbuild/netbsd-arm64": "0.25.1",
- "@esbuild/netbsd-x64": "0.25.1",
- "@esbuild/openbsd-arm64": "0.25.1",
- "@esbuild/openbsd-x64": "0.25.1",
- "@esbuild/sunos-x64": "0.25.1",
- "@esbuild/win32-arm64": "0.25.1",
- "@esbuild/win32-ia32": "0.25.1",
- "@esbuild/win32-x64": "0.25.1"
- }
- },
- "node_modules/tsup/node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/tsup/node_modules/source-map": {
- "version": "0.8.0-beta.0",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
- "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "whatwg-url": "^7.0.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/tsup/node_modules/tr46": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
- "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/tsup/node_modules/webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true,
- "license": "BSD-2-Clause"
- },
- "node_modules/tsup/node_modules/whatwg-url": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
- "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "node_modules/tsup/node_modules/whatwg-url": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+ "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -21056,490 +19933,24 @@
"webidl-conversions": "^4.0.2"
}
},
- "node_modules/tsx": {
- "version": "4.19.3",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz",
- "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "esbuild": "~0.25.0",
- "get-tsconfig": "^4.7.5"
- },
- "bin": {
- "tsx": "dist/cli.mjs"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
- "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/android-arm": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
- "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/android-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
- "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/android-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
- "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
- "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
- "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
- "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
- "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-arm": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
- "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
- "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
- "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
- "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
- "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
- "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
- "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
- "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/linux-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
- "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
- "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
- "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
- "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
- "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
- "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
- "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
- "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/@esbuild/win32-x64": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
- "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/tsx/node_modules/esbuild": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
- "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
+ "node_modules/tsx": {
+ "version": "4.19.4",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.4.tgz",
+ "integrity": "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==",
"dev": true,
- "hasInstallScript": true,
"license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.25.0",
+ "get-tsconfig": "^4.7.5"
+ },
"bin": {
- "esbuild": "bin/esbuild"
+ "tsx": "dist/cli.mjs"
},
"engines": {
- "node": ">=18"
+ "node": ">=18.0.0"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.1",
- "@esbuild/android-arm": "0.25.1",
- "@esbuild/android-arm64": "0.25.1",
- "@esbuild/android-x64": "0.25.1",
- "@esbuild/darwin-arm64": "0.25.1",
- "@esbuild/darwin-x64": "0.25.1",
- "@esbuild/freebsd-arm64": "0.25.1",
- "@esbuild/freebsd-x64": "0.25.1",
- "@esbuild/linux-arm": "0.25.1",
- "@esbuild/linux-arm64": "0.25.1",
- "@esbuild/linux-ia32": "0.25.1",
- "@esbuild/linux-loong64": "0.25.1",
- "@esbuild/linux-mips64el": "0.25.1",
- "@esbuild/linux-ppc64": "0.25.1",
- "@esbuild/linux-riscv64": "0.25.1",
- "@esbuild/linux-s390x": "0.25.1",
- "@esbuild/linux-x64": "0.25.1",
- "@esbuild/netbsd-arm64": "0.25.1",
- "@esbuild/netbsd-x64": "0.25.1",
- "@esbuild/openbsd-arm64": "0.25.1",
- "@esbuild/openbsd-x64": "0.25.1",
- "@esbuild/sunos-x64": "0.25.1",
- "@esbuild/win32-arm64": "0.25.1",
- "@esbuild/win32-ia32": "0.25.1",
- "@esbuild/win32-x64": "0.25.1"
+ "fsevents": "~2.3.3"
}
},
"node_modules/tunnel": {
@@ -21642,80 +20053,6 @@
"node": ">= 0.6"
}
},
- "node_modules/typed-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
- "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/typed-array-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
- "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-byte-offset": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz",
- "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==",
- "dev": true,
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13",
- "reflect.getprototypeof": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-length": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
- "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0",
- "reflect.getprototypeof": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/typed-query-selector": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz",
@@ -21734,10 +20071,11 @@
}
},
"node_modules/typescript": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
- "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -21746,21 +20084,6 @@
"node": ">=14.17"
}
},
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/unbzip2-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
@@ -21866,6 +20189,12 @@
"resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz",
"integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg=="
},
+ "node_modules/utf8-byte-length": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
+ "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==",
+ "license": "(WTFPL OR MIT)"
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -21906,16 +20235,6 @@
"node": ">=10.12.0"
}
},
- "node_modules/validate-npm-package-license": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
- "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
- "dev": true,
- "dependencies": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -21925,12 +20244,216 @@
"node": ">= 0.8"
}
},
+ "node_modules/vite": {
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
+ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-node": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.3.tgz",
+ "integrity": "sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.0",
+ "es-module-lexer": "^1.7.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vite/node_modules/fdir": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.3.tgz",
+ "integrity": "sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "3.1.3",
+ "@vitest/mocker": "3.1.3",
+ "@vitest/pretty-format": "^3.1.3",
+ "@vitest/runner": "3.1.3",
+ "@vitest/snapshot": "3.1.3",
+ "@vitest/spy": "3.1.3",
+ "@vitest/utils": "3.1.3",
+ "chai": "^5.2.0",
+ "debug": "^4.4.0",
+ "expect-type": "^1.2.1",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3",
+ "std-env": "^3.9.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.2",
+ "tinyglobby": "^0.2.13",
+ "tinypool": "^1.0.2",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0",
+ "vite-node": "3.1.3",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/debug": "^4.1.12",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@vitest/browser": "3.1.3",
+ "@vitest/ui": "3.1.3",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/debug": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vscode-material-icons": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/vscode-material-icons/-/vscode-material-icons-0.1.1.tgz",
"integrity": "sha512-GsoEEF8Tbb0yUFQ6N6FPvh11kFkL9F95x0FkKlbbfRQN9eFms67h+L3t6b9cUv58dSn2gu8kEhNfoESVCrz4ag==",
"license": "MIT"
},
+ "node_modules/walk-up-path": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz",
+ "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
@@ -21940,16 +20463,6 @@
"makeerror": "1.0.12"
}
},
- "node_modules/wcwidth": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
- "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "defaults": "^1.0.3"
- }
- },
"node_modules/web-streams-polyfill": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
@@ -22010,93 +20523,21 @@
"node": ">= 8"
}
},
- "node_modules/which-boxed-primitive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz",
- "integrity": "sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==",
- "dev": true,
- "dependencies": {
- "is-bigint": "^1.1.0",
- "is-boolean-object": "^1.2.0",
- "is-number-object": "^1.1.0",
- "is-string": "^1.1.0",
- "is-symbol": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-builtin-type": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz",
- "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "function.prototype.name": "^1.1.6",
- "has-tostringtag": "^1.0.2",
- "is-async-function": "^2.0.0",
- "is-date-object": "^1.0.5",
- "is-finalizationregistry": "^1.1.0",
- "is-generator-function": "^1.0.10",
- "is-regex": "^1.1.4",
- "is-weakref": "^1.0.2",
- "isarray": "^2.0.5",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.2",
- "which-typed-array": "^1.1.15"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-builtin-type/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- },
- "node_modules/which-collection": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
- "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "is-map": "^2.0.3",
- "is-set": "^2.0.3",
- "is-weakmap": "^2.0.2",
- "is-weakset": "^2.0.3"
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
},
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-typed-array": {
- "version": "1.1.16",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz",
- "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==",
- "dev": true,
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-tostringtag": "^1.0.2"
+ "bin": {
+ "why-is-node-running": "cli.js"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
"node_modules/wide-align": {
@@ -22457,10 +20898,11 @@
"dev": true
},
"node_modules/yaml": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
- "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+ "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"dev": true,
+ "license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
@@ -22575,13 +21017,23 @@
}
},
"node_modules/zod": {
- "version": "3.23.8",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
- "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
+ "version": "3.24.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz",
+ "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==",
+ "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
+ "node_modules/zod-to-json-schema": {
+ "version": "3.24.5",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
+ "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.24.1"
+ }
+ },
"node_modules/zod-to-ts": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz",
diff --git a/package.json b/package.json
index 6b3db19a012..35e4f36913e 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "PearAI's integration of Roo Code / Cline, a coding agent.",
"publisher": "PearAI",
"icon": "assets/icons/pear.png",
- "version": "3.15.3",
+ "version": "3.17.2",
"galleryBanner": {
"color": "#617A91",
"theme": "dark"
@@ -110,11 +110,6 @@
"title": "%command.settings.title%",
"icon": "$(settings-gear)"
},
- {
- "command": "roo-cline.helpButtonClicked",
- "title": "%command.documentation.title%",
- "icon": "$(question)"
- },
{
"command": "roo-cline.openInNewTab",
"title": "%command.openInNewTab.title%",
@@ -283,11 +278,6 @@
"command": "roo-cline.settingsButtonClicked",
"group": "navigation@6",
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
- },
- {
- "command": "roo-cline.helpButtonClicked",
- "group": "navigation@7",
- "when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
}
]
},
@@ -336,7 +326,7 @@
"build:webview": "cd webview-ui && npm run build",
"build:esbuild": "node esbuild.js --production",
"compile": "tsc -p . --outDir out && node esbuild.js",
- "install:all": "npm install npm-run-all && npm-run-all -l -p install-*",
+ "install:all": "npm install -D npm-run-all2@8.0.1 && npm-run-all -l -p install-*",
"install-extension": "npm install",
"install-webview": "cd webview-ui && npm install",
"install-e2e": "cd e2e && npm install",
@@ -351,11 +341,12 @@
"package": "npm-run-all -l -p build:webview build:esbuild check-types lint",
"pretest": "npm run compile",
"dev": "cd webview-ui && npm run dev -- --port 5174",
- "test": "node scripts/run-tests.js",
+ "test": "npm-run-all test:*",
"test:extension": "jest -w=40%",
+ "test:extension-esm": "vitest run",
"test:webview": "cd webview-ui && npm run test",
"prepare": "husky",
- "publish:marketplace": "vsce publish && ovsx publish",
+ "publish:marketplace": "npx vsce publish && npx ovsx publish",
"publish": "npm run build && changeset publish && npm install --package-lock-only",
"version-packages": "changeset version && npm install --package-lock-only",
"vscode:prepublish": "npm run package",
@@ -381,9 +372,9 @@
"@anthropic-ai/sdk": "^0.37.0",
"@anthropic-ai/vertex-sdk": "^0.7.0",
"@aws-sdk/client-bedrock-runtime": "^3.779.0",
- "@google/genai": "^0.9.0",
+ "@google/genai": "^0.13.0",
"@mistralai/mistralai": "^1.3.6",
- "@modelcontextprotocol/sdk": "^1.7.0",
+ "@modelcontextprotocol/sdk": "^1.9.0",
"@pearai/core": "file:./../pearai-submodule/core",
"@types/clone-deep": "^4.0.4",
"@types/pdf-parse": "^1.1.4",
@@ -422,6 +413,7 @@
"puppeteer-core": "^23.4.0",
"react-tooltip": "^5.28.0",
"reconnecting-eventsource": "^1.6.4",
+ "sanitize-filename": "^1.6.3",
"say": "^0.16.0",
"serialize-error": "^11.0.3",
"simple-git": "^3.27.0",
@@ -436,7 +428,7 @@
"vscode-material-icons": "^0.1.1",
"web-tree-sitter": "^0.22.6",
"workerpool": "^9.2.0",
- "zod": "^3.23.8"
+ "zod": "^3.24.2"
},
"devDependencies": {
"@changesets/cli": "^2.27.10",
@@ -456,8 +448,8 @@
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.11.0",
"@vscode/test-electron": "^2.5.2",
- "@vscode/vsce": "^3.3.2",
- "esbuild": "^0.24.0",
+ "@vscode/vsce": "3.3.2",
+ "esbuild": "^0.25.0",
"eslint": "^8.57.0",
"execa": "^9.5.2",
"glob": "^11.0.1",
@@ -468,13 +460,15 @@
"lint-staged": "^15.2.11",
"mkdirp": "^3.0.1",
"nock": "^14.0.4",
- "npm-run-all": "^4.1.5",
+ "npm-run-all2": "^8.0.1",
+ "ovsx": "0.10.2",
"prettier": "^3.4.2",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.5",
"tsup": "^8.4.0",
"tsx": "^4.19.3",
- "typescript": "^5.4.5",
+ "typescript": "5.8.3",
+ "vitest": "^3.1.3",
"zod-to-ts": "^1.2.0"
},
"lint-staged": {
diff --git a/package.nls.nl.json b/package.nls.nl.json
new file mode 100644
index 00000000000..8cd0b0e71f8
--- /dev/null
+++ b/package.nls.nl.json
@@ -0,0 +1,31 @@
+{
+ "extension.displayName": "Roo Code (voorheen Roo Cline)",
+ "extension.description": "Een compleet ontwikkelteam van AI-agents in je editor.",
+ "views.contextMenu.label": "Roo Code",
+ "views.terminalMenu.label": "Roo Code",
+ "views.activitybar.title": "Roo Code",
+ "command.newTask.title": "Nieuwe Taak",
+ "command.mcpServers.title": "MCP Servers",
+ "command.prompts.title": "Prompts",
+ "command.history.title": "Geschiedenis",
+ "command.openInEditor.title": "Openen in Editor",
+ "command.settings.title": "Instellingen",
+ "command.documentation.title": "Documentatie",
+ "command.openInNewTab.title": "Openen in Nieuw Tabblad",
+ "command.explainCode.title": "Leg Code Uit",
+ "command.fixCode.title": "Repareer Code",
+ "command.improveCode.title": "Verbeter Code",
+ "command.addToContext.title": "Toevoegen aan Context",
+ "command.focusInput.title": "Focus op Invoerveld",
+ "command.setCustomStoragePath.title": "Aangepast Opslagpad Instellen",
+ "command.terminal.addToContext.title": "Terminalinhoud aan Context Toevoegen",
+ "command.terminal.fixCommand.title": "Repareer Dit Commando",
+ "command.terminal.explainCommand.title": "Leg Dit Commando Uit",
+ "command.acceptInput.title": "Invoer/Suggestie Accepteren",
+ "configuration.title": "Roo Code",
+ "commands.allowedCommands.description": "Commando's die automatisch kunnen worden uitgevoerd wanneer 'Altijd goedkeuren uitvoerbewerkingen' is ingeschakeld",
+ "settings.vsCodeLmModelSelector.description": "Instellingen voor VSCode Language Model API",
+ "settings.vsCodeLmModelSelector.vendor.description": "De leverancier van het taalmodel (bijv. copilot)",
+ "settings.vsCodeLmModelSelector.family.description": "De familie van het taalmodel (bijv. gpt-4)",
+ "settings.customStoragePath.description": "Aangepast opslagpad. Laat leeg om de standaardlocatie te gebruiken. Ondersteunt absolute paden (bijv. 'D:\\RooCodeStorage')"
+}
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 00000000000..ac084260c3c
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": ["config:recommended"]
+}
diff --git a/scripts/generate-types.mts b/scripts/generate-types.mts
index 2ad167b0d8f..141df12ee1d 100644
--- a/scripts/generate-types.mts
+++ b/scripts/generate-types.mts
@@ -1,9 +1,11 @@
-import fs from "fs/promises"
+import path from "path"
+import fs from "fs"
import { zodToTs, createTypeAlias, printNode } from "zod-to-ts"
import { $ } from "execa"
import schemas from "../src/schemas"
+
const { typeDefinitions } = schemas
async function main() {
@@ -16,12 +18,17 @@ async function main() {
types.push(`export type { ${identifier} }`)
}
- await fs.writeFile("src/exports/types.ts", types.join("\n\n"))
+ fs.writeFileSync("src/exports/types.ts", types.join("\n\n"))
- await $`npx tsup src/exports/interface.ts --dts-only -d out`
- await fs.copyFile('out/interface.d.ts', 'src/exports/roo-code.d.ts')
+ await $`npx tsup src/exports/interface.ts --dts -d out`
+ fs.copyFileSync("out/interface.d.ts", "src/exports/roo-code.d.ts")
await $`npx prettier --write src/exports/types.ts src/exports/roo-code.d.ts`
+
+ if (fs.existsSync(path.join("..", "Roo-Code-Types"))) {
+ fs.copyFileSync("out/interface.js", path.join("..", "Roo-Code-Types", "src", "index.js"))
+ fs.copyFileSync("out/interface.d.ts", path.join("..", "Roo-Code-Types", "src", "index.d.ts"))
+ }
}
main()
diff --git a/scripts/run-tests.js b/scripts/run-tests.js
deleted file mode 100644
index 9ea8a835dd2..00000000000
--- a/scripts/run-tests.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-tests.js
-const { execSync } = require("child_process")
-
-if (process.platform === "win32") {
- execSync("npm-run-all test:*", { stdio: "inherit" })
-} else {
- execSync("npm-run-all -p test:*", { stdio: "inherit" })
-}
diff --git a/src/core/CodeActionProvider.ts b/src/activate/CodeActionProvider.ts
similarity index 97%
rename from src/core/CodeActionProvider.ts
rename to src/activate/CodeActionProvider.ts
index f749987d7e6..5f37d0320a3 100644
--- a/src/core/CodeActionProvider.ts
+++ b/src/activate/CodeActionProvider.ts
@@ -1,6 +1,6 @@
import * as vscode from "vscode"
-import { EditorUtils } from "./EditorUtils"
+import { EditorUtils } from "../integrations/editor/EditorUtils"
export type CodeActionName = "EXPLAIN" | "FIX" | "IMPROVE" | "ADD_TO_CONTEXT" | "NEW_TASK"
diff --git a/src/core/__tests__/CodeActionProvider.test.ts b/src/activate/__tests__/CodeActionProvider.test.ts
similarity index 91%
rename from src/core/__tests__/CodeActionProvider.test.ts
rename to src/activate/__tests__/CodeActionProvider.test.ts
index 1d6b84f09d6..1a56ad899f3 100644
--- a/src/core/__tests__/CodeActionProvider.test.ts
+++ b/src/activate/__tests__/CodeActionProvider.test.ts
@@ -1,12 +1,11 @@
-// npx jest src/core/__tests__/CodeActionProvider.test.ts
+// npx jest src/activate/__tests__/CodeActionProvider.test.ts
import * as vscode from "vscode"
-import { EditorUtils } from "../EditorUtils"
+import { EditorUtils } from "../../integrations/editor/EditorUtils"
import { CodeActionProvider, ACTION_TITLES } from "../CodeActionProvider"
-// Mock VSCode API
jest.mock("vscode", () => ({
CodeAction: jest.fn().mockImplementation((title, kind) => ({
title,
@@ -29,8 +28,7 @@ jest.mock("vscode", () => ({
},
}))
-// Mock EditorUtils
-jest.mock("../EditorUtils", () => ({
+jest.mock("../../integrations/editor/EditorUtils", () => ({
EditorUtils: {
getEffectiveRange: jest.fn(),
getFilePath: jest.fn(),
@@ -48,7 +46,6 @@ describe("CodeActionProvider", () => {
beforeEach(() => {
provider = new CodeActionProvider()
- // Mock document
mockDocument = {
getText: jest.fn(),
lineAt: jest.fn(),
@@ -56,15 +53,9 @@ describe("CodeActionProvider", () => {
uri: { fsPath: "/test/file.ts" },
}
- // Mock range
mockRange = new vscode.Range(0, 0, 0, 10)
- // Mock context
- mockContext = {
- diagnostics: [],
- }
-
- // Setup default EditorUtils mocks
+ mockContext = { diagnostics: [] }
;(EditorUtils.getEffectiveRange as jest.Mock).mockReturnValue({
range: mockRange,
text: "test code",
@@ -106,6 +97,7 @@ describe("CodeActionProvider", () => {
it("should handle errors gracefully", () => {
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {})
+
;(EditorUtils.getEffectiveRange as jest.Mock).mockImplementation(() => {
throw new Error("Test error")
})
diff --git a/src/activate/handleTask.ts b/src/activate/handleTask.ts
index 0f99380df58..6f9d35c26f2 100644
--- a/src/activate/handleTask.ts
+++ b/src/activate/handleTask.ts
@@ -1,9 +1,11 @@
import * as vscode from "vscode"
-import { COMMAND_IDS } from "../core/CodeActionProvider"
import { ClineProvider } from "../core/webview/ClineProvider"
+
import { t } from "../i18n"
+import { COMMAND_IDS } from "./CodeActionProvider"
+
export const handleNewTask = async (params: { prompt?: string } | null | undefined) => {
let prompt = params?.prompt
diff --git a/src/activate/index.ts b/src/activate/index.ts
index 2fff46a5f04..74f82af9d15 100644
--- a/src/activate/index.ts
+++ b/src/activate/index.ts
@@ -3,3 +3,4 @@ export { registerCommands } from "./registerCommands"
export { registerCodeActions } from "./registerCodeActions"
export { registerTerminalActions } from "./registerTerminalActions"
export { registerPearListener } from "./registerPearListener"
+export { CodeActionProvider } from "./CodeActionProvider"
diff --git a/src/activate/registerCodeActions.ts b/src/activate/registerCodeActions.ts
index b1c15f19e43..7af28076a78 100644
--- a/src/activate/registerCodeActions.ts
+++ b/src/activate/registerCodeActions.ts
@@ -1,9 +1,10 @@
import * as vscode from "vscode"
-import { type CodeActionName, type CodeActionId, COMMAND_IDS } from "../core/CodeActionProvider"
-import { EditorUtils } from "../core/EditorUtils"
+import { EditorUtils } from "../integrations/editor/EditorUtils"
import { ClineProvider } from "../core/webview/ClineProvider"
+import { type CodeActionName, type CodeActionId, COMMAND_IDS } from "./CodeActionProvider"
+
export const registerCodeActions = (context: vscode.ExtensionContext) => {
registerCodeAction(context, COMMAND_IDS.EXPLAIN, "EXPLAIN")
registerCodeAction(context, COMMAND_IDS.FIX, "FIX")
diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts
index d3a16c8b618..bb46d2e010f 100644
--- a/src/activate/registerCommands.ts
+++ b/src/activate/registerCommands.ts
@@ -116,6 +116,8 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
telemetryService.captureTitleButtonClicked("settings")
visibleProvider.postMessageToWebview({ type: "action", action: "settingsButtonClicked" })
+ // Also explicitly post the visibility message to trigger scroll reliably
+ visibleProvider.postMessageToWebview({ type: "action", action: "didBecomeVisible" })
},
"roo-cline.historyButtonClicked": () => {
const visibleProvider = getVisibleProviderOrLog(outputChannel)
@@ -128,11 +130,6 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
visibleProvider.postMessageToWebview({ type: "action", action: "historyButtonClicked" })
},
- "roo-cline.helpButtonClicked": () => {
- telemetryService.captureTitleButtonClicked("help")
-
- vscode.env.openExternal(vscode.Uri.parse("https://docs.roocode.com"))
- },
"roo-cline.showHumanRelayDialog": (params: { requestId: string; promptText: string }) => {
const panel = getPanel()
@@ -217,10 +214,26 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit {
+ const panel = e.webviewPanel
+ if (panel.visible) {
+ panel.webview.postMessage({ type: "action", action: "didBecomeVisible" }) // Use the same message type as in SettingsView.tsx
+ }
+ },
+ null, // First null is for `thisArgs`
+ context.subscriptions, // Register listener for disposal
+ )
+
// Handle panel closing events.
- newPanel.onDidDispose(() => {
- setPanel(undefined, "tab")
- })
+ newPanel.onDidDispose(
+ () => {
+ setPanel(undefined, "tab")
+ },
+ null,
+ context.subscriptions, // Also register dispose listener
+ )
// Lock the editor group so clicking on files doesn't open them over the panel.
await delay(100)
diff --git a/src/activate/registerPearListener.ts b/src/activate/registerPearListener.ts
index 053a984ecb7..6e81634c337 100644
--- a/src/activate/registerPearListener.ts
+++ b/src/activate/registerPearListener.ts
@@ -69,7 +69,7 @@ export const registerPearListener = async (provider: ClineProvider) => {
// Initialize with task
- await provider.initClineWithTask(msg.plan, undefined, undefined, undefined, creatorModeConfig);
+ await provider.initClineWithTask(msg.plan, msg.images, undefined, undefined, creatorModeConfig);
});
// If there's a creator event in the cache after the extensions were refreshed, we need to get it!
exports.pearAPI.creatorMode.triggerCachedCreatorEvent(true);
diff --git a/src/api/index.ts b/src/api/index.ts
index 0ee6fdc1ca1..4d431ca66d8 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,7 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta/messages"
-import { ApiConfiguration, ModelInfo, ApiHandlerOptions } from "../shared/api"
+import { ProviderSettings, ModelInfo, ApiHandlerOptions } from "../shared/api"
import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "./providers/constants"
import { GlamaHandler } from "./providers/glama"
import { AnthropicHandler } from "./providers/anthropic"
@@ -24,13 +24,16 @@ import { PearAIHandler } from "./providers/pearai/pearai"
import { HumanRelayHandler } from "./providers/human-relay"
import { FakeAIHandler } from "./providers/fake-ai"
import { XAIHandler } from "./providers/xai"
+import { GroqHandler } from "./providers/groq"
+import { ChutesHandler } from "./providers/chutes"
+import { LiteLLMHandler } from "./providers/litellm"
export interface SingleCompletionHandler {
completePrompt(prompt: string): Promise
}
export interface ApiHandler {
- createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[], cacheKey?: string): ApiStream
+ createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream
getModel(): { id: string; info: ModelInfo }
@@ -45,7 +48,7 @@ export interface ApiHandler {
countTokens(content: Array): Promise
}
-export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
+export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
const { apiProvider, ...options } = configuration
switch (apiProvider) {
@@ -91,6 +94,12 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
return new PearAIHandler(options)
case "xai":
return new XAIHandler(options)
+ case "groq":
+ return new GroqHandler(options)
+ case "chutes":
+ return new ChutesHandler(options)
+ case "litellm":
+ return new LiteLLMHandler(options)
default:
return new AnthropicHandler(options)
}
diff --git a/src/api/providers/__tests__/chutes.test.ts b/src/api/providers/__tests__/chutes.test.ts
new file mode 100644
index 00000000000..63af600be79
--- /dev/null
+++ b/src/api/providers/__tests__/chutes.test.ts
@@ -0,0 +1,141 @@
+// npx jest src/api/providers/__tests__/chutes.test.ts
+
+import OpenAI from "openai"
+import { Anthropic } from "@anthropic-ai/sdk"
+
+import { ChutesModelId, chutesDefaultModelId, chutesModels } from "../../../shared/api"
+
+import { ChutesHandler } from "../chutes"
+
+jest.mock("openai", () => {
+ const createMock = jest.fn()
+ return jest.fn(() => ({ chat: { completions: { create: createMock } } }))
+})
+
+describe("ChutesHandler", () => {
+ let handler: ChutesHandler
+ let mockCreate: jest.Mock
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+ mockCreate = (OpenAI as unknown as jest.Mock)().chat.completions.create
+ handler = new ChutesHandler({ chutesApiKey: "test-chutes-api-key" })
+ })
+
+ test("should use the correct Chutes base URL", () => {
+ new ChutesHandler({ chutesApiKey: "test-chutes-api-key" })
+ expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://llm.chutes.ai/v1" }))
+ })
+
+ test("should use the provided API key", () => {
+ const chutesApiKey = "test-chutes-api-key"
+ new ChutesHandler({ chutesApiKey })
+ expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: chutesApiKey }))
+ })
+
+ test("should return default model when no model is specified", () => {
+ const model = handler.getModel()
+ expect(model.id).toBe(chutesDefaultModelId)
+ expect(model.info).toEqual(chutesModels[chutesDefaultModelId])
+ })
+
+ test("should return specified model when valid model is provided", () => {
+ const testModelId: ChutesModelId = "deepseek-ai/DeepSeek-R1"
+ const handlerWithModel = new ChutesHandler({ apiModelId: testModelId, chutesApiKey: "test-chutes-api-key" })
+ const model = handlerWithModel.getModel()
+ expect(model.id).toBe(testModelId)
+ expect(model.info).toEqual(chutesModels[testModelId])
+ })
+
+ test("completePrompt method should return text from Chutes API", async () => {
+ const expectedResponse = "This is a test response from Chutes"
+ mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
+ const result = await handler.completePrompt("test prompt")
+ expect(result).toBe(expectedResponse)
+ })
+
+ test("should handle errors in completePrompt", async () => {
+ const errorMessage = "Chutes API error"
+ mockCreate.mockRejectedValueOnce(new Error(errorMessage))
+ await expect(handler.completePrompt("test prompt")).rejects.toThrow(`Chutes completion error: ${errorMessage}`)
+ })
+
+ test("createMessage should yield text content from stream", async () => {
+ const testContent = "This is test content from Chutes stream"
+
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ next: jest
+ .fn()
+ .mockResolvedValueOnce({
+ done: false,
+ value: { choices: [{ delta: { content: testContent } }] },
+ })
+ .mockResolvedValueOnce({ done: true }),
+ }),
+ }
+ })
+
+ const stream = handler.createMessage("system prompt", [])
+ const firstChunk = await stream.next()
+
+ expect(firstChunk.done).toBe(false)
+ expect(firstChunk.value).toEqual({ type: "text", text: testContent })
+ })
+
+ test("createMessage should yield usage data from stream", async () => {
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ next: jest
+ .fn()
+ .mockResolvedValueOnce({
+ done: false,
+ value: { choices: [{ delta: {} }], usage: { prompt_tokens: 10, completion_tokens: 20 } },
+ })
+ .mockResolvedValueOnce({ done: true }),
+ }),
+ }
+ })
+
+ const stream = handler.createMessage("system prompt", [])
+ const firstChunk = await stream.next()
+
+ expect(firstChunk.done).toBe(false)
+ expect(firstChunk.value).toEqual({ type: "usage", inputTokens: 10, outputTokens: 20 })
+ })
+
+ test("createMessage should pass correct parameters to Chutes client", async () => {
+ const modelId: ChutesModelId = "deepseek-ai/DeepSeek-R1"
+ const modelInfo = chutesModels[modelId]
+ const handlerWithModel = new ChutesHandler({ apiModelId: modelId, chutesApiKey: "test-chutes-api-key" })
+
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ async next() {
+ return { done: true }
+ },
+ }),
+ }
+ })
+
+ const systemPrompt = "Test system prompt for Chutes"
+ const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for Chutes" }]
+
+ const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages)
+ await messageGenerator.next()
+
+ expect(mockCreate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: modelId,
+ max_tokens: modelInfo.maxTokens,
+ temperature: 0.5,
+ messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]),
+ stream: true,
+ stream_options: { include_usage: true },
+ }),
+ )
+ })
+})
diff --git a/src/api/providers/__tests__/gemini.test.ts b/src/api/providers/__tests__/gemini.test.ts
index af32b1bebbf..97c757f8fbd 100644
--- a/src/api/providers/__tests__/gemini.test.ts
+++ b/src/api/providers/__tests__/gemini.test.ts
@@ -219,7 +219,7 @@ describe("GeminiHandler", () => {
mockInfo.cacheWritesPrice! * (cacheWriteTokens / 1_000_000) * (CACHE_TTL / 60)
const expectedCost = expectedInputCost + expectedOutputCost + expectedCacheWriteCost
- const cost = handler.calculateCost({ info: mockInfo, inputTokens, outputTokens, cacheWriteTokens })
+ const cost = handler.calculateCost({ info: mockInfo, inputTokens, outputTokens })
expect(cost).toBeCloseTo(expectedCost)
})
diff --git a/src/api/providers/__tests__/glama.test.ts b/src/api/providers/__tests__/glama.test.ts
index c44debddff0..58d9b6ab670 100644
--- a/src/api/providers/__tests__/glama.test.ts
+++ b/src/api/providers/__tests__/glama.test.ts
@@ -6,7 +6,7 @@ import { GlamaHandler } from "../glama"
import { ApiHandlerOptions } from "../../../shared/api"
// Mock dependencies
-jest.mock("../fetchers/cache", () => ({
+jest.mock("../fetchers/modelCache", () => ({
getModels: jest.fn().mockImplementation(() => {
return Promise.resolve({
"anthropic/claude-3-7-sonnet": {
diff --git a/src/api/providers/__tests__/groq.test.ts b/src/api/providers/__tests__/groq.test.ts
new file mode 100644
index 00000000000..068f7248fdd
--- /dev/null
+++ b/src/api/providers/__tests__/groq.test.ts
@@ -0,0 +1,141 @@
+// npx jest src/api/providers/__tests__/groq.test.ts
+
+import OpenAI from "openai"
+import { Anthropic } from "@anthropic-ai/sdk"
+
+import { GroqModelId, groqDefaultModelId, groqModels } from "../../../shared/api"
+
+import { GroqHandler } from "../groq"
+
+jest.mock("openai", () => {
+ const createMock = jest.fn()
+ return jest.fn(() => ({ chat: { completions: { create: createMock } } }))
+})
+
+describe("GroqHandler", () => {
+ let handler: GroqHandler
+ let mockCreate: jest.Mock
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+ mockCreate = (OpenAI as unknown as jest.Mock)().chat.completions.create
+ handler = new GroqHandler({ groqApiKey: "test-groq-api-key" })
+ })
+
+ test("should use the correct Groq base URL", () => {
+ new GroqHandler({ groqApiKey: "test-groq-api-key" })
+ expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.groq.com/openai/v1" }))
+ })
+
+ test("should use the provided API key", () => {
+ const groqApiKey = "test-groq-api-key"
+ new GroqHandler({ groqApiKey })
+ expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: groqApiKey }))
+ })
+
+ test("should return default model when no model is specified", () => {
+ const model = handler.getModel()
+ expect(model.id).toBe(groqDefaultModelId)
+ expect(model.info).toEqual(groqModels[groqDefaultModelId])
+ })
+
+ test("should return specified model when valid model is provided", () => {
+ const testModelId: GroqModelId = "llama-3.3-70b-versatile"
+ const handlerWithModel = new GroqHandler({ apiModelId: testModelId, groqApiKey: "test-groq-api-key" })
+ const model = handlerWithModel.getModel()
+ expect(model.id).toBe(testModelId)
+ expect(model.info).toEqual(groqModels[testModelId])
+ })
+
+ test("completePrompt method should return text from Groq API", async () => {
+ const expectedResponse = "This is a test response from Groq"
+ mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
+ const result = await handler.completePrompt("test prompt")
+ expect(result).toBe(expectedResponse)
+ })
+
+ test("should handle errors in completePrompt", async () => {
+ const errorMessage = "Groq API error"
+ mockCreate.mockRejectedValueOnce(new Error(errorMessage))
+ await expect(handler.completePrompt("test prompt")).rejects.toThrow(`Groq completion error: ${errorMessage}`)
+ })
+
+ test("createMessage should yield text content from stream", async () => {
+ const testContent = "This is test content from Groq stream"
+
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ next: jest
+ .fn()
+ .mockResolvedValueOnce({
+ done: false,
+ value: { choices: [{ delta: { content: testContent } }] },
+ })
+ .mockResolvedValueOnce({ done: true }),
+ }),
+ }
+ })
+
+ const stream = handler.createMessage("system prompt", [])
+ const firstChunk = await stream.next()
+
+ expect(firstChunk.done).toBe(false)
+ expect(firstChunk.value).toEqual({ type: "text", text: testContent })
+ })
+
+ test("createMessage should yield usage data from stream", async () => {
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ next: jest
+ .fn()
+ .mockResolvedValueOnce({
+ done: false,
+ value: { choices: [{ delta: {} }], usage: { prompt_tokens: 10, completion_tokens: 20 } },
+ })
+ .mockResolvedValueOnce({ done: true }),
+ }),
+ }
+ })
+
+ const stream = handler.createMessage("system prompt", [])
+ const firstChunk = await stream.next()
+
+ expect(firstChunk.done).toBe(false)
+ expect(firstChunk.value).toEqual({ type: "usage", inputTokens: 10, outputTokens: 20 })
+ })
+
+ test("createMessage should pass correct parameters to Groq client", async () => {
+ const modelId: GroqModelId = "llama-3.1-8b-instant"
+ const modelInfo = groqModels[modelId]
+ const handlerWithModel = new GroqHandler({ apiModelId: modelId, groqApiKey: "test-groq-api-key" })
+
+ mockCreate.mockImplementationOnce(() => {
+ return {
+ [Symbol.asyncIterator]: () => ({
+ async next() {
+ return { done: true }
+ },
+ }),
+ }
+ })
+
+ const systemPrompt = "Test system prompt for Groq"
+ const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for Groq" }]
+
+ const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages)
+ await messageGenerator.next()
+
+ expect(mockCreate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ model: modelId,
+ max_tokens: modelInfo.maxTokens,
+ temperature: 0.5,
+ messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]),
+ stream: true,
+ stream_options: { include_usage: true },
+ }),
+ )
+ })
+})
diff --git a/src/api/providers/__tests__/openrouter.test.ts b/src/api/providers/__tests__/openrouter.test.ts
index 76d27840af9..2225bfae7a4 100644
--- a/src/api/providers/__tests__/openrouter.test.ts
+++ b/src/api/providers/__tests__/openrouter.test.ts
@@ -9,7 +9,7 @@ import { ApiHandlerOptions } from "../../../shared/api"
// Mock dependencies
jest.mock("openai")
jest.mock("delay", () => jest.fn(() => Promise.resolve()))
-jest.mock("../fetchers/cache", () => ({
+jest.mock("../fetchers/modelCache", () => ({
getModels: jest.fn().mockImplementation(() => {
return Promise.resolve({
"anthropic/claude-3.7-sonnet": {
@@ -78,7 +78,6 @@ describe("OpenRouterHandler", () => {
topP: undefined,
promptCache: {
supported: true,
- optional: false,
},
})
})
diff --git a/src/api/providers/__tests__/requesty.test.ts b/src/api/providers/__tests__/requesty.test.ts
index 2b28fd61588..b999a01947e 100644
--- a/src/api/providers/__tests__/requesty.test.ts
+++ b/src/api/providers/__tests__/requesty.test.ts
@@ -2,338 +2,227 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
-import { ApiHandlerOptions, ModelInfo } from "../../../shared/api"
+
import { RequestyHandler } from "../requesty"
-import { convertToOpenAiMessages } from "../../transform/openai-format"
-import { convertToR1Format } from "../../transform/r1-format"
+import { ApiHandlerOptions } from "../../../shared/api"
-// Mock OpenAI and transform functions
jest.mock("openai")
-jest.mock("../../transform/openai-format")
-jest.mock("../../transform/r1-format")
-jest.mock("../fetchers/cache", () => ({
- getModels: jest.fn().mockResolvedValue({
- "test-model": {
- maxTokens: 8192,
- contextWindow: 200_000,
- supportsImages: true,
- supportsComputerUse: true,
- supportsPromptCache: true,
- inputPrice: 3.0,
- outputPrice: 15.0,
- cacheWritesPrice: 3.75,
- cacheReadsPrice: 0.3,
- description: "Test model description",
- },
+jest.mock("delay", () => jest.fn(() => Promise.resolve()))
+jest.mock("../fetchers/modelCache", () => ({
+ getModels: jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ "coding/claude-3-7-sonnet": {
+ maxTokens: 8192,
+ contextWindow: 200000,
+ supportsImages: true,
+ supportsPromptCache: true,
+ supportsComputerUse: true,
+ inputPrice: 3,
+ outputPrice: 15,
+ cacheWritesPrice: 3.75,
+ cacheReadsPrice: 0.3,
+ description: "Claude 3.7 Sonnet",
+ },
+ })
}),
}))
describe("RequestyHandler", () => {
- let handler: RequestyHandler
- let mockCreate: jest.Mock
-
- const modelInfo: ModelInfo = {
- maxTokens: 8192,
- contextWindow: 200_000,
- supportsImages: true,
- supportsComputerUse: true,
- supportsPromptCache: true,
- inputPrice: 3.0,
- outputPrice: 15.0,
- cacheWritesPrice: 3.75,
- cacheReadsPrice: 0.3,
- description:
- "Claude 3.7 Sonnet is an advanced large language model with improved reasoning, coding, and problem-solving capabilities. It introduces a hybrid reasoning approach, allowing users to choose between rapid responses and extended, step-by-step processing for complex tasks. The model demonstrates notable improvements in coding, particularly in front-end development and full-stack updates, and excels in agentic workflows, where it can autonomously navigate multi-step processes. Claude 3.7 Sonnet maintains performance parity with its predecessor in standard mode while offering an extended reasoning mode for enhanced accuracy in math, coding, and instruction-following tasks. Read more at the [blog post here](https://www.anthropic.com/news/claude-3-7-sonnet)",
- }
-
- const defaultOptions: ApiHandlerOptions = {
+ const mockOptions: ApiHandlerOptions = {
requestyApiKey: "test-key",
- requestyModelId: "test-model",
- openAiStreamingEnabled: true,
- includeMaxTokens: true, // Add this to match the implementation
+ requestyModelId: "coding/claude-3-7-sonnet",
}
- beforeEach(() => {
- // Clear mocks
- jest.clearAllMocks()
+ beforeEach(() => jest.clearAllMocks())
+
+ it("initializes with correct options", () => {
+ const handler = new RequestyHandler(mockOptions)
+ expect(handler).toBeInstanceOf(RequestyHandler)
+
+ expect(OpenAI).toHaveBeenCalledWith({
+ baseURL: "https://router.requesty.ai/v1",
+ apiKey: mockOptions.requestyApiKey,
+ defaultHeaders: {
+ "HTTP-Referer": "https://github.com/RooVetGit/Roo-Cline",
+ "X-Title": "Roo Code",
+ },
+ })
+ })
+
+ describe("fetchModel", () => {
+ it("returns correct model info when options are provided", async () => {
+ const handler = new RequestyHandler(mockOptions)
+ const result = await handler.fetchModel()
+
+ expect(result).toMatchObject({
+ id: mockOptions.requestyModelId,
+ info: {
+ maxTokens: 8192,
+ contextWindow: 200000,
+ supportsImages: true,
+ supportsPromptCache: true,
+ supportsComputerUse: true,
+ inputPrice: 3,
+ outputPrice: 15,
+ cacheWritesPrice: 3.75,
+ cacheReadsPrice: 0.3,
+ description: "Claude 3.7 Sonnet",
+ },
+ })
+ })
+
+ it("returns default model info when options are not provided", async () => {
+ const handler = new RequestyHandler({})
+ const result = await handler.fetchModel()
+
+ expect(result).toMatchObject({
+ id: mockOptions.requestyModelId,
+ info: {
+ maxTokens: 8192,
+ contextWindow: 200000,
+ supportsImages: true,
+ supportsPromptCache: true,
+ supportsComputerUse: true,
+ inputPrice: 3,
+ outputPrice: 15,
+ cacheWritesPrice: 3.75,
+ cacheReadsPrice: 0.3,
+ description: "Claude 3.7 Sonnet",
+ },
+ })
+ })
+ })
- // Setup mock create function that preserves params
- mockCreate = jest.fn().mockImplementation((_params) => {
- return {
- [Symbol.asyncIterator]: async function* () {
+ describe("createMessage", () => {
+ it("generates correct stream chunks", async () => {
+ const handler = new RequestyHandler(mockOptions)
+
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
yield {
- choices: [{ delta: { content: "Hello" } }],
+ id: mockOptions.requestyModelId,
+ choices: [{ delta: { content: "test response" } }],
}
yield {
- choices: [{ delta: { content: " world" } }],
+ id: "test-id",
+ choices: [{ delta: {} }],
usage: {
- prompt_tokens: 30,
- completion_tokens: 10,
+ prompt_tokens: 10,
+ completion_tokens: 20,
prompt_tokens_details: {
- cached_tokens: 15,
caching_tokens: 5,
+ cached_tokens: 2,
},
},
}
},
}
- })
- // Mock OpenAI constructor
- ;(OpenAI as jest.MockedClass).mockImplementation(
- () =>
- ({
- chat: {
- completions: {
- create: (params: any) => {
- // Store params for verification
- const result = mockCreate(params)
- // Make params available for test assertions
- ;(result as any).params = params
- return result
- },
- },
- },
- }) as unknown as OpenAI,
- )
+ // Mock OpenAI chat.completions.create
+ const mockCreate = jest.fn().mockResolvedValue(mockStream)
- // Mock transform functions
- ;(convertToOpenAiMessages as jest.Mock).mockImplementation((messages) => messages)
- ;(convertToR1Format as jest.Mock).mockImplementation((messages) => messages)
+ ;(OpenAI as jest.MockedClass).prototype.chat = {
+ completions: { create: mockCreate },
+ } as any
- // Create handler instance
- handler = new RequestyHandler(defaultOptions)
- })
+ const systemPrompt = "test system prompt"
+ const messages: Anthropic.Messages.MessageParam[] = [{ role: "user" as const, content: "test message" }]
- describe("constructor", () => {
- it("should initialize with correct options", () => {
- expect(OpenAI).toHaveBeenCalledWith({
- baseURL: "https://router.requesty.ai/v1",
- apiKey: defaultOptions.requestyApiKey,
- defaultHeaders: {
- "HTTP-Referer": "https://github.com/RooVetGit/Roo-Cline",
- "X-Title": "Agent",
- },
- })
- })
- })
+ const generator = handler.createMessage(systemPrompt, messages)
+ const chunks = []
- describe("createMessage", () => {
- const systemPrompt = "You are a helpful assistant"
- const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hello" }]
+ for await (const chunk of generator) {
+ chunks.push(chunk)
+ }
- describe("with streaming enabled", () => {
- beforeEach(() => {
- const stream = {
- [Symbol.asyncIterator]: async function* () {
- yield {
- choices: [{ delta: { content: "Hello" } }],
- }
- yield {
- choices: [{ delta: { content: " world" } }],
- usage: {
- prompt_tokens: 30,
- completion_tokens: 10,
- prompt_tokens_details: {
- cached_tokens: 15,
- caching_tokens: 5,
- },
- },
- }
- },
- }
- mockCreate.mockResolvedValue(stream)
+ // Verify stream chunks
+ expect(chunks).toHaveLength(2) // One text chunk and one usage chunk
+ expect(chunks[0]).toEqual({ type: "text", text: "test response" })
+ expect(chunks[1]).toEqual({
+ type: "usage",
+ inputTokens: 10,
+ outputTokens: 20,
+ cacheWriteTokens: 5,
+ cacheReadTokens: 2,
+ totalCost: expect.any(Number),
})
- it("should handle streaming response correctly", async () => {
- const stream = handler.createMessage(systemPrompt, messages)
- const results = []
-
- for await (const chunk of stream) {
- results.push(chunk)
- }
-
- expect(results).toEqual([
- { type: "text", text: "Hello" },
- { type: "text", text: " world" },
- {
- type: "usage",
- inputTokens: 30,
- outputTokens: 10,
- cacheWriteTokens: 5,
- cacheReadTokens: 15,
- totalCost: 0.00020325000000000003, // (10 * 3 / 1,000,000) + (5 * 3.75 / 1,000,000) + (15 * 0.3 / 1,000,000) + (10 * 15 / 1,000,000) (the ...0 is a fp skew)
- },
- ])
-
- // Get the actual params that were passed
- const calls = mockCreate.mock.calls
- expect(calls.length).toBe(1)
- const actualParams = calls[0][0]
-
- expect(actualParams).toEqual({
- model: defaultOptions.requestyModelId,
- temperature: 0,
+ // Verify OpenAI client was called with correct parameters
+ expect(mockCreate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ max_tokens: undefined,
messages: [
{
role: "system",
- content: [
- {
- cache_control: {
- type: "ephemeral",
- },
- text: systemPrompt,
- type: "text",
- },
- ],
+ content: "test system prompt",
},
{
role: "user",
- content: [
- {
- cache_control: {
- type: "ephemeral",
- },
- text: "Hello",
- type: "text",
- },
- ],
+ content: "test message",
},
],
+ model: "coding/claude-3-7-sonnet",
stream: true,
stream_options: { include_usage: true },
- max_tokens: modelInfo.maxTokens,
- })
- })
-
- it("should not include max_tokens when includeMaxTokens is false", async () => {
- handler = new RequestyHandler({
- ...defaultOptions,
- includeMaxTokens: false,
- })
-
- await handler.createMessage(systemPrompt, messages).next()
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.not.objectContaining({
- max_tokens: expect.any(Number),
- }),
- )
- })
-
- it("should handle deepseek-reasoner model format", async () => {
- handler = new RequestyHandler({
- ...defaultOptions,
- requestyModelId: "deepseek-reasoner",
- })
-
- await handler.createMessage(systemPrompt, messages).next()
-
- expect(convertToR1Format).toHaveBeenCalledWith([{ role: "user", content: systemPrompt }, ...messages])
- })
+ temperature: undefined,
+ }),
+ )
})
- describe("with streaming disabled", () => {
- beforeEach(() => {
- handler = new RequestyHandler({
- ...defaultOptions,
- openAiStreamingEnabled: false,
- })
-
- mockCreate.mockResolvedValue({
- choices: [{ message: { content: "Hello world" } }],
- usage: {
- prompt_tokens: 10,
- completion_tokens: 5,
- },
- })
- })
-
- it("should handle non-streaming response correctly", async () => {
- const stream = handler.createMessage(systemPrompt, messages)
- const results = []
+ it("handles API errors", async () => {
+ const handler = new RequestyHandler(mockOptions)
+ const mockError = new Error("API Error")
+ const mockCreate = jest.fn().mockRejectedValue(mockError)
+ ;(OpenAI as jest.MockedClass).prototype.chat = {
+ completions: { create: mockCreate },
+ } as any
- for await (const chunk of stream) {
- results.push(chunk)
- }
-
- expect(results).toEqual([
- { type: "text", text: "Hello world" },
- {
- type: "usage",
- inputTokens: 10,
- outputTokens: 5,
- cacheWriteTokens: 0,
- cacheReadTokens: 0,
- totalCost: 0.000105, // (10 * 3 / 1,000,000) + (5 * 15 / 1,000,000)
- },
- ])
-
- expect(mockCreate).toHaveBeenCalledWith({
- model: defaultOptions.requestyModelId,
- messages: [
- { role: "user", content: systemPrompt },
- {
- role: "user",
- content: [
- {
- cache_control: {
- type: "ephemeral",
- },
- text: "Hello",
- type: "text",
- },
- ],
- },
- ],
- })
- })
+ const generator = handler.createMessage("test", [])
+ await expect(generator.next()).rejects.toThrow("API Error")
})
})
- describe("getModel", () => {
- it("should return correct model information", () => {
- const result = handler.getModel()
- expect(result).toEqual({
- id: defaultOptions.requestyModelId,
- info: modelInfo,
- })
- })
+ describe("completePrompt", () => {
+ it("returns correct response", async () => {
+ const handler = new RequestyHandler(mockOptions)
+ const mockResponse = { choices: [{ message: { content: "test completion" } }] }
- it("should use sane defaults when no model info provided", () => {
- handler = new RequestyHandler(defaultOptions)
- const result = handler.getModel()
+ const mockCreate = jest.fn().mockResolvedValue(mockResponse)
+ ;(OpenAI as jest.MockedClass).prototype.chat = {
+ completions: { create: mockCreate },
+ } as any
- expect(result).toEqual({
- id: defaultOptions.requestyModelId,
- info: modelInfo,
- })
- })
- })
+ const result = await handler.completePrompt("test prompt")
- describe("completePrompt", () => {
- beforeEach(() => {
- mockCreate.mockResolvedValue({
- choices: [{ message: { content: "Completed response" } }],
- })
- })
+ expect(result).toBe("test completion")
- it("should complete prompt successfully", async () => {
- const result = await handler.completePrompt("Test prompt")
- expect(result).toBe("Completed response")
expect(mockCreate).toHaveBeenCalledWith({
- model: defaultOptions.requestyModelId,
- messages: [{ role: "user", content: "Test prompt" }],
+ model: mockOptions.requestyModelId,
+ max_tokens: undefined,
+ messages: [{ role: "system", content: "test prompt" }],
+ temperature: undefined,
})
})
- it("should handle errors correctly", async () => {
- const errorMessage = "API error"
- mockCreate.mockRejectedValue(new Error(errorMessage))
+ it("handles API errors", async () => {
+ const handler = new RequestyHandler(mockOptions)
+ const mockError = new Error("API Error")
+ const mockCreate = jest.fn().mockRejectedValue(mockError)
+ ;(OpenAI as jest.MockedClass).prototype.chat = {
+ completions: { create: mockCreate },
+ } as any
- await expect(handler.completePrompt("Test prompt")).rejects.toThrow(
- `OpenAI completion error: ${errorMessage}`,
- )
+ await expect(handler.completePrompt("test prompt")).rejects.toThrow("API Error")
+ })
+
+ it("handles unexpected errors", async () => {
+ const handler = new RequestyHandler(mockOptions)
+ const mockCreate = jest.fn().mockRejectedValue(new Error("Unexpected error"))
+ ;(OpenAI as jest.MockedClass).prototype.chat = {
+ completions: { create: mockCreate },
+ } as any
+
+ await expect(handler.completePrompt("test prompt")).rejects.toThrow("Unexpected error")
})
})
})
diff --git a/src/api/providers/__tests__/unbound.test.ts b/src/api/providers/__tests__/unbound.test.ts
index 3ceacf4d2e5..c01a2b53676 100644
--- a/src/api/providers/__tests__/unbound.test.ts
+++ b/src/api/providers/__tests__/unbound.test.ts
@@ -7,7 +7,7 @@ import { ApiHandlerOptions } from "../../../shared/api"
import { UnboundHandler } from "../unbound"
// Mock dependencies
-jest.mock("../fetchers/cache", () => ({
+jest.mock("../fetchers/modelCache", () => ({
getModels: jest.fn().mockImplementation(() => {
return Promise.resolve({
"anthropic/claude-3-5-sonnet-20241022": {
diff --git a/src/api/providers/__tests__/vertex.test.ts b/src/api/providers/__tests__/vertex.test.ts
index b15e8842c7c..99178c9ab7f 100644
--- a/src/api/providers/__tests__/vertex.test.ts
+++ b/src/api/providers/__tests__/vertex.test.ts
@@ -56,11 +56,7 @@ describe("VertexHandler", () => {
yield { type: "usage", inputTokens: 0, outputTokens: 5 }
})
- const mockCacheKey = "cacheKey"
- // Since we're directly mocking createMessage, we don't need to spy on it
- // We just need to call it and verify the results
-
- const stream = handler.createMessage(systemPrompt, mockMessages, mockCacheKey)
+ const stream = handler.createMessage(systemPrompt, mockMessages)
const chunks: ApiStreamChunk[] = []
diff --git a/src/api/providers/base-openai-compatible-provider.ts b/src/api/providers/base-openai-compatible-provider.ts
new file mode 100644
index 00000000000..82eeb830331
--- /dev/null
+++ b/src/api/providers/base-openai-compatible-provider.ts
@@ -0,0 +1,129 @@
+import { Anthropic } from "@anthropic-ai/sdk"
+import OpenAI from "openai"
+
+import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
+import { ApiStream } from "../transform/stream"
+import { convertToOpenAiMessages } from "../transform/openai-format"
+
+import { SingleCompletionHandler } from "../index"
+import { DEFAULT_HEADERS } from "./constants"
+import { BaseProvider } from "./base-provider"
+
+type BaseOpenAiCompatibleProviderOptions = ApiHandlerOptions & {
+ providerName: string
+ baseURL: string
+ defaultProviderModelId: ModelName
+ providerModels: Record
+ defaultTemperature?: number
+}
+
+export abstract class BaseOpenAiCompatibleProvider
+ extends BaseProvider
+ implements SingleCompletionHandler
+{
+ protected readonly providerName: string
+ protected readonly baseURL: string
+ protected readonly defaultTemperature: number
+ protected readonly defaultProviderModelId: ModelName
+ protected readonly providerModels: Record
+
+ protected readonly options: ApiHandlerOptions
+
+ private client: OpenAI
+
+ constructor({
+ providerName,
+ baseURL,
+ defaultProviderModelId,
+ providerModels,
+ defaultTemperature,
+ ...options
+ }: BaseOpenAiCompatibleProviderOptions) {
+ super()
+
+ this.providerName = providerName
+ this.baseURL = baseURL
+ this.defaultProviderModelId = defaultProviderModelId
+ this.providerModels = providerModels
+ this.defaultTemperature = defaultTemperature ?? 0
+
+ this.options = options
+
+ if (!this.options.apiKey) {
+ throw new Error("API key is required")
+ }
+
+ this.client = new OpenAI({
+ baseURL,
+ apiKey: this.options.apiKey,
+ defaultHeaders: DEFAULT_HEADERS,
+ })
+ }
+
+ override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ const {
+ id: model,
+ info: { maxTokens: max_tokens },
+ } = this.getModel()
+
+ const temperature = this.options.modelTemperature ?? this.defaultTemperature
+
+ const params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
+ model,
+ max_tokens,
+ temperature,
+ messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
+ stream: true,
+ stream_options: { include_usage: true },
+ }
+
+ const stream = await this.client.chat.completions.create(params)
+
+ for await (const chunk of stream) {
+ const delta = chunk.choices[0]?.delta
+
+ if (delta?.content) {
+ yield {
+ type: "text",
+ text: delta.content,
+ }
+ }
+
+ if (chunk.usage) {
+ yield {
+ type: "usage",
+ inputTokens: chunk.usage.prompt_tokens || 0,
+ outputTokens: chunk.usage.completion_tokens || 0,
+ }
+ }
+ }
+ }
+
+ async completePrompt(prompt: string): Promise {
+ const { id: modelId } = this.getModel()
+
+ try {
+ const response = await this.client.chat.completions.create({
+ model: modelId,
+ messages: [{ role: "user", content: prompt }],
+ })
+
+ return response.choices[0]?.message.content || ""
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new Error(`${this.providerName} completion error: ${error.message}`)
+ }
+
+ throw error
+ }
+ }
+
+ override getModel() {
+ const id =
+ this.options.apiModelId && this.options.apiModelId in this.providerModels
+ ? (this.options.apiModelId as ModelName)
+ : this.defaultProviderModelId
+
+ return { id, info: this.providerModels[id] }
+ }
+}
diff --git a/src/api/providers/chutes.ts b/src/api/providers/chutes.ts
new file mode 100644
index 00000000000..6f7481f1809
--- /dev/null
+++ b/src/api/providers/chutes.ts
@@ -0,0 +1,17 @@
+import { ApiHandlerOptions, ChutesModelId, chutesDefaultModelId, chutesModels } from "../../shared/api"
+
+import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
+
+export class ChutesHandler extends BaseOpenAiCompatibleProvider {
+ constructor(options: ApiHandlerOptions) {
+ super({
+ ...options,
+ providerName: "Chutes",
+ baseURL: "https://llm.chutes.ai/v1",
+ apiKey: options.chutesApiKey,
+ defaultProviderModelId: chutesDefaultModelId,
+ providerModels: chutesModels,
+ defaultTemperature: 0.5,
+ })
+ }
+}
diff --git a/src/api/providers/fetchers/__tests__/fixtures/openrouter-model-endpoints.json b/src/api/providers/fetchers/__tests__/fixtures/openrouter-model-endpoints.json
new file mode 100644
index 00000000000..10ea52f07fd
--- /dev/null
+++ b/src/api/providers/fetchers/__tests__/fixtures/openrouter-model-endpoints.json
@@ -0,0 +1,25 @@
+[
+ {
+ "scope": "https://openrouter.ai:443",
+ "method": "GET",
+ "path": "/api/v1/models/google/gemini-2.5-pro-preview/endpoints",
+ "body": "",
+ "status": 200,
+ "response": [
+ "31441d002056aa5ad5de6cfba09eb44cd983cf558aa50307224fd48d88f0c0d12137eda7bef1c435891ecc325645bf9d4794cd227137c069a7450a3f6ea3541aeacce9727170159a489e4b07a179ae738dc1a983bd860cb018631c277e3ab29720d5dea2ad528e551ef3c67c0e83e03cc3e22da9c6d2dbbb03ed2d5afa96237dbbe0d4e5e379806d0ef657edc161db2c0d863cfc7525951860c1af95425fdef6f1e177a1a24eb98a9b4ab75cb9acf4e63df938f044074a6c06dac44cda2750e3aa6e1246437d1cde032d10d0fceac4d20b07958df4a4aeec4affaa012d9b3eb5d0e3c33fdd4ad849181f1ffe53efd2b0f7f70b17431cdc7a92309228d5154e736588069b1ce7714bce6952e85c744b1cb672c175e424fda500d2300b1b3041bffe4209e02917760c1a225f6c218da952e14c3eaba01868e2fc07a68969cda1df7a9777e56ff7021bc945ab34b99e29c5222ab6214868114c9f3ebfc91c1c358cbac63aba3c18cabc99b8570923ed7b493445434205c506e4261983e7a03ac145e5e4177400cabf2a713a933092e58c0b18a4ecdf48b9d73933ec3534ee38c815670864c1a091d593757a991836ccd364e0e3e026d14b58285fe813f16ee4eaa5f285b20969d68ece56b8c01e61f98b7837320c3632314e0ce2acf4b627b7061c86ca07350aecd135c00ba71b0a08efaa5e567b2d0cbc9adc95fbb8146c53ef1fb6072b8394a59730c25e23e5e893c2a25ed4755dd70db7e0d3c42101aeda3430c89cb7df048b5a2990a64ddbac6070ceebeefc16f4f805e51cdcd44502b278439ab5eb5dbfe52eb31b84c8552f1b9aaaf32ccab7a459896918a4f4096b035bdf1a6cccc99db59ac1e0d7ec82ca95d307726386bbe8b4243aff7b14d855db2e5b0ad032c82ac88aecad09dd4eab813d6282a8dd0d947de2ecb0656ea03175e91d885361ba221b03605034261814e6c1c060c0125d58114a23c9334aa543079846052706459dce45f590e0f827bf794f3f751e24c224c06e3106cccf5c5dea93db5b0303"
+ ],
+ "rawHeaders": {
+ "access-control-allow-origin": "*",
+ "cache-control": "s-maxage=300, stale-while-revalidate=600",
+ "cf-ray": "93ed496b8e0a0fb1-LAX",
+ "connection": "close",
+ "content-encoding": "br",
+ "content-type": "application/json",
+ "date": "Mon, 12 May 2025 22:17:32 GMT",
+ "server": "cloudflare",
+ "transfer-encoding": "chunked",
+ "vary": "Accept-Encoding"
+ },
+ "responseIsBinary": false
+ }
+]
diff --git a/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json b/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json
index a8fd47fe046..60c7556bc91 100644
--- a/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json
+++ b/src/api/providers/fetchers/__tests__/fixtures/openrouter-models.json
@@ -6,16 +6,16 @@
"body": "",
"status": 200,
"response": [
- "6300f8ffc388d4a41e008dd0e173de57a9daffe9da8597a45a0c84c420fe485ab2566b5256f426bd929b4003e8afc10c3cdd60b05ff0e1fa53ba5fecffff7ed9f787497a6287a87a84dce79e231e891710452224aa9288aa548b74ff39f7d64b755525bda692a14a6360a0995c48d020283236e921fa20cce8312a30086ad62842e1c6cb511933fa717b28561ad2720ae8c45ce6afb3792340662aa6a159b37de5a60744910068fb7bf097a846c568f1eb9788eb6811f55c052fbed1b31ed9d46242b668025114470e7b8a16518ef087b780cdf21a2e1ee03e839326109d467134cff2b5a98e16d9ac9c64e76596a67154cf80ffd31a94bd8b16d166796d2e1ecc7d062c8030785133fff22cd530c3f5bbc029f8062e888607a257739f41116acd3554395502f281c0f21a94b007f5c0fd10fc8e3eb448ef6bb2dfbefeb7c0b4138bf18e1c898077305aee027b84adf5d52bd5a07ee04aa0e6aedf2de43a7415bb165805041bd2230cc1376c2981d5c856c13b9847bd0eabe9e73550bc63d74233fd3f0d54f62e065660a7d4065412c8b2f415b435825875173e8e7634053cbc7d841a1585b4e18a5dc5247dedc257131c5a7b846a0ca85443dbf3552bf1dbd106755e83965bd79353903e64137814c957038114d9098806efdad0e663a87cfdb8175d0dd334addb88b73b762d5438347cbf87496231c5a393de34762d68fc46c0373004df0f2a92be6b028906ae946a6007f759f2ec9e5d54b02784e8201991cd3544d565c03be830f4d0b3722bd5b9604baeea7a0caf1270dd54460ce0ba2adf0fa4acbc23a8026eb340555d55d5596bed681a549457a9c8ec1419c3b048033604f799c966b329b003ed3b17f4a481abcacb06dbb853f269a4c0140ca9baebbc2460095fb125e080b734a32d982f84496f1af0a8d1e0d40a084d735cacf1a1a7001b7f09e51e142b553a06ead7241680341eb2d04c5bb4248c4250a190c45015d80faa66d742c76d6744f195046adf4785cfcf58758002965ab431f454738536061f0047f5cef77e1428bb212f4914478332f9a02f259b6c205a64d3625ea67114cccf42b4f812f5be46cb7a8c1691d241cddf2b1d348a2376c3a82f9f28629268f1ebfe52467f8c233fea6151f5afe4f833856811e91cba29451c7c065ef43850b4886aa241885e4dc8a23fc7d110b862d7468b2f51c4ec8a16513a283dfd600991cad2288e029594603ed2cf3db6f4bc774fdb9769e5ccc9a862f4128ff066f99fe348fdf092721d5ab4f822b0293d1e5e42e1bd0cdeb2122ddc686d1cb1bcf4be261d5f255a346885fe1c47038597700e79b1dcb37ea7fdcf31727f80adf7ada5b3967a766cf2646286e00dd65d83f6262d4c3e0171efea0ba9055cade7813c99c06df070fbc785e3bb5a9ee7659e4e5ddf4fb340978182cb89a292f18dd18e0c069c2610e2a901bd5a8f38e9aa88453af922605aa7544c4eb9e14a6f557d7bbf6e02dfbefe9f76ec5ed9b5dfbefe3f6815c8e1d6027a3d140a3f0ea5052403c18f6d97420c25813d6b07ff59aaa110d0b83a06a0cd8d6f181d08819d344ce4682d0184db28a07e30ca14900cb0dd3a5882306756e507d170103583c58a60f0c2caa90902bd0e82f56619c821d4f6f7c3d87a0c750c811a4b95b26b81b4d64113486a0c8fa881a42185ae86c9035b3aa0bdec2a2bfc654bcbf964365d7bdfe9d008f59e95ed8a8ba3862dc100c5c0c6d189f42281ee1727699aa669a60c24030601bc3bc60c0aaea8244d27d9141018ecd65161d5d14b20ac0311a75375b43e7466f681959084c74492e3d9994e26c564fd75d36eacfbb3d6f6e673668a7c4bffbe391ebf7fbad82ce06abd815f3228f2d56e57cbf3bccccaf97257eb8df9253345be32699995d71aa77522478b08ce79b5de98d214f92a862df7ba66e303d444034a94a28dc1faf60945f1d69acce2798888d23c0290e05bad61194e027450727500749358e38af4846974eedbd77f2be7a70fe5d5d86d3974359bb8d6801cf62c04fae699f4bcf5dbd77f63a52e24a038e81f1061c088d2006c456f7c3f6020a5d0fa295b14120421e97131fc92c1e4cbd7b747d87a2f2a6c0d14060a32690c24e1181d04677bb46400944c314529ddb859a002d30d6b8cdd5b9406811d23dfab05b3049879ac6f1a0a742e53f90e8bfa1a1fa006d985c6871e941e1c0c89c7503f28f7fc398d8847e151ab624b4eb982bd0faf8df5fb448180b38324c8d27941ea4fe764c7083fe3fdcd690c3f3cbcbf01f5de4285d632dd1dd2b023d3da1f20cd3e77a4d0703b06b259687c00615cedecc6f3e404ae2b2dc1412dab5048a0b0e532762dd454c6d834548a8f6a4474fab0eaa2c03b43a132cdfa672af2d974bebae0f7da518810761bbb18616dba8342c6fd2857632f572f333dcf260dca15ba136d6dbbeb9dbce9d89190591818e73b053f9033ad26163793e1580e253aa6f23581bbc02abedca10850b232237ab40445d9db4056f9b9bd836cf208ed69ceb69d712d91d163b85b91e9087747bb15d6ee727b1468c6a01d0508d46898aafd3ac8c95384921802fd13595bac8d41dcab8af86cd9b6793a5464518f467fcde1b2c11830283758a934402b234548520f02e220667293d9b5d8ed55f00c2c18ae1eae6e1f4de919a23801ca3f14262df2d2e254a5fe475bbab79d2979620ab5e3d0ed0a96d3406351ba6d72abe9d4de5a946efbfa66e5743aa32ec879b43f6cf6dafbf0daf920eadd110307811b6833195392a08268951976f01ca5fa6fc57364549911e8b4a6acbad05763f5c6cfeed9dd78a545499461ef1c114f6539b003dd7b2f615616404bc84ccb7a67780ab9bd8c5e9b180defe24424dc49cab534569676f4aaeecbe07b47805e7fa5bca304ae1b38fab102f930cfd8a3ca61ec8013bf71b97604cfd162b7e4730432360d1f4e637056865006e75a74182c57acf608b8f3cc3461de49a0c8674042cb3e7aa8c4c4d828e0e49c3a6145bca3ee78f1704815fb0b55e7bd1c1dc1353e59b8fedaaa2ea87b6a470ed855a3b8ba3a6e3bc9510f1a18d9d3d8555904b3da630cca20bc0b186b0c74125fa6c743a8c1c7c4de6a798e60663c851850c0d5ec6f3d8df36a4750fb6aecc92999fb844f3ad5411667677e2017fca81412e4b3da5772360a1922577396b0517f7b7ed3e3e1e9a0697c30e6de8ff3a9a14c98eac720be75fe3d376976e8693addfe03a5d3ec3c4f0236b1cd3b92ab286e9592830e3851865f8e729a32fc0e514cfecce10772c867be34eb291db75d22b0f2fb81dcf27a01be840d3b86ef3f61db00bb38cfcb3ccbe9db75d0e95a68eb4a56b0f7c0f5a0c0af1f3bc01f4fce82e39f02a988ace6a5a1272910cadee8eeb8ed3897a377c029b2619b2ad516433f8d66747a539c7ba3d891b09e064563a8bca8a90d4dbdfa3429df9cb29791114167b8be107f2370348ce7ca9c80f9211e4778e8da46c9e7b4b3851db9ba3c04c6dbeb34d54d76af32bc236863c97ccbebcd259c9c9f2793df09b2f8f6a89d77a701ec7af8f1d258ea5eec0da02e52b611f2b2e7aba922111fc01742ed4357438357f402154861d599115ee1779dec7b72aeeac2dcf17b82257bb49602087fa678140da343c75b56a1d3ca682a67070f8f971bcf845dfd05a74bfbc387134ada24860d6af781453186cd66f3741acba88c806a56e77796057ec1b4a03dc29eac3532b2d20678790cd47e15c3a82015390cec055a3e13d9b6d9c447f02f79d2c55415d80d3f2c81c70eddabfc16a34505e28be5be84c4d92b94c0b7e3c1cf41f0c30496d1f00a1d541db28b271d12fbb54621370e539a69deeec8fb0a39920675f7ecd8f97a0e8bc76f5fffad3d313976d090971a58d241071d95fc355e8e855b1ecaabedc5a1c35b9265abe7a12ce379990654e5af239bcb950f76d8f96ce2d6659127a1ff41f611c7f1c86918817eb402de472940fdc04539a1ef6dbe4057a8522af83137091e5434e57e4fa119ad5927050a1b06284eae452a80e0688f1ea41a1f82733f8ec827a8489a636c8032822a58ef452b1e086d4185133c54cc155ad887e68f6e702ad8cbde995d5f8261c83c09b1e3080625d2d2d48561d1c60bec471daf143782c313ea1416d8a4940ecea2ada6614672989304e46ee5b0faf9fd3b60aec4d89d4883fb6f86041e48611ca0a3400b88cd58de169e29aafefc60efa4b926f918c1c7afc56cfaf15322ffa000684c51185621027b41d2f3f2075ac3a2efa3c4437b4ac78206f9ecc2d771971b6bb1c72229cc2ce5bce779e8581096d70bf8fde6f990c3da628f502405ccd21590e0279e4dcaf9441894a43bc85a15112eebe37f603f541daac1868e23ada31388a39b7325cb6bf00e36a4a82dc130fa6694322b731d3743788b188a3768d0c79f497aa7e8f5915a771934db9c2bf1f5b83d0a5cb88840502d258347c44774798496a1a4e703f846e137b863a17abc61f1d20f6f1fed76f6e2f6bd763c105acf63a9371b88056a78e830d0d5ed23e54fac3d54c7be254a0c0d3e2c784b83c5237658e2dd8e82845b26be33a9871d4fb2fabb2981ddaa71ec1d67109695ee409694c908fb6477f308d7ec14c0a942d8b939bfea650bf820d40a0665428a5d2b5b9265b06596aee497294b080cc8cc9c55515e7da253bccefb6b87a9a9cec5566dc5de5b42cdd21f96b079841566b0e7e5fae75f9690a5a9a5bd807b7c1d6bf4e42508593e7f3796827353dbc6acd3b5017b48efbd76f6e8934572540be706a573efdd77d76ebddeccf6b287ab35bab6b8078506bc0f3a52ba20351f291615b0a782ef3d12d46558428f89c179a8b251b20c2cba2497abab4b096296e1c67c11e8c06a294ac1725cd5a1c6e9c7a3805c937bf9e388e5a43f2ccf2e6fbc8e11058c24b84f1ed657d7cdc088bced8a884f73e7dadbbd6ae2c3fcb42777f6694f2e4f26a6f2350533db9a59acb2e9d2bb3db905dcddf9b1f0e6d560b6826b877b98b928e7f314db74e261a6d9cc8c3730cda6d90aecb7135cf207fb65d551913960bb76aa173d2e88685809a7641e502c55bc1d5b68f800aa85abca8d9c7634c656d6e9c7b53f5208168ae4b5a727a7e8e40777ef6f2f6378d8f3d5fa2986fbcdc38d0f7ddcd67775b7848a2e8ad30d640ade43765049199840bc47f7cf787fa344dd03e8a001076fe039e4d5f2ae668493fa520c950fc3289e26e5c7a0785ab8a618e4e8b423e5ca5ba0d5a6e8a0f33f8616f700484179223cce49fd7614b5b9bc7f4a31f69904cf21aa9e118098f217517b1a71aac5fea5060c15627aaad34212c1ee566a0daa49bd007eb72bd35f087a11386b73aacffd8ba473f3d734587fecc96902f79e2ba811c2b5b423580e5875047992c2f693b6055375c6eff6e422d27f2c3930881bb7bae13242b07df16b389d8b6907356592617ed0f3e1461b4b38c974921573d5263d807895bd1a8bad743cb4a4e47647945ada5e591ef1984068cd49850ba160d31257532607fd34c711629ddc31471e7ab6d6adda8187750a68eea712fb3ad133d2188693666b1ae5394e266532fd1d55721be003056e98ea53ff8e7cca63c5e4c227f35952fe0eaedf5eeed0a6df353d06821605ddd42476ad4a92cd54384a19649f4489ce28a9b96924b619fd10c832a94dfd005e900f54a165b668be30e3cb13222731142477022bb961868a2486eb8bcbb45aa6babd97c4b5c359e891cad92f1208a481698796f1fdb19b3d55cd1a1cf1abdbc7b7446f6ffaf9db5863c8f1694f65f256cd5654f3c5fc8cc1e08e6c022a828f301a4f55166dd8d87ccfb511db40aead5093e55d0585956f5ad427a01ad61dcfa320e356149de256ea183f198d22a02b16350c44cd56e36741a97c2081729264bf2bbb7558acb9688756622826c9fc4e0b6f46abfca6436bc9b5d07ffbbcec02357f3f1977b01453a5f37bcf8c5756a5182ab3abc8926917f24bae2924f0c3066f8fadf56a0094b9a0b437de7122699b14ab915bb5ff54464d32ce3ad81e9ee1063d15d53b660230d73f27d8a9b475300915d1af5ff36cdada7faa644f2fa743e7fd9b7bb8c383673b3dcfbcf521a100e595aea977dbe1be7dae19c3d5ede3b7afff5c261938745e0252d2a02849c17f79d5110e2408975168b021219d067cbeb11c9d02ab8498002dd4915640881d1fb4a41f0eab9883baf8fd09f3748ecd66fd14c3244d8aabbaaf6eef968e37387f41a3550dd684f3e96f5fff951910a57007ba09e179ec590ac0943fa6a40cd20d7d0a930412e2ea74b54cec28da662286fed73c2dbd703568bfcdfb7f9790a5513b0ac867d652dfe3cb6c4bd20797f7c82faf17b07e7f1838dae7cc6591e7a13b3fc4c0cbae689de977532d81987aca1e05d646e3d78ea2e78daf09ae4ecf5650886548169d592fab1dc16df0be31b76cc9e4fde8c9d37495ab87c9186008f2021828b9bd1357a3c5608fa4611baaf68554c0c7fab1ed74506d414007ba32ab42e5fb6194bdb7a1a5881ac138aaf51011ed570b75a172acbd31f559fd9ba7e0fcfe98caf47c0ac2ed1b9e07e16bc556f59391a5b734c992f832bac3be486e9743db04aa87e0e5acf23511371628772d23de72cd7a6c46def261f9dbe06581cd1db75ee306f1b92678789cab6dbdd46c3e2bbd2507436f99196cc34c51e106d26aceb1c6cd124c8fa8e935a9e72eb9d705901e43c6d613b0d2057b89d26c59e16eedef7b0af11fc913c0fefc5facdbcbb78f60791b301c97dc158265e4b34ffb4fa6c8b7e6aa0b34610866b7bea9b996c1f2f27a0177fbbbf2da53b91fee61f77fc1e56432399f6b3f5277fbbb1a5beadc10733fdc9b1d8233aec86164e30d14a3885533f5dfedc99d7547c8395e09137c0f5234adb562fa4c56e3c4ab18439106afcb8ae44fe723b8bfdde021b46b6229e5d0ab83d31feae8eb507ecb09d6c8924c4e60740cae70370db647380fe91cbb5656a019b5a4ebffea060a50335adf8e043a06472e1857035981f64c7129a091f48258856ce328d0b4c7a433edcf6bde3f98bbf5fbfbe577e01dccdf812b9ca98b91a192508375a2db8c4566daea8ba0228263307706c0e0e40d4091bf3b5db4ae3200af3f59672de8ea0560550130456c410747940a1f31d02662feacad981abc48628ef8ca1015c66cdd21e454b0b1a0c3e311bea62aa8c3f737cf8a5626e3b9e57fefcc74ffa62c310f1a1fdab39a68a878e5b2722b1073c195b993b7d084e3bf2990952b6d5822dc9ab838cf33f75f100d6f9eb363651e054cfe7159895b0daa8255121cd36e7a6b9a0b16656bcddd9e9cc94a5c4b423ec2d69fbfbabf7dff5d9818b33e59e78ea68d34c046948876ef6a76d2da54814c6909fcd19caba17a6fa872f6ae6ce7a213d4e4dba769de68d89a77f4c6d7549e9f057693388d06b032b280ac2f4c26cfb56dbdd5e7535ed34e6f27340b6bd37dfc087bef9d745e91cf5eb967b3b3068bada2cf454c0a36f7c0ff8bbfe39ee1c31a96c50a1e557209f6c1131769392fd3b6a5efb867f361ad9d29586e3b9ded15c3860f3a0655e6d0cbc34041250bd9c8947fc07986621c955f39c1f9d63c99efbf34e042a0402a1a9d09aeb433b07f1836269712c6decf50d126e347f35606cdb258996521fa3dcd9dc220e79e6d26f4df0863c279cc6e6a393a70d4556587643846a6024bcceecd66f33475d64ccdaec03b34179013e947592d0c7b2d97e8b9ee9bffb036b3d5736ff88afa1e4d61b27c95d4c2ecb8816b443913e830293cd877e165b40cabc0c67bf7811f811cdc57ce2efdf316593acb93be3f2ddfdb77f022db741031cfc1209fb5c1bf1a0ef231664b8a535def50db2d04ff0a4511c25fddc4ce16cd92976936005bf774824014539645398b6d54686f390dc8a532e30de40f42d1ed46277b7f2cebdabfc44af257fdb490e4760a9c9e0649a8837a8875e54a25bf673c7888cc82e7dcadf6eedbd7ffce4383469715de51b15539d3647ce133c4bbb4c3eeacf4d3884e59273bda5f94f74a361094e30c81282f3f7efe6c89c1078c302c6de336761b023a1930905351f9ee1ab0228163e69e93b79612b8a00647ab1044325d529a5eac0c83f7194198118774c2c7ac67f702be804872630b788e3a6ebbe708fefcd16dc4438b8e3850166e31dd7b382caf815c7d38dc943ab3342ad9d5118e3b25828b2dc03321be551af66493a1afcb413ef85149176e59baf17388683cbd476715d2d7a0e84d70df3b57e800eb1a3eee6bf9057c01795b8a985ef4e78f31a8ff27f24816c6fa572276a2847502cf0ed236515ee48c5f05ff1a7d796a8adf29d209a62584b32448f6fca4d3b92932b558d4b2122ca7871d96d7095ceb1f6ed3c481cda263988854659a08a12cef30b077d7a8c8344399d8e1268dd1772f19fb1e037fa6a1e56fbd08792dc3cad1894953801d5cee85f74c31748456bb0a03c560b13a05811c8c0ba34bf32f4ab241fa409c3ef0f55c510855ae32eb37abf063e866fd646e8357b84ec0ca8cd1c08c3256ecdd4f314d7058547cbf0c4e927cf9e99f7d29753bae19cfea01f78a22c98ca3de6bf0ce3874deccb799d6dd6f3e5c5f5c2f17328c4c0637f74301fc1061be4abcee629617f35911ad5fc1236f1e7613ad12b06c4950993d573859af37a7f6989cc83866438a7f9073b464664e0a7619a439147bb28688ec5b1f6b1a9ad03243a070107657c1e0d8f62eb28a11dc0f27f7cb2b465bbf7a6f8d99621d504a9073ecdfa24517d1280f34e6999654c7181a0e5af49128ad7004efd40382b06b2d07e503187b0aa60d5813dc3ffe0457b74f7092b2bed26c29b2aa72fa17570571b835dba02459df8c6ff8c335890b9b98c0186bb80ef8d8cd4219c664bdfbe81e4126f1ec07eb38a547d06e64e1a712b825d2ae014204bf3e09b604f774523a7ebddca23f1a74add68d6dcbae6db0a2a4f2679bb459f5b52f1bd51a4f56039a7c52accc2efbcd290d84e658fb6f8b41579b51b025139ec93b85e27757ef03cdf07ea24d9968e731a77341d71315903e1dae29cfff3e51718b1fc6810294e7df5fafecbc3c2f9fa8081e5e85fa9b14b892107fadc9cb66c320e8180e35810bd47408e0a04e600ffdeb21dcd018d0420b9e104ed1693738b9593e9c2a7b1bc57e5964e18dc292e01ba69572213b20ab1ea0de87a3f01fe2073f317a94ab1f422c285a8a1dea2d61e059630157e52f98bfe61ad6e7f714471943dddaa4d6abdba7c92b0d7dff4502dfe7690a803a6e0bc7755dc5ffb1893c141243e0cb354927e789b6b77dfd9b1a54d432219794829b09feeabea97f4f9499329dfcaf2e14ca44e41c00490a0ada17d5c746848f41dc6a087d46745303058a41dc1f28ac01113b29a5dfa4e791527c1ac668e5b8ae4ad8d857a18353ff68481839880ee6070cfc9f982c4dc1f99a80f0a7e65a5fba6967afdd3d299a0f1834bc8da5e9714781abd78a5f9614b12f53c2e68609b0ee0d2fe6f36c9ee7d603d4653cb892932c9f5f9e7ae741e1cccdf9ac429c9347ca33556e57828e5e357dd5f0117482938dbf3cb5464316bb37cbe770bb63d0d59071ea8c70c155405ca9f1618fa1860145e0a4e498cea0684f6b616842c1ade2a42086ba0f95c1a80ec0a7083726ba0f345854aa62de51479663530d696ea74b02ef1d739c4552331397850f4539c5004ac10b59564a84952e9e292172abc3207ef97a54d15d59a4139aae98ea281bc19eac776e841803316fe3661494141a1fc071bb54d9959d534724a60913fab02db465d298d922d02a0f3603612c23f5eb7732b02145d3b2d1086ff9e47636c0ae85bfe439687801a110947412f5aead46f54d03ec6039b6a328e4695e8a59bf6aef603904b63089214ff389ba95770ce95ed906eb57e85865da35b02d508885d500b43d3e548c362762c27fa44a3824d0f56c871c906bb566c752d9c9ca0634bf0e93e907fe671443f7357563fb096379916d25001f1176ffa03468ff38667d0437f36f43cc3f946c1695a147d41ae1f7683a2f3fa0e1e8a601f45397ca8f1a8a9fe243e547fdf17c4db273bab7ebbf700ae9c9a26857ddc8ee134dd08e962dd44345e3b38ea4d59975f9183b5f18f806b2f49c4ae64617c2e109e0049dc986cb866303c0eac6a755f99a4e01b9fea2bd8fc02af5e8d2e1eca840bc0be205bafb2824904de714ee1108aa2f46d48a898509b2143a157a05ea48a88d630ef89732053b8077b4eadb089870a589a99005f744091e95ff4aa378eb7258e93883f63e21ec2f8e12a3492d98c406890a20c15cc3f41ab44752ca4a652a1cbab0d23c83866147d08a115287d8fb3d46d4a64fda348ba2630f081594d1d1c3012daf321c5dd5913d19e572eca1a1a29ae00fe6499607c9bcc8b6c247e06a7248dde4586a00f8ff0340ee7d9dff7dfdce76384732926c53b21552790f52809b2dc996b13d801eb2c6916408ebffff5efd9cc2260d837c40c306650506b07d0a784f7a40b2055a8a4b8ac769fe9e52cfb9efbe26eb7bc925592e69d53369f64f3aeb858581d6e0001cc2256b5a67090c0a8c8ab8a20ef161b0d3388e4152ba8f82fbe612f75de3faa0515739fbe187623eab1ce42a4ac2ef89cec923fa2642c6e3bff5a56b7b4cf73d2bdcaf7b3ca16f22acd66da5fbbf2bf4af73e7639d2b5dd8e4efbe7c56386083dc2c68590d7a9e41130fb66379d83af4a6aadb1bdf8c65be66032bf6ab277b9b38a7a1633d79c9e8f1dafa38a1fc5badd771d0625031165301502c82bd82098c6ec34af9a9a8b14ac0bfd421dc924f32f33b68acb83e6782808952572645155a843bc89e200237ba5bccc61529a8a1de2e8f680230ec34d48a4afe9890e0e8e7e5da6a730ba87018faa1f70231428557471e5f7f34a06875d64aae66eac053b26b25c2be2f3edbb6df3beb09a34c49abdb40fc45e4628419fed33d7481bb602961b8c2fc755919c158b9141b67f45b3cbf2edfb90991fcd2cebe0f52f4fbaee936da8b560e0747c697ecffb196241b695b55c9bd056ca202b233655904f4112d2f8bb8953354385e8dfd3b8c19fff0e2c88b6fe898cd1c06c4fd5a1b534037da1bf7a70774728a9892aefff7d10dac6f72224c17e6eeec2257ca34c1b97b910719e6a80d798e01f3738cbdbcd0d438bf2835b1ca6dd77311f955ae5d17ba5a70d40850db0a278dfec035b72dfb483ee67f84dbfa55728f4d9e192a4419ca0509a17b3ac23335101d6e695be2a029dcaad9ade7746cb90d01d49484e75c6b39506d9325c6d2247e333beab65f0eceda1d0438be48c436177b135b23b6c45ea56b02e76e096c0c7566f74461e43f2c70c53cbfe41482a4059036311cff5a3b30f6140368610d811c5c32425a4e457a5692d0c5d40bd70534d12d09a0abe5ecd7e3d473578247fa68a9361f7662033a0c71b9dd9fbf2e59ca055ca78ff15403dfb2ac0da39afd865c217fc095ed03ed950803eb6db32f0f86114c16c170d31ce066a0000c8f438fa313b8461ff89480cb0c37759517e2add69043e4fb9073575cc06fbd74d3198945f594afebe4a5af3a1b355877ceb9748750ad8134cf67376df47d78cf919f63629d679b8951a622deb020a15d0c36d542677cbb9663725768097dbccc5d18d1ae3fb071763d2982e06926838a44fadca4bb446c31548e0005e40bf491f6bda3e62636667933af94b0f0c7c6130d2df031b923dfef9c1f7b45123ac9c757b1bc1765d14306672fef6bd1a7601714dbd44536ddc520b94de6ea87d729b4f69b1220a9eb0b60f2d58d454242e394a1e5b2ea2e62648fc922ec8044463c083851747149848d00461dddc0351b190592713e9a2fcd3e6feb1f27d629ff1e8c4ecc6f4e7dc424cff9f0d78ed85cc114c84028d1197b52fe3aa237b3a26bae8a75a5d577d5e63f31cfb44cd7eec8ec8d9c42e2b776b7988229d65670dd79613d1b975aa749d6f34ccb8771ad2f347edfb23ba2e546116b6faa69ec403d600a69109bffa658cb20cf740ec4977a73a5e2b922f0990287441fac7f216eb0b8bf43ac0f41874d8a82080941308f04cd4e103ce44ddad11aa2a50878a18686629c4d9bf0784f22755f17f8f5eb41043bc04abcd8c4ebb92a60bd5bfd760560dab25bf245989deca3949b6bc8c8adf6b149ea12d38299351ab95a94ab275343c027b444f3090ae7c104384bad13b43c5dfc2a0f3ce098deafb678b3053bfad03ba5124638d38ff00db4948edcb0e3c3b54f3a20c9e09d47828f4438a87b8eae6515ed0f5b0cdff69c71388cb08a23536893e97ca28c51fb8f30d5b3e2cbf4d723fb9a7eed26c545d65e147a9ab4a023373f46eef013f5e3e127eac7d7504f94eb5529fe7bae57f23e9b288b973b3e1d040b8f232e34f4458bd6c4e58c5d351662e8c8f10831fbcba863636ae4e698d1ae71283145c6389d80be3948cdda8e85568066456a987ad4cbd9198cb42e6f52112a124d59b6bf91cc0c219b19be3f96b4434974d9860c2d768f1ef9b294932926698392986640cb85b7f6e9b05aada380379c334c7172bf0a2339ebc9902dc2e6ebcaa64ff5d36f0049ff87433b6ad9b52c27956c4ac80773e700fdff44d6ec5a86c902ee6a57ce562637053911dd15c6898967babc5f3705eb9d79160e4b98c3ab68c2d661b6ef39c07c99bd28be2770494c62eb81aff67bcd0210b0256bfbf2b64414598cdc55561be3934b647a75b5431ba49e1c7444815eded48d6be9dbf9e5c08554a57e706bd867eb54141fa310b8c9840c33f827ecc01df7d63780eee118d49cde2df3f63cb48f2305ea84ebd7ec446e7d14f671f4f9fed6e3f13e9fcc68bca7bc9ad25ecd144e6bd4b361062bc2e08375cb58896e083c31c3ab6fa2f7dcd3326d40e5f840c967faf2f074adecc9e1d16cab1c1f86b0f4ce3eae27655c1b1f6ef1ade3c8146a96e9892ec6439b4cafe623270b79a7002ef9c811bd7f72b2784cc624a55b12f51fea7dd20f928a8706b7abe5eb0b62329c7bd6ce76f26c93ecbfff69b2c3541f7521f37c3c044435b35fd081958a3dcd91ea38bb8e757711270150df7b070e990d06f6209e4a340fbac90c458390026466059ea7966dbc421d045c81d99ff31d42fb449f22a749de99c1dc398d3f9d08b1b825ebe13d97fce11ec960f4c82f35111f20be6a3b37d5456c733ad1eb19c521a864d44b856994c90068df7d9d0bded16022a17d08a200d23e2ddfb129d3b43771ae709ff93223072a586ac460beaa5c7cd0e248c60b614d4ffc1fd5fdf15daa6ba2067d4d3233f7071ef556260c514e5442b51777f893ba811f4bb99b6fb630315ca9e7ce95516a8c4ce6ee0cec4c9f77b6563b476f9d170f24c9e1b42d8ddcac025f6266e3760dc55362bd04a2b8c35f7585f04a1a18ddfbb1a386a47882cc1836f3c276c5d5a299ec0ac164b45285e3b00b24da068bdf4df4b6eb094abf20ef81bdbcc69cfce24e6c30716ef25b5456c9ef72b1e9683d5ca87acf5311c451ea7b77e91887316af446ea35f424d6e6cefb16dd1cc6eb236f391093b7682ac291eb3b6753c2fcd2070da509ad27e0ba9d809286522d38985a72a819079338e9f13e7bdb3c5732f562767e49677f3c67ec9684d671600954892936dbd10e1fb2cd6d20fdb2891e2aaad46c51f951e228b009ba0d9ff700e169e6d2ebec090fc72cb2b02aa3bafff598c132cd6da49475c8b3f6f5624c23d98f3511aba9162c22b53853e23cbd337da4f2265c96ad22c4e585b04c725661973dc1e8879d9dcc7f0939f1018ad18f785f41de0e14e1cd9fa28b12ab28f030083758730a7648d1e779efb70b79d811b6eb7850f7c8ea7f042742c32076cf3fd4cda7fff412b6bc9bf7b875795f328ed2e99533069bc135b8a49ddf43b99dbec363f27d55a113ebbf676c1603cfea2286d6b019e8d5dfeb8eebf7b7b9800da1bb24d75bdee602d6bbff7d95529dbd1f605c13a0a5eb2efff657ee03b45c594751a4a2d378d7dacdc132c6d17cb59d4232cd308a75a36e9c926d8863c08647359432682d551930bc1bbd8c33a13bb27f3181cb202466a455bf7c7273d9f7e689ce8a63bd19d5a936ded38ac7a3b16eba4ab705a8c90d0ce3b7a070263838ae50bc01a24e77a0681b8a51ec35f40de87af3eff488e7cb3c764a3ad2c9030ac306e8c23535af35b8a2127482b94f1bb15f9562ab45b2992056ffd505fccc81d00b9807ac6c2de0dd52f2d8feff7216b41e00443809d989a29f1ff8973b7dac9c7ee4d785bc6bb3834dc7beca2cff40237c559edd88b4fc77fa78b4e9a9af2050c7ab28be5fbfe676c5b3b45affdc7d5fad9f0847058b0205df44a353a7fa4591d7bf640c1f3bf687ab85378bfe421e56cbdbfbe7ed3dcc1f37f7f7ebfbe7ddbf9758bfb1ce4aa9b55ac8db23a651e5b81ab568fde8e1f2a5febca8c745c1fdeebe91c0cea77fce076ce67e8f50443aa0ef4e0d696842c913f8b6f21a18f2de89551036818b109ddbcc8c51b3cea6d0633d022a8ff445ad54af0d6909bb0c3d493d683126a0420d4f616772b7cc8fd7647e7cfd98693e9be6d3be7c5fd105057fcf8f0e3bc62133f2f2d938c0522ea3d008fb737c009309fd1fece204cfebb1b5f8948c64e4f0bddaa8f386f3f4c6874c79c2dd1ea8e683b7abb337d0778a1798a53c2fc15bd63b21bc112276eed059fed114d769f029ebb12bcd57aaeca498c1f10d25ec62fd62c9a99b10495e568df8082c1701d6f817b50df17a7d5f9bc0925e9ac1895dad1d86d643b4ed73928ae2295489f851d6ab1fe2e30b7d28b49e1d53f3bae4920415cf3a2d82bec68ce69aa24d4d1956e65126e6e5df5a9b69d770c90b19c668183f3334f6ff7ce207df868fe0cc991c21830ad78842786af1eae55ba172539cdb4c4d3129f950ec033c5000c2785a2e6445cd8ea2ad180b9ab6a87f65ee01e60ea3283e48af8571c069b9a174ba06ddf4c5af24c2360c818ee2dbea9aa8018ead7fbcbff8225a7e960656008e02a1e623c2e98248d024e5f3692995ebecb38eef6762b0f436ee63c638283c0416f073bf84e8d6dcffc6d3c14406aee709a09b5864da8b2053bfe6495b74812018b9ae5578a70fa33d613a527014e3e8eb42e174cd4c276fffe7a160a25af982a698ea72a6cc861e939b03bf90b39e3048a9329fbef9fbcfefb097034da0f44d563e230f1753b3bd5f62185eee53a5ce2b0ca20e3a198ad03fb1b5464719ac141683718a5e86514bd3143d21562f855555f48f8f1d51d37711067fd14aa9efa17033a73c51c35e24e07b4cbb0701f861bfe17c732be0899cc3ed050f0256d856d8b87d2bebf5ea872bac128d0ce90d2113b0ffce6816447b2147ae2d402eb0defc7bba2ef0b76d3191bb42aea2faa69dcd77b0995cb23906a29144f9396720553a43666041488e56d7ea2b5ae8ced0b20b0c6700c982f2ff0546f02926373d2590c12a522206c0fbb92b506f88886f0c292cb8cc46d69f38eaf4827c13af9d73b172127d4452422f97264caa5d435a895b2ccd33ac1f31348f4aebfb40e3a7bd40e1f4e4f9023d66449b9afcdfbbdb46654bd7e73181165a1a0d32f73f64f47852fa71b3ab388d3bd7876847ff2d91c48a406a3f9c29c2b5dcc99bddb4f4265b791bd729cf3498621e7bed269fcef28847f16d072b1efa8e7aa7d1cc67a13bdf0706a6547a2850802e64fd014cd17a40a5ffb900b8e158099ff24502108168402062c0259ce1d00ace760dbdb40521f33ead4d2c05423fe1fe2399a4a4ea7f85ff4f1e064ea7a2fb6570ffd5dbaee3969d464f41b9aacdf4d4d3a9592369c0dfcf37400266ea4290d84c60a998e5907aafc7e22181ea185393ac88bc9f1c05ec20cfb522811ed076818ee4233286347aebce602c465dbee97972cf4089cbeffc7e52fe3a135c80449a8f681531da526c4d2966e6511df665dec3b3b3072b110b44f6ff29534acdcc384835b909d4caa1aeca61ff7632e811bb6bdbd95a3a42cece11d2979b000b6c32f8eedc464d26c610bcba07301967477985aa3157243e8ef34246c4c5df72cb0d3d70a829ca5bdec55e895ecda989c0c2f3225a29a194628db743df6c41c82780c8a16c7e2fb0dd3d5dc1a2206f1d59be2c31fc6ebbe586f6af985071857a7a83a280fda984a675ded20fe555425962f7e53d693687e7e498c1815593195191931eabf0c6b75a690329dd3468a20ba55f42c538a60515f52a262092c1369e90aaa313eb0dd8c86bb91f77242fcbf5fc622632e347c644e4e2a9776ee4f22c97c2d1bf6a4019b49c28dd43bfc63611b9eda977ee06567996c3fd8dcf0d1b0d13e5987c2c359e8ca124d6f22c9777be9ddc683951d1ea694f5f4439eeaa923feef8c37b6ca9d1a6a2fb9eaa614e69b8d12028033d6c53029e238372dd24aea096b80f922f47d8ae9683b5f11747d3344b50b6528618b237285d4b1d147f3ba80dc4566054e3248a60bb8723c120e5bcfde575637e3e2c750c568e4ff6e60c725f2c071fa2dbfbc7e2b6891a07f7ddcb483c9b0a2c22ddb5db327c2eba34861b420031d39768c2f4d9c78b9d1c7a226bdbb327e7b33db01a7a0f73074155d9a067b7210e73ff2961c6fb2e37a9c21098bd3b918c89132b69fb1da8801425aad7a545c841bb0b17d4b3715e969b7592bb727e8a542c645149e31b3c5d9e80f25198b751cc0901e675ef4e0b70dc526edcede9289a1c182266af2e22d33554e5a8bbc221b484d0820089b14095aa0961d089e48a501a00ff27ce7792698ef687ec0bda089ed3ea6898c1036e961e0f7303fd1683f3a8808ec1530ed5472b16ff1e7c7cb714b9e36fce5b8ca2aa43935fbffe4b75e2ad2e3996fbc11519735756bc4eaa2cb512c9450daa40845a459bcf09566fc1d9caa0fb84cff5a243d22c7f2f97df2b9a9216c67151642a9aaddfa3c7c423be8381e33a91e2515f0a54313caaabbbfb31688d1efd826d85526763cc0c335dfce4f9d2e81bf809db0a41676358dd243855eca04532accd9746df1bf7c463842339688ff982c76b156cb3a1445e36c8850bdd62fd01b64944db551dd604eba5d6b6c11adb0af70c51dfed2ad048ca559c6310285bfea495f9d268d0ba8ce0a2cca626bddea0f6b1357d7d60cab19884fd86a29256ba6f34ceeab880d2c124b66eb2f21b65193a112d9a1dad1e59472a574334e2d05bfb69fbf26c27306415a1cfcd5f3c931e89308ba4e730f51d19e433a444f3b5466e0c3745917ce9a1e192620959b70610a91fb1f469aa765542dbd83d24e390d66d17a6c695b93b748b806d87febf741f02eea0d959e6b2806be0f2f509b8eb537d147009984ce3e65f08f40d3c5115e8d2298972323a839317d057ac4699a7c880dadce372b964688d6eca64c6d2561c18c034c1e3b72497697e7364195c9d4f6a5940327966d7e6031eabc8f7d5d59384ac1a4f0079bf41fbcae93a1bff76a55aeecc81e959b760e9df199435419637b4f72fcd0f766c143376e853507b65eddd1860d088fe2d16af13f8611c24532ddc423c51981a1f9e4afbb00d094c6a406e47710e2a70429f8f9a526fade8ad32a0df4c59a69e804bf2c83088655af0a7ef9f662d52e4f3537ef1676815f35e6b134b9bd02cee0f306311a18be59ac61f4d892f8ea8666a1ec8e840053057b9f7781f6b647b67be0c2f1a5a3bc04c7e3c9499fcf808562481c661fc107c74c5d893f044d45ea65ef2958e5bd0863b7f8751cd6d8bbe91e8e227b7ff6f7223f1e04cf40dcc67bf8f319d15f9ee59f42e5c1c5be33d483e4804adb590522a4b3b134c393e95630965ce1ef6d2b7b135b4dcee7d2614e29d74b2afca030a9828a604f458f6e977504a80d1b221887ac7b78621ebde07cf48e6bdb228ef76dc93b6af91cb2ebb2619f52d6cd61a9ba4a24d172714f2030ceafdfa683dc52837caa4fc486158ff8952f7d565ba7c8ed926d87c0cae229e6675b172a71c3b65e18134378b2a505be1e57464d3ed45364cc4b6211f444ff5542b15a1c7787540655f0e669386dfbdf71ce04215c47b3cd07ab83d62825b43432925bb1304bf8173cc67ee2b44dba0c74abff63a9dbb1a2aa3347186ced26a3456c7d9ff509745926dcec59eab1b9952caa8009899b9808f5f4c91d18e9ac97fb793a4f9dde0b33574a2e59ca8b766322b6681bb2fdea7681926f4c44ce5a7e77fc97cacf36fbe53a013a21d053ae1a61bc7e599f8cd0d9df066778d93e449f88f31d566cad4fb960d9df0cea88d659e1d119bb193204aca172287e2fa838da612f1a8fe830d9d608833023ae1e76d8196007257b42dc7bc84d08e58721cfeeca103e0c31072a38398263d5a7e9866da02602f5b069bd5cbcb908f880d53603351ced3b16c42b4a34775a1d8636264a70c37f1641cc1abf6cca90bd20455d8bb25be6c0b324ccf166abb6bf615f049621f1f107b27392009ae8e4989998d41c3175f16b14d3f2e00937a6cda49c4d0b2df8e84e024e7a9617e60c24384c1e7afffe4d97ffa5f3e7f3d844b4900c9a862f8eb50003da829462b836f41aeb6366d5144c1406bed99869112dcd5bd317d39805d06795b1cd91106aae44c1bab89d561a10d8b18f8ff0340ee55b5be6ae7e992f43e010104a32a87dd4cefc9b22eda5b8cc8a1883508d00028593f37c51545757eff4bebe54e049800131011313435ab5b55a0d52d106680341aa0991f42acaa7e92ba35f28e366b4348b38e380768804c488a879b4169d62903149061521117b6ed117b504aea3806c9bd25fd722f18f9b87cec3d8c5dd201a5e50fff472ef342e5b5fef2c8b4bc215dca60396952c6b94f904742a32582b8129dda7252aab27c67d325f70efc7dfafed7dfd27a3857aef04a6f73bf246b6cbbf4dc808c53b75e0c04309197d2fae8517f5569ee2d37847955f93860342a95cf1d07eafc3c8ee4d768e7830e919a6f2b457e6027d00e1bfb81de3cb4bb81eb1f28a4f00ea5c86fe057f40e3b964596a675d521c2e73294bd550bb75a6c52876fdef9fc7b2c79393054737eb947e4e207fe5c5d83970c2374e1010972977f63233a30b16b44906cb79e6292804c0bb18b88778a56b8c2f033c38553442804ca91614694d550433caed1e842ea98f424fd961244f4240f685867f56d79eee47cf478c980aa565d387dfb801dc5fb6aab8495b101c60c8f70f818c358cb0d17f42694091848e1f7cf19481a14f63110850b44b43c5de7b213b258351f21041a6699ed66dc6beac957d3d954c6d4b1ec06aad8440a094b71fd1eaaf760bbcd71fcf60d1a8c3ace1d1d71a4b03ee3a5474f3ea559af1407ac35f34c71829f79f3bc37bc5fdbc06f3fb009e65c296eda79dcb11c43151519a8b25721575ccf2980d44b0f6377228bd402c3b610a37d8c583180eb799c1c1e10ce6adff05159e7f5896c82c55a13f8e4491132c41c5b0a994d6c0450170a42267a5f6f74cb68a4df3acbcda01d801322b1b503df8a22f0167d78d77c78c7a2a88b9acf267107bc7c83806ee6600a7fad3b25ad437be444d06b718273b7cd84e4b899d2fe7503444c10cf08d1f94b9c7d216c0c8d61ae259bfae48f023d6a337bda25d63d57772301f326667a0e194236632f21b76245d2a55d865d5732c3cad093990203667affed0e1d4a52dad071fdb62cb15517f7372b8d0cc2f3a58f47741dc5819d5249a4f1f0b8bb0355dcc0af6987b1efbca899857bdeca299540e4caec63a4064144ce96e642421c765dc88cf3ee0b5bb5d77126a701c12167ac0ea3eb9f6b40a5a72c2b4076c3cb5fda24cf7298f00e110d8ef7e838046753a293db4c8366191b619687b4e1e475cfdcc076d090e52ea2674c0351c8772c555da41530de736f07cd5e02d1279822e49d0d41ce8b1b6d7064fa8b1c5264ff9be07b3d1d328c74629e9808a04213020d8ae3915397590bbcf410c2715f91b458d93ed1d2b574afa9cb4e5825d6a6016e131b302688b528211d3921958b173525ec46d6bf35c2c6600b1457c9fc64c86bc068bbc4f25fb349a9238158ea8a356ef353aa2735e6c57a763cd11b71fbcece2818c575bf77de51a1cee947997b4d5052e60aa3fa6093665007a6a454be7a1726830d14811a3647cf0b7734259b328fb30c3675c2a822d48bfb178ab3067cee114cb4ae9b0626942490b8cbb84f13d8846c57447f41520f22e3d5d1091edb435906ace7e13f674fbcc192fbc42364d91c5261b5685cddd3b43db27bca40252cb81d314baf91850a91c8251bd3a09925e5295baf389efb85b5881c93857262c79d3a68a18889ff3c6551e5a397f1e9fb7fdc89fc64e855c7cb3a388bd4e183e89ecded635fbb810767d1c36e53f60ddb709f3b964a2a250205019c3c5e627deb5d3114383fe94c807792297976f77b36870722784cf61605a4b8ac736de01b731a47bdfe2c5c74c2da59b0f80e2e6ecebc073f063b78c2e7ce9d2d5dfab2addf6468bb6583c9bb15bfd3c96ed311e9e80e93a75113b473b472ea00c006c98529a129b6ec9640f8a6eb613f5f775dcb5bb75fa95bd4aa8c064eda43bf4a5bd6d114077b3484fd61e303cce415a8e3e0f3ca85203b4b8b166e4806e29e12ad86b6b3f8fc70106c250534362a470ecb4f708a10f10c28a305dccbef8385e5434a2ed35145fd183b07c106ef52c635e060ab91c5ef058669fbe52dfe00d20c67ce2efd357b97e1ca5ccfef0f44cf2d4123f4048abef938d0360337526e674b866eb0735d476d8a01725134ef5ee7e69213cc109404a8b4c9ae01862e9ab8ec926af7320e5b33e3bc2bef144821635778d3387b8ca14c219125af1e3a068e410461789dcd938bd7b10287d63f0a52cebb81d1680ab18bbf199937fa61f835c3866c212efbf7774453e2f8e4e67f9b374413ec1e1c7504c79069a669287932c2034aa27a452c85eba647c6661b8bba1d0a0b580aec897912b9f232ec0f1cc0f62b145188262c4dfd7856cde53ca6b9fcbc9bec67d8051d0ad37ff488461f6e705dc7505981970106d0118e190d6a412667bc6c32580b2e9640f4e122eef10a330f713475659a412866082b88b0cee00982d6ecbfa76c522b81c3842737cdc6f6b41ec0f2f1612b164b46f2a7cacb562b78b20c3e5a63e05a84cd6ee8b06dd95611224bd79773887cf6e80afe01b7dd973e66230e14b86a983b094079186839a5bceefad9ca5d72fcceb67ab2eccc22c474c598b5530ef4d700d141eb6c37b711e875c0390cb1e40cccb99d6887c20a643aa5e8eb237c9fafa510e2b536395c43cb82d640ef8f66453d084c5b282bc423df0b2ef34226b474a032763a7fb24c68a646f0b24e87a86d1bb98e55e1b357e03649efcc81bdf50326ac2c278ef6d1e124a35a030b1f51406595dcd96a6f15e7bc8e01b95d36c09630d23ceff662e0207339c241c7fccec49711513a57f6c1af87e3edcf3038907cf8686735ce244d4a12bacec4e15898d506d29666a462277141594d42fc88642dca563f3a929b6a2defd6e80fe485580a29f7775a49a722a857d712fbd5d83fc9bb18599254c9a657fac0ec24fc49de99ea5e3dadcb4c516d90dc4c03b693ec05a8a9b2a29081af744e7a543560a1c5fc2c49a6ad288ec409b839025fc87110f932a3476dd15f98cf31159a000619b539a0779a74c638e66f1d850968d299d0f0338412f4344f23fa670d61a420539198e3179c7dd724b05382db3d45001bf4e63630552b2d57553169bc140403a0a3d9ee4a6093631de37769919d829f271f22e96ab4eb8c7c93f70a8016b1353918c97dec506af6196ce646fdaa4290b73c27ece4d7046d6d2f01d9932cdf7eb71fcad3ca9676209c586c77fc1af71c4b3103b1b029d818a5c3562f31ad25d5e994f77fee58a6a2aa646fd0bf3fdfbb909b0b2df43a5597414a681216b76626d436899f7cd39ab5e0584500c89e1d12b83fdf27656cc975a9840a134d02b42ebc809b252a1b0eed11e5a752731ad7ae3f86b6d0b9b30dd197230b594d6d6509884d2fe749a59cc6c57de86e426ff728757a1e69019b164cbaad84553755ca49b2e177779f350e801dbd472f2450440cdb43f4127014884bb54bbf6bd9103301dac0bf98c5cbf9a50d4e9f8d27f911e3fe96d2fc7ef9d8ee4631c1b3dcbf419c4d75b45c0e06a30b3b935319d9090e46e72c45b80193c581a3a0ecb248729ebd73df8abb670e4016374c0535454cb9b7db5d8852d695006a6a57e0ac37ec5a01679b9545e2d2d1407af478b5ecaa6fcd71e6ca19124cd763d617c2337f4f03692b62cf4e1414d03158628d2f84823b6dd1537470bbdb331d64dd8bd3af99c8c3bbe6e7ad8e4783e939bc14f02fe1b9728b88858ceb1d15f6fdb70e41288ca7da4c310e2cdecc67dcdd29658d8e0411402d07ac5b5b0d8c543529bb47ca63b136d35a6fd152d7d75b80e4a22952f5a5380de55d9e9ae64ea653428811bbf4a3ef642b9ee5bc6e63172ddcc8fa3eebe6a005a21cbdaf19c88f149832533d2056910addf8e2e6402834fbf0bc1550b8f50e062a6aa1efad2865adca545fcffe6a59c2354e3690046aad3a3383e3d530b9230998ddf30f17f8e2e6a01a4473b3b5a123e01ed2a2588b653e373770ed9ed7fd65763b5b8688a3c43294f9499c2b490bc8966e9a6f92718820fa9ddca9a5fba169ee208fd21b93a766e6568ad6e3320ebf117c706d8893ba5acf654d451ddad6e94a9f96c0b7b93b26bf44ff11bb90c988ba7487c67ba0df34777d8a6e385596eb694f0b6de32cbe1ffd6991d04734e84d693bcd0eaac2f77a71b4cfa86b2261f4f6cf4c20bae3d190259e809c6dcaa790974ee8d8357b8ddf5629637886eaef4f1eb66193e7b03c03e39ee05c455556c1b9c3a7424b2e3d95208cee82eb43c3b6ae3f3ac1308bc04060a827748579ae36b8dcedadedd0bae2cd5415dae63e59242d4c7e6f72f762282626ed853937075b5936ba60f3574047ec68dbbd587e937ce8088dfa8a1b0cf72826583140539abdc067f363608c3bc336227d1a659fc93c79a28c507a1dc55c38b7e1041f9b689002f337eac498031760c0c18545c0d94c95207620ee004025d6e5f016ae3be3c3adc1c76987e6c85675488a5b8bda7cc167a33070eb89ace2a9a346bba8f00cbe5e35a03173abedae9f695d942529f1065f37f2b093f6a3c3f9e4f06c3f3f3a18c84c1381722ed3a9d60dd16bfdb8df5bd5e3d43b4e26a99282410cd6c170aad2447b4fdb792a0a85c6a1de9311180a5aee7cf454b009798010d04059a279198b08124998c992cf7c0c7b8a7560fb81b6471664e5d6b07cbd5a042059dc3885a3af12c014a555deb4926fe57f042e45a5ca3ae1ec01551993612645ca9d14474247de7877a3425c6f168f181d89c565e1019e7519068aa45cd405eaa88d8e31e1af217251a4f5212a7fba04169c846a488995ded263800e881aa465ba332cf7fb77fb5553cd1f5f1fa58ada81e4f9d7e57afb1086655df2fc36f844431aa9fa18c0946230c2b66e684e1880c85b91a365d9efe4e049bf0fd01860982971e5a576851d345b42f38a09b66d8b08c67f89aaa994d4c4a617093117c9ad66181629e30b97f60b441b07ef26ddae5b8373474cf19205672d65dc2dae1fd8ddc0ed0f6f038a97f0e05bce39b23495e24cfc54fa5ab15663076430b68f7ace3809a5e2c0bb4657653f86873ac4e436d148e7fa7a6ac542673c7c1808121a5949a0e05e82a0f26a1e27dd09fc39953d254bb899f7d8e162c4c6261b82090947aef1aaff747a143f15199791997d855460922df6c8c7ed2d3f9a6174f12c4688929fa49f8d612162fb0c393f4fd65842a897e13f577ea5a4e275e641e63615d5c84c8fb752106b971c6451b64c08ca2080a4c1d18deab6440451b9cc4234b682d6a6706866ab083ac91c447a74ad07dea4806799296f70cea42ac36802762889c318115180726943e43d70bfa573684c6f61a532c7b2231f4073ded38bae71d4f680ff065c88ac923a908bd83d446bf387dfb65f15eb86d1942c58dfaa35da1a41279b58abb05f7bd3df0684c387e86b1f0f647ab6127f9e64d5e34ab0e571fc669d651abe08a35b2f7ce3d676121ee005d7ab0b91d5291e4b7e026639ecfca6357883865ef9a09a722c6162c37d6c6b9e092dd9e03c7c2b887cc4ec5bcb08943b271857ee52a2e3de24eb03538055d7a9a1766a59a84280148bc23658d741b3b9012e8ae410dfd61e87a174b234f7979d8b71a2253995f0d835d81f4d4b57a7d282d16a466f8bae7531b74270cb3165ff8be75b2fcc07d2a75bf16a4ff4284458ad8ca656d28b69412cf23e1d2ba1889082c53681e7a441c4c165599d8f0eeedd3feda7971bfd4c460fce0513329f252af048ebba13d199ea6a137d8175cf3cc6e1f1ed09e6751b7670eb4dc7f45d6d3bcbe6c938ec02c7ef4dc96b1f8ddad9f5a3be25eba2ccdb4aa9b413b2cf6bd5b5b5a864d9e7ebf7fa4bfaebcb6d3ee0f997e3f5fb4f85fb60904ff6b80a7ee684e8aa2b9c81b9b65a4c517aebd19a0172b92390dfdec93d3ec7e171f6dcd65276b136ee6bb3d99ff5cde5654a1fcaf0f997d3ede96326765f02d5068107fde8048f37c61d611b1121f088ea0df321128201c4bda9ed9135fc71cda40c29678f4c9721e0d1b658d89e2e914ff3f62d34bd8beacf5c86e568160f2967987a4d6f030f8baca261e7aaae844a157e568d7fd4c30376dc7ba599215ba4cd4d2c8b6316eb44fbecae33046fb1ba32fa6125b8035c078d49d975200151790eaadda431952ef60a4327b4bd6cb2c5976de7260edaaab321d07a9e8eb6eadc1f4631068a1103eb333fda4ea365a503312963e7fefeff5f89a737f6386aef8f8f7987062f6870fcfbff7f25592428c0480ccbaca2f46ed6edad63b49ee096e351f40353072b5dcf98784610272516fccc283b0274cfe7c73338ea35597526ff6f3a654a47d74b17748a7902ede9858497e626f637210a939445c52ac2184f674f84c8ed8b8675e7cc3468abb8605eb283bacf342b1858f3cd63d76127c9182561b6dab9aab322cd6acc33fc4a39fcc0666b475a7a75f4659c7df20463af267db837529fe1106dd57e6082e854a6905aab18c97315c05014508148d8b1f54e94b135db9a4ac2aad0680cd304f2b22e6b15d859acee6449bc541815da38df76ef3c28a0c9b54300ea8bd27d9c5e09f13cbce3223a286e6dde7754675d445284f91aefd24dd463d8fec9b8d1e6956517ca1e884413ecd21c88edbcea76c0f87ebb4fb4ce52da439a0759dfa2afdf54edf1b89ac2139b016324b6382208e9a7e537cb94604559e2212bfb527565df174599a9baac51ade0b63fae62d16e7efe0e17787ceb750b1fd0c7def96e453a343ceafb7695c0e30d5978af632480f0b2833e86e8fcf894f79d7173a04fb3bf98873144eae2b6fd9117866c6dea7e2a6baebb4227bb5d3f7be3c69343f73c7debf03f0ffff316827ea9fb7aeff0b3ac727aff36fe5eed8fd2f043b2d478cfd19bc5ec461f3ecee83bf706133a00ee0b0fbf9fd1774e0c71577576219504bb153c9334797913defb3692553730d52a96059428402e5dfda820cea8889b2f29d31c8787c6af86c662d2aa919ab243e1334852e4d7685e5e3bd76447fa4d7317bdb3b13ce251f99a90a67f6f6d1d15fa0196c3cbf02934f74dcc46329cfce936cd5d419d2aba9e241a34140a44ba1843a329c9aa9aa1829d0f231cf5c9ba8ea2c5800c32debca1cb1cfd5a701e661bb0e7a6dfecff57aeab8cb8667480a72fbbc0d4b4790027edf4a124ed05479c4a09d734b6e283803d9d2635289175efaeb925f9a7163be49ef99a01ff89be0b50e26c92a65d917c0489054eb2a3292e27b55cfc74da1cbee637c386f0159c512257aa5137e6cc82faddd93225f07945c834bad4ce73354ca3d4906c662218845b99904f355c197aff4e045e9691a91a325417649d2587cf031379004f2c4e99525e20616dd17d32b8d8854925e17ca7d4b554adca1497179e5d839756984e13b0249c6f57bd1b15bf08a642a2726e466ab5c0c5936a90a9ef0163c3c86ab049598f57b4adcf88c323cdf9bd300beda67395cff7c78b832702ecbecdc15ad1bc296f94deb95c8f0165e6994a6a34c1cf9518555989f488abb5436c8375842b398dd7516da959d013221c4991b1eab8196bdfe104d52ff2d641d68a3b98b3a6199168769703cf005f30e6553a3e941979c6ebe052ac98ece7c50f7228d985c32d8ec0f53c0f41d53f4051c131cbfb1d7c731ec87be74341922b2fa105f5139f81c8142507440a0c5e24a7ef068c1823804d1aa2dd40366683f115274fb3baad178c7d139daa61bb722adc27a805edf7feda3e3da5fa65dbb3b0d8596e2111f686a3af4ee242d8426e7f3e23cc0f0946c82329055769c4a00eebca57045ae28eeda8007dae6d80c9412888a5cdf750d5aa2ce5654abfc71432af4292b5a3e1f144975496523591cbd1bf2ed7b23209b2869e40b1aafe21774ea87dc9d0b1949c954c49807d5e794839954826b719893980a1b79ba714327ae925cb66a62b545e530269f831270ce14a6e20173ce34af2fcebfd07960bb1f0ad55cda5c19dd8821d47f31d6c40a622ef4373932dab1ed268d5faaa265d063bf953e8ccad322121324ebdcd6ccb9d934618a08309936dc76127db0460f487366dcc6ac743ee398dd5cbc8e174c558c24ba7beac2ac98e1bf5fa45aeb502807ff77e7f632afd7eaa46aab467ee70c2e574d9f7bf23d9c8795a3183ca7b771ca265e087657ccc86772f0b3bb67394459de5c3e667a248bdfd948b2cabf70e4e65a195b8f8bcb0f3865a0656c6f41b3ead9c58487a39b29938d8480f0db2f16c700cb9b124e3a5de826798c5e3dd5baddbb106f92257fc0e961345a02e4f490801175348d40e95490aede1b72a31425ea6c2e22635f454703ae493f1d791e6ce1f538ab28c73af731264a58274e235d37a8df16190506a231f819d0c9bcc1c02734a18b087c9c2af4d14f2b89338869229d6f9d7dc9fc9fe14e0ad9f13d2d9357ecd092305c60732a723393c38a22a8c5d30bce20a8158e20ec1b84c71b8b847d9266701f46473cd492096b4f46be9eab5b2f95cef10aec20501c4a5c7a9ebdc659e4682cf8009d83481246d45573ca3ceb3d8b8b1599910b48af0f92b314612fe26f4aa096cd935f76fb9ccbdb0b6e59e43c37469833c8842fdf00f94165575f5c59e4cf9f5b0c9dc8f0ab00bbb87b0feaf39c94580db6fe75a3bdbe0216ce07ab91f419ca3a8cbbc1ab4f20c8c16e0d388a10197c7c473104f92b8052ee9c4c88ac328459c3a05582994c2ab950f6712808b4597589ba5962fb32f41db41a4763000f8ff0340fed4965fb5ef930b662ca1a7c3c75639c965efc1129a253311468006231149c6902a4df1cbfffb66fdf8a9254f05249054d658876101f4cdcc07926ce02dc0d7bb37a5cf1f7d59b27dbd7bd1d5821b0b4061a4560825ef55876d585061090a003836a459efda6ee562107458a60724cbf1c317c11867292b238c171e61503622f672f05b903bf3c177d63ba8f5fa4dbaa9ce46ad7a04a096d2e7b3ca19b9cbc77141d0e2b422927d19389e2c11548e3e9290193eaca3382cc5acdef2cc90e16a3d0185378be016e118de68d52d9d88ef2e59ffea11933a2e5a3334ce0d80347a9f5929223d647369d6ceb6ed3bd1c8941a11a1bf45c3ac8f268b2708937b46e54cc8cd4604b723671370f02b8dceea686d95cea803c13bf69b3d9d4f96e3f6f3a477d1c2d25dc41f67dd2161265c6f8ee46178208f87eb029179b121b42803ebd294a7540cc8351a3b89f06a9630e03b725880b1bf3b507e1f0b27ab73603c854d7b5fc4fc1e90321897ef27d35faf9c79c6d7ec202c92110870200b16d4f51896948a9757a55e0917e3ba9b37e6f7591737c9bb5e3e8d33982b66ee9577b36e07c9bd0ed11e69602d275f74d81c40d4b49044acf81d2940e51c8acf256210fd372476aa42a5d608d7e9fa3950d4c23473d8231101a08d2426201ccfb6dc318f22df0ee79975c03b5c0d937e1d02fc558eddc827baf6eba82fefa2e6bffda5e2794a21059324175f896616a6280c37f7341562edb6a8508cf9f8e0d6c2981815696cdd9d369e2aece25988e891a437c89986091e858f48a13f66e4f79b23113541ceabd757d822fe4fa28c21e3908d9494a2518c81e3a63eac7d331d258bff35bebc3ab2aaa0eb14b25d0dce9329ce5643e3d8b834a3451b94e8b89f46919f481996f0522a1ae2e3b2dce5d6e3c964c32d6f138d185c251a0cf3696cebc7e4202a62f51af7a5d4ec274e776b631559b53dad02edb1871092d0f9316e666324a5584f30af29f9b3e133f3e85dea588a9c8db6d088de3466b0b6611333d85af7c767b02e9a364dfa235d149818e9aeb20464aa1ed952e046907b23822b680d296660db7471a554204c32acd057df2767a02e2badbc56ca03644cb55bf820a076ff7c9cc9b261b7a34d4fdd1af3867337b38367711006e6ccfd510cd9199433f354a857db05419f7a924f4dc9aa9a7ea4ad0bc8b3a94b56ba9020d8b5e37b95b5c2de047eff48fc48c1c7ccb7981b67eb061a5091ee1109330c108e433eabd120b6e15040af1825582204514ac7218dbe408b7b75cecb6a9f8dbeac4179b6209d9578cd5a90b892fd0d1ca4328e84baa9f535e3cff142b973e225c6b3eda5ed10b249457886339cd0edd1f84feb5e6538c22f9903a4faba73506cb05490c0707c531360d38ba670e1d189dd03b3c72f8e741b986767f4488d6475bd933befdbce8cd9ac757b80f1bcfe329b64435fb3f18329c62bdcc0fd9f003642ef0ece0f2e0a8c5c083f54eb23b5bb4d03b9e44be4f7c590475683bb258a6cb224fa088505d21f861432f1baab2b21ec3241a75b74f2bebba7bdc17690459d0bbf760fc4511a270bcc90d80bee830b32588ddcac3556a3b8e35a57a3ce0fab918dc0d8270aedd77d01b230acd885218464ec04fec1cd6d3c68442d9037e63e6f6a50132c67a3d28d38afd8f53bf825491eff1209a12377a69ea91f42178aa9e7edf9a2d360141e1052f5151e37f78e547ded2378c92a9ba14594530e43fba76d919ee6555b9353953627ee48d8fea60243a0852ad2e864c47e93bd97a3e6455ff36c0210b171e75d57d978a1ae48b38db7d5fba99e3edf2f407a600a859e0e878a7a2dceb8244c111413287d67e8b4870f9cfc9001af1a68e9a5ecfeb2e24998a4f5517849abfffd72b4dec5b7b9bc01c5692184bd1741ab21b7926f070259979b6d02eefd9547036303905996e36618db78b1b376f33276eb43b862e542c275ed9cba4258c127c89592cc2e145f7fc3ec4f63a5ea45efe34db52c78c51ce4b1775f69bf0d9e0752d999a14c0335600feb13d32a3c451a2adac586d48a5e7077f3c01e1a8b23176afc6e25beb248cfb6d70e6f9afac738d2a1d3bed47e82055ef41e9dcc75522bd11208ef33b4dbc894a2fe366c361f79bfc363729234f7dc8906853b41db3e6ff60eccefde9e070563092224268375e47849996336f3e0b11cef70c3db1bd5d67214258c3714a6c64db88d6ebcd126a53d680c803df3fc7465db3352641c246ed71a1d98a208dca61806c8cb4a77b0d59e012323b99292379bace4534896a0d2eb9cbb28b192a5701ea469829483b58f6e51ef7686e004cbae149c54f12910e2fe8dbd893ec44d8172d7fbfde2e670f121ccf000088a14d2ea1047aa9bb0a354fa179ce6e4c8a42a49853ee8df535ee1ea4dd582320f9082ca4ea7d8e44935a892f0105ef9992ced08d28ec1e376875163406c5767ff2a8b8d30dbb68381b551ea75c87384f219a27c8144259f1f94cf10a57ba021b604e287073d651a6db627af58a50f5601eb93694a96af2a97abf7c07dcd398d978e1392da3bec81a51d63caed718389ac4dc244f1a70154c34b8e6ee9b49f242bb63eb548098d1fd2a676b625504bd7ba221138eea9e0e6caeb361850d7b144aad124f3928103a78297e442944c01e0cb52c5a280d0272035575b5726492515b12d0a8fa0d9bbd68313db499eb9f7b118798d1f8fa6f1e5a4650988a8ef8f0179f1aa5dbd21c8b28ae54e5762132be3fa9d9fbfd2ed3798bd21b40f98347e1f86a28c98936239dc8a8d884fabd21a4699a124167c6205a6c8db1f6f3efffd17bf95fa365b07152f620f1d6d44ad859855e2df1355145f951d36973677361c46e4a04068fc751858aa9d101202e9e41049dc1e84b1e9016efcfad0a63e1076df3332c883ec06dd57d8c24b192beaa7eeecefde6ea6ddf6488af56254ffd739de403d6b202afd731745c9f2b24c89e37df5ac21c5fb0ceacdf39eb589895847ec535b7ced110a97b7dba3576382f02c96642b5e44d1909c1e44cc5c3dd577a3701faa29a03bc1c32a40e913396db3e38ceb593329a787ab96110566adda3a76b167757e409cd7a5a181bb006cad550a82d415601d573d6c179e0c421e319eac8e636a1696c081aa02a3918e9f7bd888685502c825281f7ddc999494d3826118e88b7f26d5f6338116abd6b8758814b3af755bbf7cabdc6e57d0ac7591dabd4ec76ee916d6a9ed8f4377b4374e2f567c5a1fd1a39f54f450613fd12830fa265e5199b24230f95bddd878f360feaa91220e65986b043d972402760f6549c49041e8ba1008541dc2324b21d5247134663e8159f171e6fcf696f5e9a9537ac1624cbcdf5b22a812320f02fa85f691094daa555852f92aaf941aeda68f0aaa14833b836e08d46080bf53d718710171be42ca90df0ff0389f0e89976381a83bc5e4b14f7dbae853e3c39ebf4aa54f1cd326e96cf464670593acc4f614eceb718a3c1758390a4ddea71dad8dcc60322964e2bd1c607f18f5dd71c239b9ed31292e46e50d104faa60946d213d35354d09f18afd7856870edd64b5155f7bcca8c6965159c3376ec358d19661e2b680f1a1729ad09bbab6f01db6ecff6d22b79783779303160d7d44890ca47cef756c83b6eeb87103ee476b24d8a06de6513d65b6c7c9492ea32129a33458a08dac005dd3ac5f1a46cb112f6bd719686cdcbd7abc46664ed1c8f3f5c992108be58955517bdcc0992172c590338cd5c6bf2ec0daaddf8cc09bbd06b461bf48fbc7c03618d35dffe95b958b39555683d3e9289b79cb1a766aaf4d670a588adfc2ef403c0305d9f2ba5fb8d853861e251d2e8fc9e913467fdafb783d9e74da1baba7c1ef7a43828f86201388a976e3624fd1bc281a3f92b98f069089f77066944f5a7db05268d6431fc450f02600262d4574cfd227fa9697a388cfd1296408397476a83f1033081da316ad8f9e0d9920c899cd6118762fd0fa49a962f0c27a0117666edc3af851ea6db8ff2b626b9ca93c28218b10f97a4f16bad422c6bd8b9ecc3bbb6fbc305e92a335333111eaf4d8b4a67cc7b6561d362f8bd96e2b013923b9ceb404ed0ec6858ccce302adbc3110d5860d2852e5d0b31bcb79a95aee1e85719141700f27b737bf0cd691984cd7e9b03e3172e613134ef4c2f69db9f099d9ecc28f144d381a01c6280948978a2d779f8cffdb9c6ddb3b00054a0a7b1d158a6cf432fdf3e684cdc5131beb6ca32f70a3d69a0b7853f239e7152a9943f1adae43b2068e509483b52ecc251186acd66ec94b3559a6a7838c2deb4bf6b000e3629bf5fcf73a825439328cb0c2d34f2a5a5dc28b61d50b5c95ad97a8bc031492c60e97f36e12ffdd1a2526b5612c757679eb40d23c728eec6bba2766796d77fbd4a16bef2a4375b50c1efd361df5e59fb5c97e1bc24f62d9d113e5df895f27ed0d3cfffd6f6917a4a9ef495d37cf7fffaf3e1796399d162a6955a461fd98e861225601097acc61301807253ac087a68a3cb7701806dac028ce42152b84b4362ec6db36095f71fc9519638889553edbd961fcf5fb0377bfdc7318440ccb65f2193b92a81a3abff51bf3f7204dd0da870b3d0cfe28d2a7ac9402f33c793ac2ec9fe3e9adb54cde44687b9b2b110120d65212a7a0be687450b75b8f48c162e1a075c70961c584400c526bab6de1ac8db6d8ae23d6e952c9f90dd502e3d9d766e25d0af5d58a0386892015f648268e64bc17ad204b24a5eecd6c08ab43751753fbd178567b4d7bc83f8ae71c2564b7b9293fae8fe8141501724a9eb6124ea47e0e475e3f60a001395f23b303bca62cabb2107c02250e5bf405fe8f68b207db29258cc692e7a9a27681e98553e5362e731c69f81a48d28372ad25d34398436b5d229b04faffa80ff1ff01a17e1da36c5307836cabc8611cff5d029453334325ada79d9a2e881b3aa57893334a15460983a1381558be4a0c2e52b867323be6e069941c0eea71a50093ecab77de1938a9aabc28b374c4a8b23d82a7414289419e9ff58dd33ba9ff1e3ba197680449f22b1aaaba669c55687816253b503764813a261dcc80cc843c84322851a7fa0293d1ae732ec068b8e09af9d869b3bd70acac989aaca2aeafd2d891d3545a7995e9f547b07ff912e5e0294faeddeba49fe4f695d767696fe582292e5170dde8596429e4a252cac76103b44538b2420c6cb43fd924d1fd436325a85c58a97a138bfb6a3b0883dd29dc1b4f58e01d38a8e6b7810a58735a6132a0de9e51b495c19c8db653afcc8d782a9124396273d4c8761ecad2a2ea4a978e1e8ceaa184e51d322772ddf3ec671b6d8227ff45fbb714007b9fe3757a2e5f375b0af0fa8d4100f077671630cbc2039c04729e5735758070c383c783fb724478cbf354ba554340efcfd2f16f7beaf142338419609b0eca6a0cc8956d3f417b6487295238e7d487abeecca7336a8fecfb8dad9ef8d345d3844d8e23955015aa4072a55a6de9a760533249b679036dcbbbc229913808ee45e1b0dc5c70f064cbcfa10740860858d25a25f97a98dfc2d3ad2311cb89674ef9cff1b463f211b69c760f3e60aa1a1cc2101009ca06c56bd8ba750aa062ef364dd52ab57667aadadcb13d672955555506e10b8b698976830e0fdeed96a4042e03da211dfea819782479e56c93a240e5c8cbb9d87a76a700197981db6c6381eae29be0b08734e3b33e58c962abf0eb17a0f222d6030b4f994a6cc4f8f16e9092b8366c94516459ce72b60fac9392795efdb8f8d4906004c95a993b0b417dd4bcb8cea80be17eff114022cf569892a4429a05cdfd35fa049193506a664c2143cfb3afadeffcee0ab02befb065587f521425c8846f7b3c26b1d78e202d4aeb522487ccdd83144f8361fbdaa8ecbd10d9a93ecceff3c2f8f0c798b326bdb389309c9ab344e13188a042cc56bb7d5abeb328d7534c51af5b148560c2bc6eb2564d95a9c8ed154b35b684a12be4ab4c42b18ef753399ee58a8221cd8f303949af318f055f8fd28cc293c03652f94e56bc2a642ec0bbbf40319593080276fb133e98cec49456ec08a3f19bc9a1e20c2f05f4eae4941e3a2138c97caa1a246489dcbe79d296baefde6435da76faecc36a4479936d0da7dc4bc28e0e34942d078deb2a19036488fd8703651de5381507b967190239ef283ff4d8546581463831c4df24c8eb48c69d521518a8c96179a187c1ef997db82804368929d7958890e3e8749fd12a1c7df7557082a6f05a483ad3025d4c6a43abd947dd48d40dbe321efb35381f0ab3e08f004a24b0a543e50414f06554f816f8d4b294cec1c612f51d4ecd410a6f3bbfbb8246fac1d7274270972e44ec15311913485d1a92dcde431dcafb0f37b688f341fb4d42051b8cd42f39640157cffdf5a3fbaa02ef0be6eb467b0063bff174b1bb13401c2eb8506d13d144d3e88f1c39c6256d50552aef8c9c47b19042765543b1df0386062512302eabce92d7afb9bfa675e8809edc9de7e06400f8ff03402ed355af6f972f311ecb58928d817b3161234c4acbd6566337a01b2bac24132ef9d1d2de00b1013144ce0c18d0f7aa0a2801ed3a29385edcfd1763754dcf4c8fa45da79491efd8a7e0be013bc84672d61d01219bc8b4ba5efe0321595c9055473ac91612374a5ce9489c6348dde900873e9dc60db2bb69a16067b6d70471731fb329e474671d1d6418bd7c9f570ba1a2f0ccc908d264873677db8e42bb668bd80d17895b721ef76958aa716dd81e5133c2a8e3c77cbd625cd84a7067738856c799bbfa0c06b70c97335e77c9ab31af927c52bd39159a405730953a8883ddba0e611b8e4fbb5631ae8ca16902d539c0b48aa4e8867def6ef63183a4cd8a3f906a28475dcc4330b42e23227c7693b557837b7bee3a4acb1bbafff1233a5b3968ee10dc8f2bff08e97579f68ded54e3981d68ff4cc43bc29195b4671fe18698bbb9f89cf8feee11ef61b6f13470f8cdbf1f1003ab2c828c5583ad9359e3d370da497ba377ef19f3c07c378dfbd4ec6a88afb5a73b28cbdd9cfba38353719817ce443d485cdf8094135957c1894a6810dcd3678c7ee8f430248be62837772f690774e226bf1d2dfdab5a445e514f98336af049d22954c37f0d6bdd2f20ab62c431159c3d6c299079bfbf486d4a951a75a60c68a4c232dc20da48380ff4f268bcdbc15499b0ed993f8a6f28338c50518944ba7b5c15fbe3cd97a63b7e09e3da4a35be5852f81c46c9ab3085a2fe1ffc011919bcc71e1edd04585903fb80f7b95a1d701b681b73afdaf621fa23311683bfe00b5c52c6568aa9ca19c55b48b119d22ae909401a7abe4fcab42afeebf9c316bd721d7ed3b8739b73f412d33324c4e2c13c7a8f89affc47dceeacf2871c2eae2f2ee73fce677717b976783e6a053b439ebd0e8d683b7b8afcd9407bc6a1ebc97b37d0437ccea06bd8218a2e4edeade1e6a9aeda0be2caa1c545dc3f841affb66668ec0e231f4ab09918cc6ef01353b8b23b8c58a8c263a62b2e4b59cb91c4e6c13baa1a85fdc59b3abb67807f167ac6cce11a8bbdb20770f579f604e879f3566647166ce96106f72ccff23246595fc60454ea14022e62c99db807e7e57c1086142cc6529cee36e4a5fe6e15b210e6274877f628fc163ff5350e033a534218c04548679b02725cfcc3aa2ca4e8efe3fa2862f42d59145f59a2340c05f87a2021d55ce93a3ca0e1dc293ce73a9445329fc17789a706e12d686633704fd504e1931796607b3bd37fb9afec0e138a30c1bdc968a9b5dc4cfb0a4d46767d2673daeb335f7151bc830840e657401a9ef3758dc04b336911b639150383f7d30f9b60b435b574882c6f60110654436b4e0e405807923b98ac918292b1f0d6187b055a291e42a3b098baf9f4ae802c32a0d105d3fa49f04985fea8543cb00911f3d828d529aed5318d7569ce9c25ccb495c6e5db6e863100739c05368a810f1393291b18e7a289aa5576bd46629373858897723710df5a6a9c1bca1ffba07cd58f76b9b1fb400a53d500ba6ec40e91b4c9cecd875113ae68fec8e9f9f9f8d4e01c132953309a32dcd151b3c6b32a386641678282a2bfc02836cb61c6cd9f92c9313c9981c2581dff0aa77ae336ef34d9f5ba65a301f442f01b83073ac4a7db190d9ba35ae050d14f0c9e660f972fba2dc2a7afb642023fab80a557391e85958ad82918972e0e65841300f875c27cf6212b33323be08aee6fa6e9d5f5c3659a4e212196515ee00a9c8439fe08f386f14f45549a46e7563c34da93e28738c781a06d7372c7a93ec6307862ab24824ac19d3724eaaaac4a176390a1d231db9ed1e27488686f011e4aafe0b87a6f3dfbbc04956ae3509dfca6af797c8b823adafb0403fc33c9ee30cf1156a2c6683e989e0a0c52a6ee839479577f7dae441aad963d92000061c4e7593c8734f54b11e1468f0116cc05bbdfa76de2de693a554a39d3784ca1b791d0c0468fdb77a006a16ea5a1ba41a6dd51f7bb60c7add3160562f9e3f3a51139a4e91d35bd87e6c04546fe02736b5d38069818e842dd55dea6c39cf4695d824c32192360c4f218b389dbf99286b78d4c1d2d9aae0704611af64a725f45e690a6f7ee48cf2ee336ad09d3730b0afad03f8bc191493c8a09070b7722d1968029c6d77f3233ad0c461af1753a35f8cef1815100b93af3d34a079941838e3b32c985346d4d96b5f7c897a6cc214d752fdd0b4d6b1cff56303f0182c397b95aa9e22891e9d1c1aa0fe5e5266fad9ef825829b87cac87a3d1a3d611ee8c402789459960ea01b6e0299a9a75e1be7c16a6fd3346ce75a61aac1f8d69ed45465c75ba7cffdbc6d67bb1fa45f3a8da93ebd5462e76b53175613604ef5a84e330ebebc7592392c275081f2b4cc17c001987ffd52083eaaaae4f5ac9af5c922610a067f320be8fde4f173f09a99717d5672c7fe1f97c56454bcda97c4f5204f590e91a53d9e8750f204aef03d47e415ab0d407ff3f269062ec9adae4d3ebf8010bc18d53849b4e16983c4c949fe7827c70534a577aaa84825d7f8ceb074dc80718b3b31493ae4bdc01df352e3d16db4912a6f641ecd39133eef5270d210402b06b78bfbdc27e0a2ae3226f9a8872dc1862ad00fd8f1b85bf33a1b7efc3f8b5ad63b49624b9d71b90a74bcd48e739619804740724f3317a14937f6b24f12b1d3631a82df614ab01c63c3d53f172b7152c7304388840bc992402e13f87253a061a1f98f00c31ec0ef116f2de3d6c22d263348cc55f4b93c5a267699ac3efcda32b1daa8651269b3595f17b956751f367581b9bbc2b5a650ce2b8bfad1db8b040fa9f236d28e5582ed129f780e8047370fac046f209d8875e2ae0e7d885428b499da9169dca7bc62188c68cdd0b4903721e42f2d0a0846c83ccecf22f853282f7779e1745b1dfe0159f53a634df66ddcd503a260d549b310801345b1d53d5003eb1f8d12431b8f0db7bff8af25fdd1e9e6d8afe964a45294f434780ab86bac9aace5aa8e1af1614954dcf9a8c2286f7d6f517241728d248a0e6bcbff4fe6872fc027f57804da52b42d3e0ac1d44902acfa76cb44b5607064e313e267d1ba784ecde1f7b951873bbb6fc9f99e86ee26fef18d4e20a490e1228afa58116356776fc62e24eef0781f5be6457d6f72f4f67a51d427fa4eb302c3a5c955bed8433665295987f2183fba48fb40d3a78652167325ef8364be20ca224f3d69a039b3857d307ad79e96a1ec7326b3e551eb5af47a4d59e526c8ecca552a78790353de8685bb0c8151c33b848166a0757016dbfc3a01264e90702b18b31d49c60586285c22fe11d4cec9d25029b325fab9b61ea6119a6ead526c901be25ac7f823e30e7a3234762c037d35bad1de946608e29061b059cdcca710900aafaf96689a078748ed6f925aafe9be40b870ecb396e3e2948e5e7948ac0c87b364f0057798c17906e7a7a7ff6570dfc17215e0e00cf1215a11ba11454187d91e557cfe935553c9d93e16aaf1924e174bff3a96f41f15235b3c6adfc11446c78ae1fbfe6b39063d3ad81617e4f7e6a2f41f7c9829f1d34c1dc77c1096fa21d15bddd050cf413a3166f50d15008dea3be78ddd12bf3a0bdb810b784ce545963bdd9931074f7abf92b4b734845a0496d563182ceee636616d4d17d3e583b6673c1aa3fca1c4b8afdd6e719e623fdd1d6dfb1a6d4e789b0822091bb50b8072043110eb7e242cbacdc23258038db4b77c0972d26d4393fd9fca8b428c9de0ef6dcb75092716c51059097416f50e15a9277e33249fd4a3911028f75bde0c2a804a8294346bebaa6ca1b80e174711cd22c846c7738c883d6c2b3f6a2b694ccebacadbbc7adf274ed49ee21d016b4570a7fea6a136cc76d163ac679c1e3bf97c33e7f6d7d115690bfff30eac8706f40d485e8eca12066fbf1109b4347c32b5eb5edea8b5180180cd25fc82847a8d034d6b8a563442540099989a91ce3ad5852340bc50a917f45e5152e2d1f7d136eaefc2c457fd6621733ea98438d98938642a461507df02903ec246454a36f99fa671637acd7625e362b5dfa00c36f2b65bd46285734ca61d155138b33d4b67793db25e7ed45a39bb34e36d21d6f6544f8f73a0d615d6439dac854cc4eb934907ab5f80cbd1b82cc421d995d44f43a0efd985fb47f62acd48155ccde13c3de8c4af0a502846c8e21c7206f76ee7b6a5db3d99931c7ef00e8f575e99cd9d3aedd02931029aa4751f0b9e57363d83204442f2c5eda529cee2cb34cdfe87f594d3346def727bd6f2c32c4df3107dc633ea66822751a4aca7f03034a45564a04bdd3f91a6e7b6a584d9fc7448d31caeac6419b900a8fa6175cb0772b8eae36c4b04d561bddd407190d5780958a1035165d20314daa8da24d717842ad498ecfcee179f7a52dd41e64a104e8ce91f21b053d7bb6df833ad3376f29291ff961aaa15ea51f7d3c21a51dce56cc59a505f4d9dd7ea6a6af7329ff7eb5e6456936bb3620f541d8ecc7ada587efef37854eb8e86c1fa863cf94eb3f1415c0d8ceeffef05f305c433ff27e045557834e2b78c62a2bffdbb9b893cc93f9af6336431f0e3e676cf3c9a77e0236838c7f39a22102f3dcf620d7c7b567fa36fe70b268eaefc6e54673adcdfe0e64e33f1a048dfbd8a413139599780eb8a0cc80d498191c56d5c7fb80b93524994becbd23078523bb5e49d9acbbc898c576901c525f42c38848a9ee23a63938f19e82e9c190a3b1c5fe21764973f2380b5ecd879abeddd901d844cd9afdd1e0d6ad598e1ac6a825be7165fe685451df38cbc1edfa854fbf4f528dba03c73bd1bf0f3b8a32e955c2b9be1fd97e3d245a468c32ee8e2fddb506633648efa8b40bedab6cbeed606a84f317993f4800f9e6b6f42679d216d19a56af2f8ff2a69524fc00b59163812b7033d6bb42b110d3ff5d5189c26605605bba519844fe0ce36caa08994f981e4a063345e2928e91230077d76b6d626175c3ba35b6e82d693a78a6f3bfa650998af77afabf0bb786b2bb645f5de43caf01154f009d57b0fef9e5016a39ae013efcaf90845163d03362ab4c70de179d350e764834708d6f5ab421f2887aa9ba589c1391d9ac4104ebcc28cc40f1b9115144d01818140f31c768a111631ab8f2b5c25e98c2490d287fa9c5229e2b0599564728dc72fa0c9982738dd87e8d855b16c0ae9a0cb08d638e837804652b87cecd40a18beb04eb4ac32e7a245a6360435a1306f0812a68515440c537334883d8f64d53a395a5d7e1464d266dd11b2d32692836bbe9d2d64cdfc000513e2e4fb6078069ecfa07ef541f042e8826ec209f4de0a19f30c5e9d4cf6d8b5374f3cee815dc06c8e3a12ae93db4430579c98939eeb186ef82a8d715a91b3a27e77f439f3dea7114edfcc2f361c9dd67456e4cfb87e4d91a487e234405ca5454d753cdfbbea3aa8b5177657a922f004583268492124e2acf80e695ca20d491f26329a33ed9d662f11a00850a291de2aed3452a27127424e04079bac9fb28bd9b4303d94ca3ced03a995d4e4335b8c2bcbc92400452ed7ddd1aab99e14f4600f24e60949e73b63ea69a69a56b4e542a0cf90ea548b23b20e0c0638f412a068bd5847b5e502741455aa1a5744f919d20a11b248652a3ab9476095fc9e691d11980fbb27ff86d9cc42b24a3522106e64a4f7c7e4591fe4193feb9d6bd9ecbbe1deee8b0a3ab74604b6927ff028df0f1d91d338ff0970d6f55a6954ade9bf3f7e453bf2f71d919bc2fc5603702527f686ec0d8849555582b120de948b0fabd716fc90b19b0755176741570736fab07cf66b08cbe4d3e3c7cb42e89841ef1af5b9048ab057819609189f488ee5d7780ef79d75aed26e5c18febfbd274fe07abf0988bf6ecef2868b0247389e350db9806eeee0319872c10339ca35450495148f6b200b9589965c32d6c7b76e09a245e5ca79aedc7e5dc4eb7ca6bff6624fdb147938dd6c60b0f85f0f00bb527141563b01b1106b728ed586d3d0d4050c0bed1303f7b39cb781809ea2c8bf5e69c92ea00bd281504bd06aecd4ace2500da73cc380ed0c2e289e9e6bd787ed8f99757d10a24a853082757b15ecd005cd5bd7c21dffe010038ecb24ecb7ddd0805a5bbfdb71dffe867821caf9344fb0fa6483fab8fc6435b107baa2fdfe8ca64818c6ce91c52d1a76edfa20b64e1772f52682fa0e3413df6fc8a0160905101e41414bf1e191e2c731407b7e7a636d0b1819d806e773f4f914ee6b38e649fd5f4e7ecbdc74b92dc5165ef91e84e884080a40860b12a60b6b698e5065ce0a1dc38f8506d76bebed0560c15c624413d5f329cc32d4300a75fe55b6371016fc6fa9407fa291b408d0373e44168579349595d16cf65843a2e2aa5845153190376614720f2761450da7737530ffe8a2d0379ca738ef47f48608db50565d3076c0f774fa8872d01d753b9f69bc5aa9c00f692e69e8797378ff059475f3e15f3d760d5012fd33d85943cb4c392ab198878553e82aec96cc92ac2313fbfc026d2e91647266a072ca2f48ba07184b052e272bbc0c9258d28b23632e026b103ddc10c22e64cd8b5f04e4aa3abddd3d65fff483b54fcf0812ec441be83fbfd8a3bb6c441f8d2bca8e8043c77dab908c7d213191632115619b9c1288c45639af2f6351d463620657aec3593403cc041f2a809c4600f68f5df1c0617a3fee225be123517e5a6ec99e039754e844f5e55303a2e03dfafa35f9289edb279ac3362879199abf379a2cf21712132ee4609f6c0576e00730300eebbc5c03d92fde7b9f58a5625c74f7e20c274e09773a83d48ba7f099c3f9336b00dd0c6f21da44da84673f7c4244ff205373ae1562dc8a23553874e410299bd8f7568c1767659fd73d261bfc98fc9a9a969bba9ae6feeda21c1c995bd6a9c70195adac01bd673d7add967a854ca3695b62dcbc86cd977e35b5cb202f5f799e0cdcf4e6d0115832ad9186754bcc9601f8ff0340aea5daebbb49f744c8807a7ea5e9d2ea5dc7d2dada33020f203bf2eb97a50009138744a8097c1dc0dcce28ec2a47e68854eaeeff27ec6a74e590331274282ec88cd1ce5d5ea7486d646c9391ebfff7aa3e6f9500216552ce175ebdc942ab9bf73f024b4cb85066e23286c2ca6961f90de2e4a58caba74ad8b17ac0a07cc608a8f5510a9b545e299896ec9e35156a78c256f780d67e3483a508c78a307bb536b6f2706ccc85ccd19027b188717b4d33fd78d7d23a490bd29f42563cc9cbadab7d8c4086dfa8aef67b52565555f7463451a17e93d6418551bd60fe39d629afbdc24aad09b949d62e875d3e17666915da33ece9767027d9c49c93814b81dacff00d9be59f60ac792f9b0fd26455f7e4e2b41901674af4c97be030e129da76228f3489a25fa787331bdd7b1d62bc8820c2d191ef2325fbe0f61e34d27c3367ddffdbcbc37d0c77207f8e90a6321ca30bd0c0b5e5330fe28f319b13789d45a3d6a85bc0459be91b34d6b3a3ccdf8f58749f58a98884015fbda9db8a0971b1680dbdf34eeb8e36cab8ba1e21490cfa73242a3dad9cfd832a22eadc4e65c2cd4566a0f5a65527b1e2335a8dcb39e7b0e241b6ac3dc796cf56e524aa0153335a572bda5778ed141524e8706f5d04042b53d1665748d5e198c60f82b4d7b04ac0b798ab6ff2a9fa861ee45c56e7790a8f0b40d077961d6ae3ebcc5674714258917dab9ef7cde8e2100864aceb5fadac326e91861ef7311df8efa1c31ecc01812aaea58162c396dddecd9897d87fe9361630d876335f208ba361915d5b2acd2d48961f62fe8653f00a0557a524d6dda6b9bbdc4e3c5031542f0bb16a81e9e48e47eaa82fcbaee850afe68336c96ce10ba3d78fb4946cbaeca55aec48baa924523dc4f7efa6afbaebc80604e910680b84e91a93a31b1c57a0158402c35c2fce2d1ba0019ad22c395997464784699fe7b36e112484456ed2c652654ca64acc4fb166faaf4759c22c604faf1be8a9aaeff19063f877e480d7dfc5939567cb79ba47cd7b88042619bbf96452a7ca7726fbb38f32b718a35c75b51e62dd0a464bb651853a0cee692151e95c4f7d464c4e551d27b1e1fb37680218eccb30e46c3ec3be95cd10dcf8910a853dfa79edae1b24f048bf0fa7177e2f4d62f4e9fcbcdc7970d6cc8ba6b8d64c4d082c665ace6e7d92db3fb433b476e082f792e7d48398e2f3d112b427da9bf9a6a83dfe969d46dd12150de0e11ede6c4ff9f948abc507ac28563461ebbabdf8a9996a9666d1fa4423e161111011da47939bed1a038c6edd41a53331f3435ab446959fb9060f51a6e7a030cd3df3234116f190339fd3ce5957b0f149b0b9d14557811c8e80bac76732f89ca57c09f6f63ff908bccdb4fb473fd216bcba516a45a5a6a4be8bcc74c187da6d3a868dbe9835abd117a003d364e0fa5ea288529c5b896e258c0545eea6a84492f39d15af17a7d52a0ba6870445fed066ec3902b515e282451a93a94010bf09f9b897860b9a3844a4ba410768287602800f86143272fd39a3921894566136cea17eee2a30d45a86447b91939073be513a0c6aa019b6b63308402d03fbe97ab7791574eb278bbe3b13ad1ee138ab6862197baf9f679a9a65dc2f041820ee7400d9d09b5daf09ae702906837666a6eda22c11f2ea97a2fb0d2f2f678c3c33760349f1295a8f8e95d0ee8247068f6e8df46c875fe4603d4d6f9d7d073e09bd7b5e1184f1d3e6f0568fb589a267f6b6b8c5f5f4d3532c63098d8970c05af28d3bdf65c6debc038d135299164fc752c1dd26320cf20fe73c2bd3dc64ab31523acb78d3cc3e9f1acc4bb88b783759e4596a93dadfcde3a147817c4565c29b8f454d680aca88f3d8fa38eef65ea81c2c1f46e733492da8c38b6303aba3af7ad2980e1e25c913967aa3d9bd5cd54ce3ccc6ba16ef62609fb5d3989d44e67d6004d6f8ab608bb3641db0cb3e0d9ae8e4a15a753cca1e1f1233971a4a2b2baffc96c905907dd59e78660fe503e4d125d307bd3999f3c62f2f033739d3ab258af97e84d5a442c70e8d10cd128be9cb945e916995c6e9e23e973121f96c12c113618fd8505a43750c8a8e499480f0e3d44e25a4ab867ea3cc0517a3c6e804f6b54866c7baa026c42d1cc3f605ed4ffe18ad3c51a002fa50508d1c06a58047cab2f62d91e003f6e931b000f50b7eeaf0f97172dcb9e8e391d727f961d127df7574488653293e618aaf906232fc22a4fc14eeecc570a33b5fb7030f298f93d35c49d1394baf38ecc9c27fbfc74fca814092094ba6f97ca4e354bbd06105365588c09388ec664cacedb25335dd6d2d491ebebdbcc319cd6b3bedbd19c96113ab1246590fc4ff868ad3784905bca196ed82614e6a791973462d68bb2e0d2dd948eeab88d0ebb00c1def85cfd0c228e8fcabea700cb7b458470e78464c4523d757b602418052ef714948a6fcabca424a151dff2824613d6285ffb2f80d1e4f3fc0d70b6b4fa4d9311614077ad26cbda0db6d6bbaffc0f42562469243a365951ea0c466259d6ce096bef1120255080a22560ec0bdb849a20288a8e621014a8462e0433c7c325ba91d3ad3457cfaa83469338ebfd7600d5478fefd8b40f37b858697e40d104142a6a961e6d7453286898bba513512d9a631e6376d07d0b983aa9719c4d6ee2856d815322646508a757b38e54f9e54489373e5070a6cb7eed2b31fe5cfde20e38f7a4b34401c6f4a6ef3f80cfd172639cbaf95e3af78cb3108e2da5feeadf932ce2375ad4f58d78552d415579a2077f9ba5d38644a9618c8127b6c51a0204d6897472c616f5fb143dc9c0828ac0bec42935052e9249920e90be1ca15cb55ebe720004628606989a6f9d510c6b860a2247282a31b6e864b410840ae7872024e3aa4eda67dc780a9d6db484f9ca070d845e81d16bbf8c35ac8ea1d12cd7e4a639d0e00a9e388533025c8542f23bad663116f140cc99346ca25806936947509dfdb45ecfdd011b323f7d093fa244877e0127293fb04e0a3a6fa482f2e1f0a9b2e2385ade78033c076e351436bab9ef9bd5a4c4587b92815f9aa0152ccfac4721d3895d47566de778b407c37672cd2a3159f85775173437fb4e2a7215b34b8b137089aedc3e8fbb2528d1df19a22a8f88ebfdba3f9f5ceee280d3868455653be34c67ea42c3e6c95036a0bff130c32ea5b1acc4a39a535ea14b2637ef45d0834638dc7d7544a96b6e39ad478dc9bdaa8c447ab11472bf5086b0558984d48070b4a61d45217cc4a7f0ebb5dbb7d81f691efab5b3a445deac28cd4ab453e81c8b6800fb6832eceec5f0e7c9cd9196351deb667948f99d0be668f7452db9cf239e3d74fa990718bbdfb566e8ea7608fcdc84b318ea7ae024eaa13de6039a4ff47ffbed72ff5c3fdc2746e6dcab5c23765229c05aaac2f6fc2854b31e722a1d12b3625be6b216aedf82b31e25bddf99b47ab280591dd1e3a350e887a896256f22992253438962258b81682ad1bc165db7823153217e9304bdc09cd22ca7b350042edfe3c3573d44a623d3874080bb5c20da9eb6bc723348fa7ef8e3884b44b0a7ae5b14332492e0115b6ed8c9532b2c8051b5e514c8c1cf9a59950a6fa42d78378bdb40e1e9a42d924e981af5ba0178fd722c9ba563eea44999f65e1db1368b6c71340af53c138a6d4657c0f3fa94fb68ca7a7b2c9df2fdc1bdfcf9a084eea02e2c5bee288412d0862d700e9f522da6629b4e757a111c2dc1c4ddec88018f3c2f9b1f1f447fadf39041aebee27aea82cd8b7cdf86dcf324864ccaf26d29d7a09443c2df38237a8442089e01e64031c7b7eede9b26412f71a747d630f82cedcef5c63390ba022f173b3786f20619ab79c7d8632cf45917fcdd9d60cb9daabc7beac997eb3a08d5867301f7eace43d99a3e7fcb046754aa8de1ec6a34d6830daf5b4e21314f1d370d3992459461422d5d522c6b279a6f08b9710e0f883d868bbc7a6011de1b9656465e8e91303279f85950518a90e68ce7f479e15a5a67e0d77e7aeefb6327f89bd2a3d6b9e64e00cc37b928c4d8eaff36b2a6d43da96945afd383c1fdce2b1551e70df2a06c54550a8f6b67740a7d913c9ac6796ffff9e2bf06cbcaa9c8c0e2a38687142be0a0bd9d9344da43b6e379870a630ec024ea566806a476c6aa27a15dc6ed3bc21bd1135c20ca143b5263d82530199cc7856b6a286663d6e18c14137759c233bdfa433e206a282aee30f8dd72581847f2368cee3610fa4519f31e31513920230a41bdcf607c513729093b656fd9feb81e6fe45c753915a67d0ff07f22c4bf2af6a4dfe300fba0ee98f551d31c0c4e401e27b73aeea7a5c90e127acbabe96ac92b9461a652e0ca743057b11c9e81c0bfb8d8355dea2890b51f0b1a7732e6762e91b789620fbd04218cd4a754a41b02b5a93a598e26b116c3ea41bf14185c14f4599244556ca321379af9e3c6a92af551b38d09c5b294576f2def8db3853af32f73b9467f86f94a69974620d2e557ba658c3b8c49162ffd7c378c9fe3c720487370cbd0c1f4eab02186df0eecdf85266422422d0ac3001891b466ffac9327717f5dfdfa3c7385d14c006fe8734d4c6d365b697ff5d38cd090abbe7b33162432287a0dd116b2285f2b34bc495ca8ee473d426de4d20cd5471f9d3480813bbcd64a580c228c5af6c3a6516a8ede275f9e60506cf1cce1dfa0e75f66a4830acde63231fb6cf913ad3537b5191cf6cc6128fc6dcf1ded2770d8cf4ccef788cb3b05a60d070e63c3ae1665ac6e21ec15a0d8301f8ff0340aebdfaf6f5bb49d78c1603ea49aed84ebacb5df4aefa5dc11296779e0005b015fbfd2feb27cc470bd03870ee56d513d33d43d840985dd2ee92d50f8a5055ef75cf9bf053080a7051e1403ab498ee1f93501c9f84b29888abec3d6171311bb37024773668e25ac4ba80c3a462834a48435c18c14d0c614c545e82ec32036b577726c51835413c22151b28aeb7e8c1d7fa0775acae4895ee75cf2f7f47c89f263af2f94648a02a89f5da6b5e73d33af8665681cbd97b0b123a2886c7b2a943e50dfbeb3bbff16b04c5c6d4228d99dce8d5d0dedda2a6a16bf87c70cd6f3ca04be3724985b1be5d278303e83cbb32819fd5306f548bb7cf8bc40580ab64b201946b961b1defb83a8ff670ca6a11a454df9a7425bec34ec8fb3c08147f246a753d04f5f7e9644ed5ec6a01dfa8e194e65b0a906cb86f63c031ed11a9b560de646114e40d3e45539e25673c9533d0e1c7e60c7248a9ed00b4937a5634b6c8f238cdbc35771cd59efec9868396b2cc3040db9f75b6bdbc5c2c8e2258014154399bccb34a341ecef5a48687ef38b32f027422eaace2f4b1ed6c1f0af567d123ca53d152336d9b4fe693dc693a21033c91d2232ff9a5ab32005469f5407730001c86d50bcd048d7bd3a02a488a081937274418369befa5d3750e787bc28b5358311a72522f3349a687dea8265a830666401c42f29fe7b4cf4a59e03608e57a1c03213c5e0ec83c71cdc156d2b09e41f212899d4f16368f813c1c4c14189a73670673387cd925b203e6950d3aa7ecdcce8844a77394e8f5c651deb978451ca28412bf979b8bd4f71d57cc21f1c9575b7e92e245c8da20a67695e4f3a3f35fe7686048471958cf99a76594e8d178ec8fb15bfe09b4722eea4af3b953e8096db17224bced28c450ed83086857c6572c43a2a7939a26c990268bb182ad0630b6d41968f467b6eeaa4768db2ddee9653296f90d8d0a3068364075e0f754f115064e1181f94ab07e388ed7c3d54092fb93f7fcfa87720c299f806e3d2b0a593f48631f228ce7e6306bc3213e2a69ee74aba271df4d6e2333b4a85a87c29874454e17d29285a989af0ffa370b7015ee40f842d9ba5c5aa12bb5ef23166f39741e2020ada0d84b6669928a2a7f4c057d39f09b32e28285c2960bb926fe1e0d672ba42d9d4181c07253322721176c9c2388067e44965bcd446f8b755382a57ba6d74e64c11537a3cead349d04913d8c9d18103ab4d88d01b847f4d0141d96f7e2c73e11d96c002e8051a553ff9b7f584d81a7c105f15dcf5b8b1c4aac8672c2b077c91fe484b0c683b3a8f81eed17d021081b12cb93c4ac69878284a9131ece5c4e033d20e6a1e8c94c9dd917646906e213e561457029067f9cb585adc09ce9a0bee93a15f60943939ec15ba097f60a9d79cc3c2539d93c057752c975852d0d944954724ef059fd7938bbb99bb7e5474d14e2a96bd4d49049a10018387d1d4227736b224b24c576e0474ad227bc7fd399388f6b27ed6c0eddc6e054ebdbd06b6fe1acc3ae4d2613a969bdce2ed8dadd8fc1d14e351169af5993f12384abe7947228a32962d244c9056858acdc31accf94871bd20098d927f2a5759780cfa627e34378b9ea88fde412228a10935b318ed208979c4f618f42b3dd38a2bf1e8b3cba581161b51f9969af4c1261538081c18a52639db840f6beef94170f100e55309b49938fada440279f062865848cd803481aef6e5e424c5b6627e70c7184751d1d1586e061da9a9d665861d512207c58dc6c8330b2c54bd021a508fa8880f2d448022d93654822921814673d9667566a6c1c427b104e1576840fc0e9910188e4a87b19f03f944bcf4a105defbc8c86406113af1f2351e831620f2e3640b82baa2ab47036efd6f5e91b92e6d47b00fae5de520f9ef1910711f7b830593c58b95eadf09d05204f634db98f392f3eee63ce8b8f5bad4ad68d81bf717d7b2f95d51e8e1868f904c973e2ec9a3875862da80742c5879b71bfdfc8a8cd6cd3e5d03bfb8d1692e759bd6432ae93e196490c185babe2e559be2a7f13b699e918782fcf5a3d6817553b5913632a91cb0ff4359f0b6657e9267912f31cc0eb6fcc0dff45775671c065806457a87a56786339ee947bc4dcd5ae5b2d1a2b8b88cd55c255d987dc9db04b369285b08c9c9c079c237cf999e85c7912f1ab2cc6c1acc5313204a862e68eb7605842e50432e71ad23148aadc5c801d0fa3dc9cdb6df9cba7953d8221200581801997b0a9cfa9989dc5daa48495af9b8fef317c0ba1248fb842ddbd6241885e171f968ecdda06dcb8c30220b229987f37ba10071d1addc8a46afe078e50f4f173a4d135c90f995196cb9f6f9eba711470f278e9ac61b838bd0b750360694da1f55f0f61377a51b91fd190d163dc78c95a600850f40f971f2f56790a22de3c0a902fa05ec1e6a27e59dd1aaf283ff80a41b49b726cc9345adab0af1ec5842a10a3f1fd076f1a09c49885813a279367dca947d39bd2e7c95130c39afc85b22460af107af6d84f2919c875ce46a9d718cf14eb3a692f70bc813fe8d14b113684c349c22d952a3a9f50de08ad5772e7b45c4e7355bf75d51eda78d6d6c13563b2a964524f6b28517c6ea8cb08af61217bf04a75f612f2ad980fa46aa9f93cebc1362aeba4fff4a6f618832f8160f948f7fb1ab2ff4dc0996877c955a416f8518cffb10a3d4c226157432c2c22079b5246390334b008f1cffcf599c80e0b633144e537e8f708cb8b9e2d2ffade2b683fc558d2534ab6733dc9f19218e916cd47ae387f03af1e51be756c8d84517d65a78d43def9771dac8b67b20351f05a8d0b63b1f372b3839e624fbeb88cf60a9b0b52e73026fde24a515b9c5d4b7443e60713f28857c14491ae7465f6731b78a9a9a9f5530e779fdeb5d584e724f737335e322e2a5ec72a0873267683346270a0ed0a64739818725d027f932a49899c30502392e31f161c90ca5def291b8f3e72aa577a16617be8488fe073eda65127e77718a1cc5c558ef0c17f12b2ca8966bf166e3a5e6a49fba35bb2c0d6e9985316a78d782fbd69eec5a40903d8888fdfddf38533deb64f0aaedd5391d7c863d12c5d740b99062ee71a19be4fb2e1aa94d51563fd6dd6681c9a45b380be15b29378825fae22a34748fbbf122ed334de409901b94ee8ceda28395024ceee4dfddf6d6f1a59629279fcb65a124c24f2f9ead1bc808282ec829a08f6044196e34606221aaabbc3fc269817e3d5383d3c21457b80f5f05d4fdaefb18eb220ed8f1eee1f93413506870a07e77a1ca628d1f8c54dee1f77f1de8c738460715e7c7b43cabcd7fd258844f95fa36a382ff3a6cc9ab2cc2a2e79933c1e033d4049d1da880a9cde63ce0bacd41df31d7822f31abc3caaa013ebec5f5116056b11e4da8220cc1773d3e6e1e57d6489301f548d36c301296964669e831bbf62aa2113512295e931536b22f6c2120c50cc1846621df375113d66c99c8c4095643049b1457c465c522194ca73cccb6ed3d361c08de60f9de274ddbfcac84530901d2ac1e0ff15982d1206bf296cdcf0a388ee1af83c9bb012b48fd6d908b7fa9d9d462cfb4c5e72770ecee0bcb4825bbdccde382dac35c82d6bfcdbe46c2ea3f5a1f5491fe2ebe2aba70f9097593cfeaca1911d5e6aa073262aaa4c4ab284b9355e04d8e9eddd0b5163c1e218d68d0eb64b86aa061a4345bbf2b5afbaef29c21fee4e535a93500f18762086d9babe2cbe944055380a6d89c0262ab2cbb1dbd49a2a3a4c351e69d7beff83b201f51092acd7e4620a6331cef657722a314fd2a7f987f8284a69734cf492efb6efff3880b8579d803af99c7eb8c53e7d927beb44923b8797fbfd3a59a6cdd228f76bd332840205b444dabbf721429e5925aa9ce452363a36bd350208a19b91bd083363c50fdef9b9f6768742aef0ecfb027f17ac096202abffa1ad56b3a98a249b7884e5f48a7f343bffe0d4501ab4e40f8ad249131d928eded8a7a04c5701570e11c69eeaec4856509209d285ea6c502eb5ccd5ab0debe7565cfb9a575cfdbedcc410a5ba8b9a5ca01694e8eca130bf087091538c8a16c943363bd02df54c1fdd06c40cded2aa38c5e97ebfaa927840414f7b24b0354a8a182b1c08d504440dc7f3e3eeac2267afa6fe6047f4b0d993c81efbafa47099303a4c4c56f870d3575dd4d61f2c4eef3d797d22e3c77b4445b3458b74e965ad1606f5968e0b46ea49022e979a0bdc7367c53fea037a5dfa962416f8be40fc88cf704d568bfe7307ce3ad37f135c10faeb88b291e3e7f97a25a7863be45262729ad296d6ee3e200ea59f7614b35e2d42fc4c0f3c4d2bdd5df978e2ab8a548cc1616c52a940572fcb376a0b71d3469e1b63f38dfbbd893de2a6702fa4afd5f3819d9a52bddf392f3e4f9ab32ea4fc2cef0c8843066f7d1ea9a3695a19295c1e56a3e86593b0222c3e82f516c93a035950d1bbb5ee4c72c7e953b4a4af6af4c195f1cd06709ab2b9b56c6a732c4c9720e75762c7c1e9e72b4865f7379bedaaf094d647388cd2718cd4488e822ccbdf6b90d31ceadc529ca6c535995794a5f8add9de79dbfb29aaccda635abf86b724d7e21bc2143079266e6edaaab2edaef887543ed566754fe0040d7795daa746b8feeab9dc2bb3a1077750d2b40ddd0748e97c4a25960a86c0de8d326993a0be97db4bd972bed52ca7453e7c09150bdfcdc8ade82fc50c00bb48227a3d48132d89f42d36a9150af5d839453e212c4391e551cbceebe81cf877267b224b516feb8bfebdc58c80c3d1d49da12bb3bd9bef2d66a1bb030c8793da33b2d5a2bbdd3730efe593c325cbf71601f2be328c6fb0bd060008b4270ac21708c27391098706b2fc4322294f7a89031e96bdde3d795dbd0da7bb9a86a634cd162c8b95e0760ddc40927f32fc5fef783fea906817dc71867a86960275ba33ecd16a931d3fbc16eea1db943009985488c789a02873df7c8c48714c7afa60c1c5ee6f903bc7847a366e3563c99557cef97d5eb0ca74bb941b1542168db86007bad8262366c8048393c67e42252c389d38d96709d2c19e7469f683fa8638c76f8f3223bc42640ee3ad61e3a4b3242e1df3d994661882dfeb6dc6345c158a513e94d35388aa949f1b3405e7cda68e60711b7ee33e64524231dd2d3cb4b37cf092e6b23b0d58d58318331a1e05ca2b3bd5fe38dc29e350a9fad1842cb92f5a7425e4349e45a96f17ab67f209c9193ee0c8b7d9de0844b30f6c2325ec1bd82958b24a0c9d0441b2471624bc96a9863a0852124ed7320ce342bcb6884d8bb81fd8c1262f7e6eb4b08cabe2f24b257f069baf8583fc0cccfcf63563c5e7858c159f4730de93c3dbfdddf2e370ca4a32265895e5b19068fe190e781aab21594359a8e5b3e942d9982d38c01c6314c8899eb10f79f02d4f875e398a20a99107b710e010ff4a9d37bf7918e8fe88d756b1d1845bc8e36cd205ed108dd5634002311165c3e95ba0e0960ed9d5a6d7fe378be84bd5c88558cc8a4eecb73b8b49aab5ec157048db803c45f1e489c735c94f811919f131739db62398f38634c5bf5961d03d136b3f5129fff7ea0a459d548575ca1c69b537a5f142e73e9c9a78d00e9a1dc52890e92a7756c96b5977fed49516e078cb823a56d5a18406f3fc4290eb83cd8a6545eff462065505bf71a8cea5d2c1ca41a8aa0c7da9fe4fdf7e703eac484a3a9e005d0e328d47cdb9206fa9244645972146c624021ef7cd5831cf1e773bf3b981983b3a709f8c5f16f5ecb59b659c0d0125be66e316be080e8186922d19c58367bf6dbf511f90c475a2a5245621344d384992bb6435a4c15cc317ffe8b0a5f46d0608014870b28a456f44a1ff887c99e56536183a3c7753efeb1505090d3f1cf5035c6a8d84211eafdc9781b7575cdf37a7bc0dccc7b249f2799386a8efa6063269d6e48ee0a921b97f129b0c2b7d15129a73154d91c986744cf3417c96617412994cc593760ad97440dc26b61fb414f3c928603a2921ef2be01f02c87bd08c39d96347482d9bb693dbcaa118060303f8ff03402e9d56d5ee858c842444b03bec0b29ad411c9a237858e1d0745f745f34df17eff7bff6a50c6945c6e544b80857b7ea89862f7639c0745fbdd7303d7f861783a4d6052c90b0e677cf6c885c5606484587a8f5773f77671a8f788010b867a12f100dcab15b0c68d50b7a588613da326cf59e5436c83f8599600ce2b7037dd8535837c112b80b54f2faf9c0f84bdaeeac094ca6ffeca47ffa549ad726c54c759823e934c1e1494e2ed0ddd4f9f7262443eb2f2d53cff57e85e4e9c9105eac62ae979503150bd9bdeabe34e7d2f4bc7e8eb5dfcb264bb86ceddd884dc6b7216e42b5de0b6d930f51e4a203573d16e4d2082e63d7b09e2264221b10224889ea717a55f3ae740d78d3b2678563d02e28090e47d14440f2844eca547fa475645e814d3e226055798f803c26aec6e70709c9d1b207ea765655356b4f6baa0f6b74835a57ff25d21da6cca4c2eea6d87050895a464447b4d16b86a2abec4427e70d9e184131daf3c23d42529e049fe81de73821af2cb6dc901d2c4c4142008d6d1ad73aae2639dc54bda625447a8f33ac9d0c4d8ec1bd4b3a94a16e979fc1f8c8b08695985f0c03d77f86ecd722ec8004167d1c6674ec23e10f762d206821d8147f8ce6bb9e17c45ede3838a8d5a320ab934c8f48090d1c5f111fe1887978a1075e16002231182a9c3f10a3d87bd30c81dae0f0018960b52d9d8708b7d2891db40a12cbcdca20762f8f8cab0db6d9a211e96a3d2f0c9d4470e155967e8f25005824027f1c4188e94c255fb2ad1d7b7051726b4999b72edc8ae3da0296b5e3d30aa5f3aa090de3cbf9c470be710ca458dc1838cd64114880fabc762252824e20a0577b5511538282b04b5d26899691f258331564d9ac4ffbd8f61132c9f690b7aadc14b7a104039b0cc4959c203cde72e0bfc775e1147719952dbf84bb7464d854874626e88c329bf145ac746d0c76287ff477eb340b7521f501665c83b11dc68ccf22bdb456014462fd8aac5602bfdd48c66d16276f5ee5d56cf90b5e72e1d575ca6fd8dd4ed4370d2f3f85d9f42ef2910b902f2b93281a78e29e139a70d0cfcbcaecd626033d02303ae548e11f0e6f284421fbfcffdf091b746dbd049f3c4d634b534e7a5d9ae374399690fe4044709899f30d5afd4a3884174d1185cfae57b5fc675cd4c0a3428acbaad68de750b3c06fa7b99d9aeb2c4fa8aab3d5922926d320f63b4d83c83701b53b7738d3737b52eb91f885d749d7d3fc592cdf5435fbd31e1fa2166639b7293ee02ad63a8454a1f7b6506a04fffffef9d74cbd759cb0cac097340886ae5b4b806710443fd3f0eb8456ea1007f9ebb1ade6dc4e6ba5a3a1f234dd35bedb014a1486cd33f084ad23cdc6d0c639d23d56cd67c36d1afd2e1c293d087cc8b8447771aec8095de3eebd213434eb5c1bb83974b7fa31e116ad3ca655cc06693c4fc8733eb084a85ed94530f4fab6586a6d40695ca23778b55220fd8ab6543f7959b6a9b30f6f6f3b308eec7f31d1b578e0865e8251157cd0432817023989080d901615691045beab12eaf6d889e3032aea3087129f6174ca3a3b53b8aac7eb3dd8c19be96c161b3f921f93cf85d5b4206a856b787aab8cbca035b0e6bce154ee3721bc93b6a0e4f2220dbe1e8337f9ad6bdd89aace1a7245e3db04c997d8e99ed521f0b4712cb9ec0ba3be901d318e8378827bdf2d5c230eb65ec67d472acead57cc11b10c127d52418a108a998af7b605d01c58bc6de62844ccf20ecbb6edb29bb3c7d48d0b0a4ff226c256476f19cdba159731b974baec2667a697008759cb582c08ea7ad29521d683af10c76755f980175bfb81438ca6d2bc76c226878c3c33f96906aa5731aa409c470c42aed1bcfb46f41f5d2fa3381ab0ef1c9d6c96420855cf3c0fbcccd8481d4fc486e43c2a403e025701d03c7df23b48bfa9dc48725876f736ef2b7142feba6925d2567b30351b9102dd8ba8340d5f24a77df60cc07757f7759d62bdccea389546537bfd027302f6ef851004a3339b33b80fd22d97deb777e7766aad096e4fa88f63899a9f71eee827b09988cdcf792ff6f60a4e3e3179783f555d6c3b77c420bd7747e65087c7cbd2f6a9154ff38e493b40456c284eeb83d8de62c2292434a72f8ba384b62993a972e32c80fb1d38fe4f576e8400fdbef1eafe60885850d2bd2f5d02cbd824603cb0e17ddf91f1049ac4c7522827b598c4ca48ebf98d976d4f217e1780b214ca6d2d25137cba390bec5bc92a97e28bc0d0698b86f1751ef88189139584189e9db5f6f0f22baad340debe964c27ab0c5ec465ae3410e0ede71e1eb271274b0182a185c9040c1908198697d5873b7f7f2c8b48c2d5b8b8588c766a388b4dfebb2b07dbb0e78a96f4c4a0e990c8d7427bc5f68492ebf58d208805b36ddbc528e186608ea24a9983e109189472bfbdac8ca264c40f5f82b4ad06e01b0e94256dd68865f605783759ad1b21af419b833df8b119687d2e6fcf02c4710e5a2d0e3aaddef02321dc3074845e4c3312fa406910a283f62836613085e2485b9efb461d2ecad9d2c91f94d0c45241e2ba051167179e74f366388f22cf99a344769bbae9691aeb40e6c1a212055a6169b790b53c42169cadcddb3b410915ace49e33448e4e145916e1143b3c90483e8e2b8461623b190076c2fcef5b8662ea3d766241fea517e4e40427979aa18eda15c90fca1325e9f5c5d2e042145c92606059e28ea7c8dada103c432cd428fdfdb8588c948cf375d6bc05d6efe53ab507ae5bc25bb6b6419f1d2da4f7d3251a6bd8d4e73659a27fa7ff5bc27aacc6349942403ff14deafb0cfbe965981850f782fbd200e1a6d02120f3e70f64bf6818ec1a0448955168ca851e50edf933df61f6f3f577aeb33ae60396103312f732737b9d531c777bed31651a4f94427be51e32a81f0b0f3b03fb675f3c8513d6492f7a54eb56fbfd29c0ba2d02470b9b6421c99d648a54e8ceb96ce9417ef6866a095a8447932d0b16f4aa5438e842efa3ea5ad17d05c1ff739dc1dc39988986fe8b9403a075c3d037f847d94c22b04becc3539e97c67eef6c09ed473284312b3599d66123e31653903f4f7111bec4b1d847dda61b8f5a9fcc115257374f780691d6827e1c80af52e170814401228f969306b873c009dea1d1815ae33793b2979b59bb3dec4d674c89e091863d1c3180245b19e725f549a591650648dd8d3af0cb7233a5cc938133e86de8a1e17d6274a659bccd8b239e1db4251283cae2bf42372f3f757deda7d2ead7e4f68bab6162987278d680502b955d27f122fef5c4794ea08c48a83edc03b54b72aee770d5a06fd66a92ced9c61506b98f418c394953a95d8433eb9e515f87d57e490f9d236552e65289aae0e3c8f1bbe38b598a88dba079a7014115a44448c80e97754d0d8f1c434043b8ef51574141e418e93d8e733fdda573e7657708cd36791026cd780d85412facb5c859221ad046d7a06db2fdb001940bf84ae89904970999582b179dcce397f9d72e644825512c3e92c6a038e222dd5ad5f2a1497e2a1c72d716c748d3fca585069e8912b8d836bf5c3b0b582371c6510c076115f9e8c3740eb21fb64ff5bdb19dcc649ee8ddfc493d655c30d1d2d1e1d70dfe99e227e6c9ceaf586b5b7114c264092b40b3aa1dd22d418132864682134b24764551ae462c3805c4881ccbf3b79df6e44088cc908d9698fedbcdcb047dc57797ce73398b271cd1dd2fc306f2b68a83912e921904b2ba1d9936331e1c64b65142889345415c494fed65b1e1e9524592c3d4446c9309650c82bc531242e91796156cc4d20f6ab2c77238292037a6d68651509893edb58ee132a9e2f05389d94a5d70932560a5698cd03fb827031dceb785244b5b2630ebbefdddf0007d2ff23aac8dce2b0de6ad54d292f5db9f5e9f705d7863577b3919cd5d4d81acb46f66c1585ebb6b0d8fab588ab0eb12854c067f1e0b990caa5959876bdf20e14bb26dbc95c3b1ec9eb3ad92c9f1597e0fda3693d101dbd3ea38d18cd45a5fda77b0c9bbff04a5c338aa60acb8fa3a09d626ebd6cbc93bba7b6df0b59d3ce334e68c42a59d7c4061eb495fcd8ceb187c6126ee6787ff2d04bbc84bd4ccfbb441148ec0a9c6b23e0c80961d625cd5b5bdf9f9b46cbfb55f1b6bec778f75e348b037f733e0e5c7c14f3b8e4f84fc16cbe3f9b0f0102401db9a54beac9fd484f9536b0496f4b058bff6396420ada69821b41d3c3a4a24c82b49157218dc30b2dd3719710305def64665dcc8116a6240c8c28d16f11b1e571ae058c95c734e4f2f83c0be84e650111607c38a1362773b22a0083bc906b255a8eab0730565d33780180fb676727296dfb7d0dc3baf73021e8c5125f4dc6fbbe55ff3de7de3eb7798f13c170ac7e2c29ce6464732c1f252bb2e5f35ef0513acafdc2258d7ea6132c83a28646b39b398f92a697051ce8d87feeb87f6640882419804734f253d778dbc506a39b2506749cfd8938c9164855722b4ace70257c4f1569005e34bcd90a1041b55435d393ce857bc374c20be3ecc2631ec23b723fdbbf3de3028aa9e89366d0d27c40b41577fa40043156598fe2a361e47bb6153ea605d70bdaad39efd86c65b555c86f6b46b758b154d4df31e4f8aee7656f5c8055fe9a6cb69ac5e84b9644373ef0051b5bc78fadfd9b95381dc03ca422909700b6af79cf0a39b5e23be3baaf2715528ef2465c668255908dc7c2656649cda7222f0dfc3a1686cb77c4483f88d5855b0e2e013a6b7bcb89d9a06af9115f58efa0e6a536f3d53eab250b7c7926d13b40771bff2071b4f5d0a6dee09a18b247e0144f8a5d31237f5758ef8d32ac79f882aee015a3b6908e5ef38bd2a162b3fa12a04e17505ae02d8e4f0ffa8ce2b55f290d0ae94626159312731834584b4cb29cd4d5f832477252395c94923692521664c8266e8da0571882c6369de547ee2cdca36c7fa73425ce6d3c2cbe855b8e9b6cbe907eeae7875e647a9b7b5a9b12b353b6af03a60ae5f5eaa4801dfb0d9268a908c0678a3b00ba3428cccac6032f08d6fe203580b5466698c7120399a5c7ad59a156435989004053cabc48f0f8c4da8798bf786c13d1d82e19f751d4f0bc02147a03c021e3a5e538e8817e9ba889769764f48704700fd731f282ac689f6a627c6b448d6b1c0d376de7e17dec4871b6cc9997f16c5d0fdab58db6ae2195b884a5fb0811ead1d0963df1c5e4de03824cc2e98f3d6a97bf6cbff13174244613cce236ccc9c44fe5348e44c1d8c81a2a6ec18d9051048b490bc99110c3e3feab068cc022b58ce1414e3504c6b1405759a944d50f042f24f5ddb40eee2ad41235234bfb81ad27ed4dff718fb5a05724116774fed20ec0532f6d1fcc9680bc60980cdbcc9d93f9393735b990f02637f3c53fba9a3c57751fce0de0ebaa54c0480b08be12bab06f8c51e4811e6a0c1f6615865aeb35f952d68f11599ce5a0f263b098b1437f5b5e9b48da2cb303c97d4ecc7ca3d1737991c8e72fb02168f44c5ab873ac96b69cda41ecb82dbeb8c8f866936c671ae8567291689f14b9057636b8a9fd8b22929c4bcd9c83eb31a4e717324e306f404b77026b73b8c07cc9847be0a166ae5ea63c5dd0b3bdfdbf618c398d27b5746bea7bfbe5a26342300e142f5c54a25e4e46401f8ff0340ee7d9df5f53bd721cf32928cdb75ca76c892ba05f22e634bc13a6c8d4f92f172476b953e89763963a36264418b217160f602c8d5d5d543b747b8ff010405a8e37c58e838b933f71bd80fa14d847259c616c5677a7a450eb6c609af17352a52cee98cb281697290231f6c11d97633c6334a80324f2a04f550dba5e94235161e4bc5f64afecd3a2df70c4e6b25796e37a287dae10b75069e5f9b19525c9e43d63688e176b51b262732005360213f5c7b70e410ae59a3d550a3b7c2477445d26175c1e0cefc88513f8052f6f132bd45b86f32c81dc7318c0684c610a0057af7b4d713a2e071a083dd42812778411750f6ca930059fabcb5f6f5ea7c07f64f6abc1963b0cc7bf71e722881d82eb81fda217841c11f389c55357daeb5ab2768ef75d8fdd00e8c390cac9ccf73cf22e6786f6e1107b93b8b328e909992466bac1d62819462ba03621a6e33a1ea0d328e2a72e4476f3a2e82273e7496467e7583374ac56f6bde6b95fb489ee40617e6d700177249c3d9e7b744d95d21bea3818c60ea8527436b1a4d4522edd85032109a9f91b661844e750d4abd34a0c161883a104ff33cf4d2a38671e85a26aaa8ce3491b5eb85b988e3d260b6768ccbcb3f73ecb65dbc71923225d0728a9699b48c03449048f62b43d6c1f9b4d66f4ee763ca30ccc19f6341b4fee26f11e1790a34d2b702d5ad450b386486a03ad70901b08d98af7de92de6631e8d63db18ea21e04780692cfaea2bd2df3eeca0af08a6f809974e2b502c28075a63bc23a968d23c0f97661d09b5661fedf7d73858abd1cdab92113ccba2e7ccc28df3cf70f19620facdb38180eea883ad801bb18c3ac1993dab858e94521ed3438dc3618cf4e4b723e4b8c69810308be1835e4214a6f35361cb71e3239e027ac62c36b34d5ce5ad52687b85be3e50ea075f8f81ee3111315c7c9fbc4c4b176428c7d16a3130b983a3faeeb298374f4f0640f135df05a8083d2c26ebed0124b35433a23b9147b35a116bcce77ed981cc47ea8c1f626ab561c4c7e1f38fdf0af97e1982122790eaec99b775d4872361488c0750f667822b8f5555b1a1300fb1dd33965ea6c2ca8d24dea0d9db60ff67a654004e6b6b09e4459081a42642d12523b9531ba4c4f3b05d6d2710fb5d73e102cb417b0581939fe622584095188f5b441301a9573fadafb1d54ab4a0ef0b7c6e3cfee1ce621aabbe1b0ad6119d1527ca72deaa84597a47c91366c4a3934dee9397c9dc180fb4f3e4e9e844003fa9a595f48f505783c6b780c0f709615d66f7fcf57977c0dd2ac75be1cde71b03df7e2f7d9e7ee88562c386b31d39546322413c0db252632cbe39b1b58f88f1ec9b137cfbd38609b54a3b38f38c18f1fde299980b562f0ee27178605ccfa24302d50cd35443738a2ea18dc74f4a6f608dac072f0870c203a35cd45c38c98bd297805e3ace0a59a9f5b9dfe91e2497da6d27f368aaea4e5aae829b8989a36467c8807d0bd39700ce5420c21542b8538638573025df33ee1b1ddc0f7820aca09aa39ae8dc24d1640a72d8526b2258ce8c45bba4102006c6c14ed7bad60ad8c64c3a17bc9b10aa10970a5007932bbbcbacbfba328f8c0b4224a1e83ed28e5c30f66ef5c37cecefc21bdcab2eb5ea2aead3f99209a806af601a0f49fe43a478df7a179ef44ccf2a5fc27af7b1e937324d326bfcf86206e8c7611d8141f8696e0f36ae031f9f3289e3a29a9d595334f737e985d8d22bd86cb644750292246921b0046a7e42f86c2751086da7d632d0b034b632b3603790e0bc812d5831ad5fd032bbbe2404c86a4b51d36811034ec2063b9290b9307d1b5f7ca2c53b68d12a5f63af23790fecee81b3cf36d3601b539f70a0a89d6c38fabd21ec4709121fcd28eb469b2a4294880a8dee8c5d2fd9094336ea816ff9769b07ebdc7c5ef02c0d77c37c0d9a6bd18a3958ab34c59bec9745b180f2d8b6e08e059c2c00561e3a5a8d77e6370482ada49018f1deaa7751a0a2741a217f220fbbbc0eebb9a916a7f1c8495dc349ab75fe0a1422815749d9a9cdbf824eab01084376b729367943f4826c2ee5c2f4f40f797d38cb79cc4bbcbc14418b893595eeb99d51cc720fcc793b9feccffaf78e98ee6777e112ab3b7a1a8b73fb101023fc158002f34f5160af2219728545a43052374cd02640240e088011d61b2eaa0cf97400c0cc2085a8af791c9d596ca30d9129c9f695a4e189c785248f04aa05b42421a215517bf27b493038b743ad51d5c669682329bef57dae35ea0578fc917dbd8f60ece57d7abf25f66bd0b04ba80abe38f7f84164dcd662e22be0fd6d08a33918ed120dc77b68077b47f98950c5929ec29b2daa9164e51a855d3565e5467766c0f2a5b83894d4bdd5f17b2ec2e17ba105f71dbe07893e50a90f7e3476225f127bba063bf3584c57aecf7c6f6e4951af6adff34672a72a1830ffdc5004c015cf850a831f6558cdfdd6c01bbbcd84b83ea8aa0b66e3976050bf0400a3e7fcdf6f2940ed86da609b416d0c9e7f7bc8f48796c8da65f56a930949a3c7ffd83cc9a5c0bb9d46cd9b63d81cf7c82c5b48837460224f50ecbb4fce1ebc5b383016f2312c8d8d0fa15eb3d0e880f007081d9d91e75d13dc79e1f0a44f2e9cc07a2d7b954287d456014e7bf952929c8a22a70981215b32b04740e6c8c7cb1321b2fe1acae4c8f98265c859ab81a03008c91809fe506c994e433d586bccaa2152270b2d3c771ea82e4126a161a15c59a568d678b92dc872e7d70d1ea8d2ca46a37cfe02b82598002dd6270feac18a5283c01cd390e3b147ca93125e6db575efbf0fd05d441bca8b2abae58d501aa7ef1cd14fd3a39865349773eac64edf0a31beeeb074b81e965c395b0c1546d367a8a76bb8d95b450d3e3a9f468f060f7137638fe0052f047b42e498eeed8c35a37ba6fe378b1f2ca7a0c269467b6a958e26cd7714c59d40c2b93159ab870820963f77258b5bd1e3d2618d504d653cc0a7a20a2c810dc05039539fd15c0abbfb8477c7496d32f27e249588e2eebc43b5047832a81129cc37b77867363d37eccc6044b2f6ebbe18de754cb3c2a6e1b7f33079d15ab1e5e8cca72f807c9a837909292f395fb2cf90955d7f00ea26d1e6f0bac8bf7e310c2594d280350941835b2df9a233f54e85bc6f6e4fbdb6758361f60f9f4cf72d3ef6daae1a0c527eab6bf1e8b1b810b2ac66dc8ee8cdc94f09a135954377018d89dde40a6ce8f821440e8dcb773a7cbf62b79bd7f73059d9097e38ed52b9daeb98ad7dd8f4f03d3003cd342f2014d64edeb0a64924585486823b4689c87eadd8f01c472d8a94d44c9e28e030bb246c39dbb80751be496bb3accf97b263cb474f912c447d96b6338daf04796b0e537c9f797162b1f7607fd09f27d486ec1a831b638ee67b12f5adf3a4bbc794d5bb3497f527b4e4a843a39814768ab61c089267e8adf0d23c11a89ba59336ea16ef4ee8cc5a9f2b9ff31fac32a2bc653a422c7c9b135ffb7617c1abdbdd2c13a69be8a47ac2a48634da223a2c9de4a654114f449b69a93b320fd89ed8aa332cb58e79737432167e4006b9c363b0ba47f34c6004e0516ad293bdc47d05a680c2fa45de405f80d50aee8d12c4f7350cfca39ce9b05cc8c0fe71201584eaf90bafbd80f30b005c3336b21c9fc646b3662bda220777426b0db58d3abfd2012dff56fc4a8428084f67f4a9ee14b51561cf58dc51de91e65277c884a0f4ed43db343fe191c4ab416c5eae2cd427883e46a4f70999e2fcd319ac32653a0bd4f71716c99ac9bdd7d45bb7f09cfbceca322512faba2c6034ad821c0317ba6f858f212004e6d4803fd9c0ea711cb1f6cff91e00f7e368ec8029ce70a4eb9d4c880ff6e40700ffcd2365e9af83e5c5200fef87cfae69f06c85fda542872c5f1a3c0582455d1a50e54ddfce67ffebbeb9389657be6416d29a49cb82b6369784e1fa8fd6ea8eac690dce16be6936a6c3db1d03280e58be54a9e4ab19da135a3d1392b3355e3ca31776478a3ab6a1dbc50e2754e9c3d3c247b9466ffa1e99f4435f3ac73eb0bc62ffb5e4b04b8c855f1fc05f4a9011a0f3dfb1ce18bb893606a52e45038a5c80b72108e08b35f7e14caef3369b2d74236806183925655f1809f087d2749c9ef3654e84d5883220abaf1773132ce21a8c68c1d9cfe372cac9951545011c33bb72eacd0c2050e0b5bff2df7583ee484a45a99566955379391c4c20954c71e6db5a0d6799b8bb8de44e9e8d03988f602d783a837d292006fca43cfbd7ab8f4226b38202c19f73fbbf7395eda661a6c3e18d0b1addf6cec6069686007502e66f750f870a65b67f5e26e636a8a88c7cfc916569c6c88c4c9e3ffeb5dcd09956f8bb980afe6589732fdfdd67380439032170bd312494d58cb6e99c4f563be30b0ddaaa64e33a23a649938ccf001646c0c40a139e51a40c5adc2c6be9054d9bf29e7776c3708e8993561b40b761f359018030f42021cede5344e961442d63f648c7180a58505134eb658b900b38ef6932c3e80b48a6d169973b74f4e439632d3c83dde28808b51c934fe09ef37fc91fbc2a841c675140ee23894ae9ce43b62d625c29f100350d1ec827dc5f5380b5c18e46f16f45b58f2d05b571314643d5fa360d8dcc52605f533634a99a4ffcad6870b05754fba7c9ae70e573cc2d506de44693deb6fa0b7fcfc473a6e80658eb5a17cdbdd48a2421d5e32818cf9e62caf8f1158c67d39db791b260340e5d6b4ba762b57e04ed32fe6136aa1b9bc68977fa667fe7b085f0c501c217699b1e44de38fda7b61d7f0628363925d06214d5321e0208399bd4dc626ab4e10300614443a03480f7f30dbba2c55e839bf08686d9a7da02582cb49b33acaa35bce361576f3e03fc4b1294f0a2f2307411d341005f25b8fbb95677748339e8864408ed0de7c25013af4917af42330b627cc408180fe71b20c4f4cdbf60e011e0e9209e4808da6311bc18de32953503302d1cfd34996d33ec16da634bd3ef61a69dfae06a557e4222c704da19c6f4f2593c28e07cdcb16ba5cbf25a90a1384542f0ec0c919d48516c2884c5c9ee3b2b4ba9e6f5e2c202fd0ae58858617e9747a47e33c989ffc4224b8a0ff4789505a22c0524ef352f20a94a373d84922c939c283bb1f605e35e5c0eee55feec7cea3cacd08ba056c96c8fe203c02aa07db9ca78b22c91a7e214d53abec5afb0c3cd16a47a50295cc84b95238b329b44463be2fc317fa29854985d2946eb1d034d69524d488384a3e027e15077bf7373e2ff7d77b8d9167e11d31251f6992abe6a89ec4e21a513da5d404aa736094a932eabf1c94a922913cf6d74db178cb0d6b7d98710500e4e0bb3e8430f9d89eb5dfe25ab0657193b83a61dc05a6965e67c0167d3457f3fd5ac2cd28403e4af9082bd0354961423d3acf69a4c420ec35d11b9800439e9162b5f4e0895db8db7db069435ee763993b18ca328549cf1a9168e3a12ebb6a7c0808e38e4da9d599fd502446d680d1d411b1ad3918770bf86f37d54dfa6f6eeb25e4a3f82b448ddbee021e43750e012a593b35918749f5b8fedf8f2227546733f28ddb920f5317fcbeebc4c8339adbc127452fb458bb4b82d97605e29d3893cc809829654fc6ad1ef26240d9b16422b2092e8d20b158390468a27264fb629ae6745627ee00db05dd4e72b396a243405beaff1e9815ce2fbe4484f425441d96b68dad579c1e516fde5d8616b68f9820f2ea1f9f75e2692aa3fdf5decf45f61fbfe4010c970edc82413c608a82d16581c53ac73073d8789a4ea897c8ced2534b4c56f310c381ab09501408ee9725aaf26e439886f1515fe43fe8923697d5d3a0df5abb54fedcfdf2990e675cf1ca3fae742a0a8a7a77739cc2e156154a2cdee0650c521cb08a16363dff82aefbe5e24c6e28088b07d752cd0ddfaffcd406417b563b07b761be46ce01c9e6b58dea8f453076dd9f48a6ed816047192f513417cadd43ab7429b43932f3d1347d114c326f55272def8cc819d67d49d7000f4e253e655f8b9f16f2154944f8b16786861209a6cda6b49e006b4e02a3c6c56f88611ae8c8552c166ec11ce4aa13e994b3852e50a5891526f0a6c530af507cd0ffb49fbef9e99beab225941f36f90545d447a686bfb548c54e09a02c5186162fd684b369f9a24f47730713b62316cb28c8d8409117f66e07e6e9c6e6e5bf84ea10621744accbf496549eefc019036abfdefc75914461786a8a4797eb07bf0ec4765e55e09e5e81718a192fcc72d8efe52f1b1a98dc6b07b09eb62878e5e8e74adafc8fc7828a062cd7dd0da888084403a1dcdb7704acb41d568ae4c61606bdf4b5936aaaffbe7476dd5ed97aa2a61c524c08b9baa91da899c22bd28417607632c391a775018bfe8d1be0c98d5b78f19bc4bf1b6042f26c3f1a337ada770737b0a2c9ec7c0d4e1fc2bd384c371c79bfc27ddac3bb725ebf8309ed791b361975c900aa317e41929aed7360b4ef7467e84a9f3cb9422d408268f735e51ef797024d5308eb7f6e4e4211e677303df228ad03f8d568e6dd3a79fe141241f284609b23dc7906641a30b85d49003b3b081165f4c414e6aada7702fbd5003f2cdd146adfc91d0bc316d77e84d53b6419cb1bc7040380c7e46a40e714001c8d5e74c7adfce41245a27ff7f5af939ef3d19fe39d9bc5eec3533747fc82a3a50cd2858845e4e024a55cf8c4f8aeaf8dd342ee2c4127fcf14a5aa115f8897ad0ec7c0f923e4bd007f4e7539094e7579e44fd8d1ff04b0b8797ab254fd1bb97d24c8622b737a496b7f6ddf284504fda6fda0770e131af810d67f423d8eba10511394e5e27202eb33439b8756d4e8c9e083cc796bc3dc77d237999159c90dbbedd1ae302daca84d44d8d55277038cd9d16322527c344d79a988edb3ace77d33b2ae89ada4e94875f0f500cee5d1115c1c6e9d9fdecdc7898dcab14beee562e63224d81c4b91f84d8e74e319fb924346d69147ba13d0820e4e404df96bd003d9aae4328c5d30dc513b74b55976971af6ca83fb442fb56207d8a7925575ace384a156cf9102f5bd5109c32e5a373fd1efabe9a41542fa8ce4e5e07ce9d15883a17cefc6118637f4fb6a1e496d339fdd448ee5dfbeadc547abe786da632f678e99238fe4690a00e39fd376627157e7b0591be35d14017abee3b4f53e22614a783dcbd8bc7cd9aad21acc9c2971d666f185e123ec925f9e150d1938fce6e6b78a76c17e7a872c0e3275e135d09b1606b4818708095b14abbbae2262885c8afab95f6d26a12763eb483aa125b5046a3939cfec8bcc52160d0f24ea6cd96ccd7ffe395565c8a08e5c0e21a2c316d1fce544789fcd2a4494c2a6bd1a8f6c0f3942f4ae25468e13d151fbe4c0df4df4719b29e74baee3363b037bf155048e21e4df1364d33fead7b8365faa91954d1f7679d9b0e05ac72e608387f15e815bc29cda88202822284c0b3b6d0c288542665b67f70b3eb98c4a7a564f0fea7be79a69ddccc5809924ad142e05e8dcf5338b77255a2bfda9091a74e8dd7c614f81326433b2cca41b81199ac85713f214944c5d8ce2bb0fda5db5d23679e4a9479761386019b97e877dc9e6b7636e4a181607fd8fd34a0c95e6e25fae853ad2f55c7d20b8770918f6e344858026229eae645136f2815bcada7ebbd4a2aee056a4585f85d912650273a550704415afd9a141e8496667890cb59033e9687da1dc28b33d5c44dc1c99a93c57a3be7261c5c36b5c1b1f176849ef55cef8944998926b43399b2331cbd258a4ab84ae8adf9108ff4752046153465f7dfd624cb0ddb0184fd49a950b3fdb48e4b50964d10a5734f773e8137bebf84f56c6e7310eade856663299b9f0a04c88c61c0a6d0ef12a264ce9342ff377fc7debe231ec04c728feefcca90af6fb4602fad438f7f46b0003"
+ "837d3f8c484dea01d0081d3ee7edff97aa5fabed3d9824ff06209220459a13250759d3a42dc74eeaa37e443d026f58a8c2af572005ff0e98b81e4e0a8bb5378b5eede03fbfd44fbe152ddb00982538adc18f16a63440cf7df78119cd80916430630b48b681ecb491b4458e7cdf1b491ee937d969b6b769fbff5d5bebd83fc53fa534c2ed9f74542170d9ed6c13409285e9368656df72b5c5823ae0e4b3e0aa999697565f997393bd2009408e6415995237e70fa0340d9eb20c7c833f24862225eb5ffc908849d689f39d06760ff7035c1ae6b6e6d0b06645d688c640369bcd77d9059b7fb57c5aef03739226755755e2aac73d95fc98d4656f7da71f2e7bc9dcbeb9787be94d765f9fa489a386771d58639f57a0c02b319bdfe00cb8d807e667499a5c42fa176693aca7cbf9d5aa983c9fccd3c45cdcff03b651bc4bd64982fbbbd88e7e0651f8e7d597973e5fbccb62e7d88ce12f84c61bb6d8f578eb3b45dd7c7437ae57f96343f6b998e2bc972d18ec7d405953741e773f28c95a715548aedc8029ac247f4416bbe010866b495c1562ab1141ea176305c17464b3c61b864f3dd3b7f103445f55961561b5368b8b9d443972f61eba8fa3b9525537d505361887ff33cced43380eff5fe3148295d5b1ca16c9e6b77e1b7cd346cdf15a1c0b2af32804231ac55aaaa18e91f58a1fa62924c2515e8fe69be9bbd87611177ffdf1dd5be93acf4a664a280eed5da42701d650c52e66f236ce62b943cd1fdc836b619de334e1bbefaaa50484c29a7599feeebb1401d87e33e22a74ca41113df424b1aca579e49e34a632b53c160dfb9298a4c8691b2ed228d23f6c8e9fd4ec4065942345363849acaf5802cfe70e394feca5dc645f74d21fa71e687a6b46f58287a4ddb2622dee20ae7a48befbb165e3f06fae01ff90ae023f4576860dca9ac42996e439c277551d11556cdc401c7ef56729457ff167971f5ff1578854297c637ecf86ad1c3988ab40d88b230b727ae290e3c13db88f1de3fcfb2daff133df81028350c4df0ed777297adfa1a11e9d3200f2e6ac77d516449f4a96ed517aa76238488d4fb5b3c99ea4caca4836f4104529fb760a3e131c7ef85d6bb62d4adf30a207c1e176a98c387fca83830b7c1f5546630efdcc7770a4b188dd0231a77adf8592d3f0620f8d9b238bc63b6f7dd5313c5d28617bd8f09b50e003b1668773de285d5d98311fc66f0fe2fc25518cc81f5c9226d7c7c1caa7f8e86aa6355917b3e5d52a4d5c65049107ddcf2159ff9034de9095d827eb24f253ccfe22f2534cd2445cdbc5c79f88096bb2fec57d25f9659a0cd5767e60e3e80fece42b87649dbc8b35870469a07fed8fb16f3959bbcedadfa4491ba4145725eb1f12042927eb6452fac9a6b58cd30d93244d027bab505f9995862afe6ee5c4bb47d4e5572569ff11ba904efd6fd224faf6519ab72824eb1f6434d4d0d363219cc71ab95aeca634117d6cbc19d89fcf24eb3d59e5dfa449cbe1b1985778b4d248dc4721cf32368fa64198ac7f91914abd394d22372d076a145554d49beb504c93b3007b1ebfdea4d1b7499aec33ff1d5cd93fb6ecc8c63e499335830e96fc30a9cc2683fa4392268db88cca2d47a9acf8f939d6576df03bfdb45ee2e34e4813d0df1fffe56f52cb40e9ff7192cbcf1e7ad6b091aec98a67a1d49576f4d66a32c076df255128f0f7f36ab62ce653eb13d4f548d452d5992543f8782edb20ca5915c8b0f6d60a19f00260ebc1125aa685431616f3304a6aafdd853b125650c4e9a125db232ae3121b985271b228bd461dfd87df912557b2422345cefc3e8b356714220415c829798ca91e54002036b4fafd7f2254e7b54aaf11a56f5a0a859e8d818ce42b57e04a152b690ac3ba07266e155a92fdc2a60db7d6f70dbba80856595ea313aea648a8d5643a8d41c80274a52465ed9afaa47d329f4ab60a7130be016c9eb984a537b6ccd0c74fafb67604219b6897148c5ec84cabeab3d5fd2e8849e15dd6066ef6bd13e2b22ff72fcabfbe3310856fa334f2d5ae9a1117b96a101f9137b3bbdd738d930f87bdf527cdfb5d1c7ebfe7a012c6b09838329cfd96ca1ea7ef46885ed4b9b0f988d1f967f5c25267181fbd731c51e48bcb225fa6d8586a08736ce9c841ca433db6f0c2370d39830f3f5aa7cd72cb58c96b40d21f7444cf28484851fa9dd737d1c8d2facec046ff589a23fd3d362da693e56cbb077f240d550cf88cb85d037e65f51ebae439c8276ffacf55007df37931d3042cc3edff5889de5b742d79fbe8f9cb4db450270aa28b0a804d05e7115b9c98069bdd173c7aaa2704b67f6395f795e5cb8a1b7192cdf245d6063fc3ebe4d5b9dd3f5ce3766bc12c5fe03ef8799a15e3dfcfc572b59816b6bf912852bea671f86f48cd5fdfc19f6582a527511284189ce42c9846674c4b61174dee6a243d282889b0bd3fa01887ffb35c578ec3ffab85fa14ec686721d78c2d6311e9428a8e0cbeabeaa901203d6257974b434c0d3903d71556f5490f2447df5c8ec61589b14545f46d168583d2c87ba74e7e8fad65ecd8957543e1a0ffe369a3bd048d596ba964b45e3548595c85426f82b1d95e077684a0c1b3779e824911786fb99c3f30f7d5839514a5323aa20ab2526113ea44e3c77bb2ceab997a7b5478ac4c9301ec7fd664be5a2cafb65398267bb1404692effac3b598ce16db014e7fdfabf2c96431bd4233ae78b9a4b2b60d53a610ab4d8ae9cf1c710a1279bbf5d3abd9020fb949dab18bffcf5c2d16c522ddda004d8588c0b06e209e80ba0d2994cc19c96549d672c84ca94eacd7aceb5032e3fa6e8d173b5e828d096defe77cb55c5d3d375eca10457ac53f514aa54134e221213dc6c7e14c0a653d24f8b8d962d789c599b80f65cd1aa7baccda39d02980942f787d7fa739ee9c462603bf8fa0205bbe8aabe0f8298ec37976a381a89882264c813e36e819d0324a618ca5683d4cdbb5b7421fc66c380e67be63327a6f27f2da2a55525b8210b2544416ba0f7cd837183806e123d97138535735ec221bb01767f22e45f03b1fa59cb63782bae81b9a1367188a340ee7b6b35957e2ce47241f13c7b7c61584e03b40abd44c86289b67b814c38a38e9377941cea0f6a767582378cdd11f1854a111470edae9fc3f85f0fc23dba77301a41c276bbb521cb1335592b50e3c99af39421464afe313b01747eea83cec22e6a7aeb5c60bef4c57461ffea48a68aec05b2e6720c532034a121124bea3fc14e885dfc6c514dc48549496c9f166a14a256ec5f2556b7246554d18bc2d4215de954ca5a0cd586595218ab20ee688261f4cd81dd69da2221fb9b1772dbbebbb162ff596a93ad173a7f0f9a7e0c8c39a9c1252c00052cda7e956fd389cb524cb6a7dac1ce6ad9aa4ef6a240619ad1fcf64a109fed9984c568b84d6d809f62cb3186db11782b2103c0711656c0127c1ffa3475b1fad5475bc4b7fdccbf672b9d3c562a65f88a898b31c87f34eac1d2f5a13567014fdb29da7180a72642fc51bbd3fb11b876fb37c310ee72f1b0bb2762f8ec7e17c786262d7a3b038cae0c6ccc386aa9f9bc34f1155f0dd8814d6ae9a04cf2314b371f876d012ca50ebc11ad1a5c17ba320654d5e082fb7406457a1952f40cbc530aee9617cd9f10e6037807d35018d0f5cc629cdf1491589637420db2720ceda747cc1d6d1aee180dbfbcf3a972e06be0935060ab940ad85bb388583f0701cfeb95f93f03592d31c206e84aa40cd37af40b657510db928c78134d103d6865a1f158e29da9e6ec06109f1a0405b5ef731dfbbd63e6a8ab2a610153ee0f31d1a5f1ec6e1dcb50ac75454b063549f096de07820094706eedff6395e51b0bd75bf01b4f627484443b1ac6df96a80ef22a43a9ea207377444c097cd96a0f926371bfa723d0ee7697e8569310edf6ee01da24829e3cbfbeb9e357cffeefe95697ffcc81a159d79e2bcc0a63b59c5cf9b14acdfa6e90adf7dce87df9d300fff67ae168b629932d03b1d98efa721d6187c46e37405a0ddedde6f8a0f560f40bd9f59766e5fd448d1e7ef2d555a4b0b7c003c7b6bccecbd01738036d1864bf8fd2f5ac2055c83e30d5fdebf037224cb2de370f6fb71388b5ec1870d8eb76ae4761ccebb3ebd6eb0be92321fd30d13c2abd48c41678501cbd7b5226cbc5427738d8cadf63a1b812d93324e6218b5fb31e0af89e8319dadc6e1db01d72322ce46c6773bcb8a9654c7e15c87c4bdc3f6fad39b88d472fb713b0ee7d58f49ce26b2ea61654f221c517ac3c88d24ccaeb88b2ab6dbfed3832d825de9bb40158bc5c58744151c1fffe95fd4c79687043150c9f167861c769c2b1fc3c0078c7f2be1965a48a1059111e6f8249bff0102396d29b02b7bb42441f1787670cae65067248ec3b954124c798e196131211504b733d44c36d625050e050173e095cfab80afb4ac96628d8662e450b7596b013fbda85da90a405c0d93b5fd2875709d50c2997b529c578cc3f989103491b888ef3bde4b143cc674589a3e6eb68a9def0e7e81f8e40e99e41d00e607f23ce97e29288adfff5415b3c964f2a6a78b737d7af5e44aeecba2edfc79bbcbd56ab5e0bfab8fc399628945df8ec39933254ec1b164c15942eb95b1d96c41114b7816013397427546f488541e2c438e89c6e1ac7899d4723eb04e149e82b0a536b16be8fd758e2125c8a7c0905f4e36e8f0b60a1253588262065e7591f9308c59cb80ba149663a49f33c555ac113bef0fca7587bc23326720c025f7dbefc58aab14a7da5b56b29c76e777d61bb2f597cced47e6c3387cfb3075f1088099e1d69735257ca3a328d721dc026c0eb9df97f7ef2e3f6cdebcce2737ad912a4ed10b5b93b5dbe8ec8d6eee6ec7e17cc3aeacc7e1fc868fe60083daa762bdabc00e4d95f596d9581e87f39d5ba6a1d748e52179f55f9d105027fd71c9b81407ff300fc99eacdd51797848b00b240ee2a89916b4d2b215c718e9e9f8109e9e6d6fa982f52794deedc544153960874f2351a1f295534cd4a849558e8c1f7f214c26ca9a654c5542550ecc2d5faf8b31dfce7e69b0c7b48dae60fd691ccea37948613e4a7f44efb0fafd7f8ec3b737d3c904ce1b5683c70863921a249b1144e37016c73fd8fa1387390dbdc0e701e1809614cc0bc2544efc6beb6a1e11aee7d21b9efde3f3e6f3db5faeaeae8ac01b52510782e43cbdeaf77b6dab64ebcfdc9dec43f4b09833548c1df65d78b923ada2da5c0cb4abf1c8b61f87b365ba09b712df74bb74f7793463f9b7ac8d7d5ddabb58739412bbae1a87f35e9ec04ff7e6268863118ad92127976a2343b1bb673f78cc6b8a03807f6ed6c87e0f5f6c963810545c65999426ce434f4e8a47fb91a12826e3706e6de704910fae83e803a2a2947ac9ae4f6d246e46f4f8d4b7fc31109753dc7a46ea1c7de21068ef4393df88bcbfa52d3216e3f0afab71f8d6464639a6f0470e6d06ebc4ec389c8bf969dbc27d1f6befe01de6a75b7875b4a818768db56ebaeab53c414b1f32dd823b90cc83811f68469f7208b5285be8d456039f28b0e151d38a2f86080783b027525d2a2175fcd45a7238ada79105171f0a9b33ecac2f0f8a5d8f1bd0b7e7c489d8746655a5db401c5575c622d26aedab2b7d2bd64768c98e8278cdf1c2c7858c9328a7f8e42b8e416b5edfa10d52b242e2caf4385ebeeb36f83608470a3dc4955db3631735857a44a6464b2562df817601956d4a42b907fe7e65e8dcf82e79702ebb3e41df4eb9f0fc98b03e3b869edf4d8b056521fcd8c7d917bdcc455f5e75db662d41ef794df832ab27f6755ecc691b478dc3f9380b28cccf93c79dff88f4393c1f0ba64619d51a1a0e151bd10df024028f072950a6c56b10b4a6d0724849f2b3eda98c1d59685796ac6a449e8a35a39b8af5784979fc6a2253839ac29135b2c16fa7f994f3c5ee19cc0e3cf4a0570afb4e8aa8341c2afd19e101641553c220785acb1a6da7351bf4adb4a4b1eeda601cce6ffd91c6e1db6c329b2b15a87dce9feb88133207b57933dbede6f3389cef834fc9248df96339261ad79f8a23ecbc48a967bfefc8c53c1a7fa6bd538cdba8e9e6f5f40ac69f0297331761e211b7b79f5f3fabc0b459531b3edd3ef091e190ff199aaae39c4895f3edfde73cbb9ae353df66d6da2aa94c37860515bd3d9a40aaa29170583c6c2f2cabebc6a2982b465d7704109527897da0894c202e8db40579a952c623663f17ec38a6fec33f88b5ecce0e87ecce3e406cdd438136a1f749ecacc4af684d30cfef6ca7ec89bccfddaccb96e35fee643a99c885e8f75b9ecd4fc2b05386690008996a445fad1ebc2c40bf0f3c248fc4ac6aa87f487a6c91a343617f8ecae8b0b51d1f3ec97b71e9a6a20a661083347fc7bbc8b4f8e803732bae625b948f42b24a05f5c739afed5c59b36274543792a8782e323960a78d1899beb97903a33869ad4813473662c6e1fc00d5a2965d03f90aaf2a71b5c3ac9203ac59b77238466d177b748de47064c523b771cb2c550c909214d14aed83366a9d764d4301a9dd9465296bf4a1ec00b303d11a903754b36d2b8971dba7570c4c4ad4428ab9e14380dfedc0036bb39958336aa6a370889b385d8da2703ea2676494e373f7afa8e6d0f569bd8a231c5318873389c7fd696b29e2b7e33ffe2b3da3d89a889cc9cc77fbb4f9c0e640fcb795e5e2cf6fd34819bcfa7dbc6c6bc9e63ae90966adedb4fbad58f6b5dd0b3dd57e67e7d16bdcd782b92e7a4bee6da71d6d8f3d2d26cfaffaea246e0dd09d7276e8c1e99c7a57c88dcc4def8c9372ccaa032e923aac5bc972bee9096329f9b9cf339c1543de6b345e07deb9c0ddd4fa3d5e728a723d469e130e1980ce47c59aa1d47084c91ba6b4f410d5ce4120a77b1f1a0e71244fbabb7aec70cad018b0f2d73ac16f2e7dd306aed9a5b2945699e403f94ba005af96edfaeea40eb4cf1cdc40a23be6f4837b702364f3c5e3733fd2b4c11fd9b0329cbf8385b19d31ee8082c6a01e2f59d777db5729de354eb66d6826ebe1bded148d1eed10bb2c30ee3030fddbc5e48f8e9f4c35a0491cd77dabc881ea06792edcfcc6e3aea3f64e53775f4420570894a94c3b514465fb89b6b25a73287fd538de10e9c08a5b1850a3f00bf12e425b66d3ed6637c4723b84efc5905b1cc3eed6b99201fb7568b727c63f8d16dc552afe714d96c4f68bb2224917c7b0e0709fcc785bc96df1a13a50da81a2e09d4af66e5bee9d0bf576ecf57765369d2d171461b1c8f14ea4a438a16940d13bb3e02dd778023f208760a73cae8d3a4b21ae73042c47f06555f83d0c25977dca7b577d4485a28a41842082d7869c5129f1149142c5c2ab3b1e828aa124a46ca17c866ba96afcba608d62e355613f12251c0b5be470e7c693cf5a0a1151b9fe6b4d41d4315404c0f01ba62eb195eeeb425285bd215b9ccabe542d5acf576d22d0e3898aa26923477ee10d83759cd4b0a6b2541acaa55c5f38bf84b8a76a1b537141cf0aa0aa52d548764c6eef3e21cd8ec746e953ce38091fec942140193fc33faec226d5334615bd8af65069526025136c6a6305b52d7ee0d3e46e356cd029551ce36f51bca8296e3714481893e42748b154a83dcba5c2a8617fda8453f197f1fb13bbcbef4fec8a6c925fedb2c93c9bad544fc3fb13bbcbf7aba46e144eecfd89dd1afff73cb4a366decfc9bc58ccaec44649c3a0348a62dab52926f915763fa5eb60636d511838da077d9eb16e6a08bb52a49e6fbda4f47121de54425ab419e03332420c4ced1dae2abc6db2aa79170c001fb874de65ffa1f7995760c3fb390d6119507f6901f700a1a38ca731c589c4de41314b9757ab8cacc20fb85a64256ef7654836458c8c679d3a361c011812ef32e2305377268b1880cf764ecc0253a97ff216d3f2a5a648a40cf0797bbfb00593400959521657727e7dee65c3a1ec429fc54231eb8f9fed38127a4358acdedd46a235b61f81960b028812f3b879671128375d14ab553630710bf212f1819f05120e88062a85b38a93ec0bb3d96c9fe5b86e5bdb873c1bb00b4c072970bf46b40c1c795bf23699ada0b2e6e0cb089d532cb2e9e4a95c11c4742572b8ec797898d2d0db4f431ed45ce40bbc21397416d57ab7f79fb2b9c7569c240c757d9f3e1d64c9f9b1df7c0c8950a0810d1aa662cc94a9e206e86b2c129678726ffde9c1981ea5ccee6ffc909403b5529cc4448b0589e5f830fe9403a4406366698f714a177539de39bc00b38161a45fbaeb4e80ec85538de621060d047803c29783efccf89fd8a3afc9f181c9c4ce953ef8e17eb1b3be42eb35a2e6c0bfbca8636c757d79793a9df229db6269a739c92571e6a4b82a9bc52f08cf84e502e1dadaa21e69fbe35e40727645f85d8be85b93e8d64ff3e5ce18da9769bedcb769be7c278a69b15a61d59cb8b60fada532a698e64b43887c6f9b39047453c24fbe8807505468234653d409eb88fdd154b48bfa5d58380611ad707efd8ba5ba60f69089b3288b35e58228b574e4e08c5a2c9e641b87dc71b0bf2e96929fcfa03a02fdc8d29d5a7a64b53cfdc034922ed621984b9403993b56073a9726fb309dcc73f34f87732e400c524c76a8929d29b202d4cbe064011998033294d30643b5a15427c6e1dfbc2b1cae860c2a8dc3bff130d79bde5123e50714ac294e6b62fdac042ec5d60b7c05ab14120bac9309e24e65e3c13e29ef779f3eb17705a137b20e70c39c8c819b18bba56c7a4de050a68d0a22d1177b593b9dad265287c7692fea8dade15b76d5d1d2eed2df3de1a32db2a9005ae35dcbeef6cb867697d539477dd914d95414e985c6d6f8882c403b719e9b9e4d8b452a61dea79a319def70d93844e29de68d52e46628c7b53331520d9b4c1bfeda795b15f461cfc66dcadc97455676c23be38f1cc85a5fc9204be07d7150442bf6acca4fb5ec8a7e787372bfc45df64db7ee0f8b188b15425e1b978b11db3a52a18ba26ed15891322130018baac60b4a64a3dbcf7734f7306f34212f021f9a8c623245f1923d48ee2849a4dba9f181c340bb0967cb1ed0f4e940001ccad987839a7d38b05984f7b8d3e7abc9f2dbc1cd3e582e3e8da3240a2220f264220a70c491438fc63396f0c7d3f70448ab616e95f970f92f4e8620ba85213bceb2427af90992cbea857c76bfeec82fb3ec6a3915295cde905a175dd0e2d70e5f667265f562f2bc1c2f6913c81ead7eb59c02cc9cb45039e86c5315a2532b544c924435bfc8ead21c1724d067c9b19103db1ee4d0b5940888af78bfd801fd54974df345885119590ffb9e4ace4b7f39469f769a2fb20f9b6778eb23ee06ca6f298a83f32707daf92e869447f51c53908e9dce873b52aee2be79647da34a3c94e9c6c8819c23f401ac61b90f10cfc93ec8dfd555b19abfe1e7b51baa7f1ea75d21ecb17dc31a5d03a8b62b43b6b1f8782a476eecb8e2519e085d7cd749b9ff0bc38ce1710f21480412a5cdbaffac862365d6524397fff40bcfaa8e82c9e6d974b68b9bca95cedf5c7c2b9d98d92d475ab75ec14297620ec3d2b8d38be7cbc5f439718c6555c053e83fb7ccf1b1f45dcc88788db8403130218cb2400c3c3b68f9c0ce7d67a0b4e7d85fff27ba0751d31b71ad3929dcfeef063e8aef346e42b52d8ac7105c83c5e8b7e1f7dbce8bc3b994379b2d0eb74871a139797985a8a6744e206e6981e2f62eb819acab001e1f5119ab3ab1aaa58f1cca430371ee09214128d9eccba5e850b925d8496608951c3b99ad6cdad8ba2c101d9d56f880ce29eda12dfefe3f1525324882359c592a275cc4992ac6851547f1021c354f96d7323a91b2d812935b5969cff3cdec260a1e9c9082e11bcede6e5ef8a6f14e51d3570dc01d54318c8911721929e26963e270227c6c5bf95115ab2fdcc839cdd6a5f9b6e7e889604c48c8f882a69de03c0110052efe5f99d753687a1f3da5265acb51fc1477ad0c3505790df1fae88e2486378a5e7859e48c6534f2c4e615af66e44ce6b6a997b3475b8be807cd0997b3e8fc7ad3b64f7184719b26ae8240ff111c73fef6998d545cdfdfa581b413097ed7e91105a23ea685503b727812c37717a22b6e930ce1f93181f9efe256316bb2052ac43595a2058469b5936552f05e504c761915388391c5e426bb2e749bf1fb6e292637b82e027327b2582d5757394222021e6929b2c6fc9781a86c0327c5284b2daea0757c83c496f7646838f3fbec96d73e60545c6cfdab67f0488a55e59f4a08a79e78aa3baa8238b2c0a26c9a8eef11abbace2cce55744ebeef18c1b3811ecd599b94a9b1ac4a934e19c231428a11584e49962b410dc03a98f947b146125242defe76d2d73514c572da7b904b8e8c50253aa29a4d032d1879142629414f2de5c2f7a7f7835b7e7f6297a5005240c2257490d1e862c5f82db7d46048facab1ee5752942a6d2b69bf340ec4a2bfbc4f49629e9b1e2e7c0b068882c1df4c31c91789e72b282e8abcf87f78a46c8a6c9ea598af60a9273f9d9ece56983ae95547dcb0e5f0babbcf72ab4a973168b6322da63f2630223bcb7b6a2bd0f033faf036c589ae5e0104c7271d1f0335de5504187599fa2e940e543252f6e5ec7cf2fcea8d1aa6177dcddbae754d4dd00d0bae169e42d007f8ff0340ee55575fb5f3f809deb78c1548db2d1b227b77c085cc60c6587f65cba79109576d53fc90fa6afdffdfcf5e5757ad18d4af90156e1f107949048acce7a4f499cebdefbed0bc99bea10f9802a3abeaaaf3c0d6052625d0ac4354eaf7ec70730dcb80443a89f315bb048b911d5fe12740eb07d61e03f16b7bf0a77e38416d843b1871be4421d61f592056578758dde2f338383047f51bf1698817c3f8c28c538edd8c150f875a55c4389d9994c209e354edd1adcfb165a86a57abcca44844d48465fde2da499484bba31e4801f97ddd299cb47806ec2938f983d54f1d39bffa53077ea4de40625453af794a2cd43c05fa5f733e75dc06e761385fd2c5c5ea912201fac28572ae7bf39de10049c4044dd30244b8eb4c21f999baf7f4c92cfb35fe835764c7b0440f8c5ced1a64dcd1cabe2704ad84aadb08ceb9969066e6692380ad118ea6c27f3fd87a6b5bb3e53d16e55ab78c8e802b02db24fd260ac4dea84cf69690723add25fd4f2275e3dd313601dc86986743169da492df8765793f4783f1686846056cdd4602fe5fa449c7561fbd05bdee79bb2cbe34f86347ec83456d212d0e46b8409c215a81da7a6010ac41a96d4b2e175969b4f277dafd9b86ff20711a2810891b4ef33dce1f68d92c5b98823f7beb10eb3993662d1627cbe4a1641c84b51bfcebaf4cc7516e4518514428e7e9893fed4a4a2b41130acda3a1559e421a253917a995317933061333b8ac56d794569e9e7ac32c41937ad5c186247594999d44887a8a22a9bf9fad9b42d25e70ac71f44ad55f67808979ceb45a0bcb493829c969ae236d5f7b944bcda1b43a5f184a0fd60295edf95c293d988a5325589f6ba50753385576e88d180d46faf014d6c4c319211b96e92aa2c5b6bedefc6a4f7542eeef61b6de82da0ccf714acb8e850f7b0c1b50daf60a56bf04cf279b3adab81ad288fedb6ce23e4e0d9d2e58527e3438556b4b56564096ef62a1bb359de925b5fd413be3d2050c10ba05c138c793b1142b57936cf6903f1f93683a96f8f4bfd4750c50159e03213727da04269b9c3f6ec9532f812dca077554b8ef716232d6308defb6285e7ceac8fe6cf0f32b37c57a1b89fc2c8af6bf8841469197b6a2808df4e59eda1760e35c2ec5d9d7263870fcf2e1aadf41732e9770b3908df97b190db33182cb74e7cf3305967748c83c8d2a54ef4eb8396484defd7dde68e8665a995e42e0897b4fdb9d78272f7c27f005cc652a0cb1083bfe916a9b5190a9886ce42ebe80373a05f920e9d0e76bc0153cb699bf8025e6562cdd47b15a61cdd17f40691bdc6f1ff20960d8bbb8729bb007b80217c110371f1c0863c4e2d20d14b057af276f67622593cc8dcfe8e485dd0500725208f472c9b0df545514727a96f1dd1ab87bc9f0085769d9314d6773c99e3a2326eb72a4b47a312f6294e1147e682cdb4dd5dfba4a7c9722b41536535874f45b2caf5f9fcffa57f733f1418af97dd64f4566d4ab88c54f76fdfa7c760257f733f820e1e6d865f2faf68f32cca499b4a20c7e18d8ae7d5a4d859fefa13cccc69bc6515f93abfb9930e283fc99fdf028292ba1539762800667a8de040f926789ea224459ba8958e4b0a7ded5d7b075953042abf56161e649c9d010573525323986db9d133c6b2c354772d7735bc814db06bf0f9e9ffeffd2f3129c7439b296a8ea94c3dbde602c59ded6243c98472f228ee8a8cb6fdd02c30674ef4a52699599d273aa225b152ebda1ff67a0fd04838a4efa8e842e20d9b8e5dc1249dd59e01e0301d39279d96a8122515615891a09e8758de312c3565ab36779eb6d1d437b8b1c0825f097121269dd6914c7a5acccf84fbc782cd85c8311f4ddab075b1dc406437725d06e5d25b0bac0271fb84a60e51baa5709acae0b5176d5e39bc9a0572812e057a258e75de93b5e7860f78165b8d2bb6c0f98d6c64de77d93d0da0cad23cb9d68926c062eb1c9c0dbb02187c7f730b75c36d7aea48f2b4e20c33aa8c746df3951c38cda7e8e3173f61e542cff824760f44f5f08104671deb74dcc1fb949b3169cf56462b34c90c49e6e1b37d4c412fd3214bc77c8527343788b2457911cf34ea59c10fabf3ff8a0347fbeea6ef0ae664c3b896efb6e1cae06534db2741f799849698832b09e8d26ba9542355d138d2701d8e920308367071d99551862275728c1225cb998de29b34a22b451fad6728e22522202ea4a2caa988b1ead8d9eb88bbbc8a8620982677cb7066dd85b260818d871f888407f087bc04e5f59dc4bf4a65765e26da0c0fb8d0cfae747b6c85080f34ab48f38bfafb724d55d60bbe078ac37f5bf112325c614a44a9725e6fc80464d235f9a0d67ec792c965de9cd77c6922f1821132fb9d29bef6e30535a1f967f89e92ee2155f1e339dab0ae2841ab31d038ea7843640e920045f1cc1d3f99d35a1eb807c6632bbc6dbb49ac205737e790a0d86c8091c1dc3da1770b08eb070b845172d45b010e248e540b5ea0ebca94b879af8dddd1aad732436a469961e3343fb498c3a1b3671ebfd4798c934e6767b1e2ef96180aa5fcb0aadd8b008d2f6317778a9d9e98d385f88b90c885a3cebd766767a03e70b984b49722f72622447187d5cdaa0dadc788ea257a3f811737d1107752d2084e304be7a0a4e6f781455a30f6816a1f52a5c174e94d8c1eea8262634240d1dcbee480c0b34f2563536672b4a8df7a4bb3b3788fc8026f8c23a4a614a4bc65ce820bb567e4eb127cc673d08470fdd12a552fc306290327b84912f8c907c9765eb5aa16171b9e4cb9b6762629bf5207b048760833b42de1aeebeed7b2cb55308457a0667a74b78ec7933023ca95ebd1a5ed04ea311e10d596aeba3870d329094149a7385a203a173a47708c43158368c1b6c0d73e9fa9bb7828b15a25c097c66db6125860a2a1bdd73f56839aec24ccd3d34d1053c9bf3bc3813cd6bf2718820139acfc5f000984b2147a321e0e1268c960b0ec53b551483cd610fe5bd93ff46de917047084fa9e1081f71a8b1f052d1ee43f6889d317d7566b4178788bb436ae1d4337f116877b58f37bf4e09c1d712b89edc68020928a688c91678f9c0efe0688b2e21b6b4638e2e011fd80def52fbcab73c44443c5ceda445203bbc0aa26b19c24e14b70e2b8778b666a28c346303d83e742fa0d361dc48abc7c8da6c6a354dd82c550a1fcb360d0257a14bea0f3860daef37243ea2c62249e4f301116972dd67c47e79fdf9e9f70ce22d11f951ccab614ccb0ee7b71bb2e8941670fcf3d3ef4ad5e741733c9da394a0c5c1b2d4cb79b56f8d4c078244de3d25f041ce69009a203d38b81dc444009c8a37fb50a19b6bc01748e6d322cb7011cf7b6e08c26fe0480d0f4042f1bb4e18cd053ad7cbda632af765391d44ae5e45f566e143454a0f3982b0363c74119c2070c6e6f1728a8a6b0c9ecf627d78cd7d5bdfdd59ac52abf71218ba0435751cb7a6d03ae899e4b76daea1f323fb20cdc26e5bd781982bc055d17e1127a67073e10e859c01f1227322b409e623016d4dfe72603ab58bf135a0f968e0e931c234c4584e9cc0fb4bfb75c3e4a252986cd8d89b15e328ccc0e4b6a437bfad309bc88179e002e4b1d4601da939b47b56da9a9804b7a2a8d7e69437917cc1736f164bd70619b97792cb400aa313930e38c2d1f1120be5a97d0d72b0848f58ce7645776153b9a5d9fa0d4644f958bd4726d84a24fa244a8f41332e10764a20d06fb4449145f9e4a962dd15275265324144b7a8acf994096088b6c03c1e8d7820793a02f924c6dfcb161372324969ed22fc4cecc1976eb959645a991a417321184dec6994d9bca30872717498ba3f316ccaced47c9758782d934bad9fbc6ceb704cb5c58629812a66f6a027a970c8e58f8fe5d221973fdeb26622cd7038a247d0df17f885c7b932143771c612a664de627e799a1b2a9881b53aa40b820be9920a8712d2d81ed88bce276c236bcf7e9a6f38216e09628795437eb1f3d144b46228a1833fd59fea071fe9243393a494331c217085aa7b0f1090e1131c9e5e48f38136105942b135016081f988bd76bdcc7cccee4bf0e55076228faf0e7dee681c03d9667d0a37c59471c4961f775248185e6315ba38bac400bdf3a4cc7a676e8bc21e7a004af46ae592f87d133a34cee636ba23e0cedb5c0a54ccf0a2c83ea083b66ae9e19a82a6a385933a28e7c4b0945f183d4e2e791dfa89576ccc4bef796417cf72f91509375f2c1523c4356c9db7878bd1d6e58e3dc4b1a7c57ab0db624f06f5f861dff2a04b74f8565678583582172afd329f3ae5f4802a25d7265aefd982c2294f0702a3bb0880a91fd5375407df460a29dafec6e7dc6f9904cfde62ff292271a49a3f5478f8d73e51f840af2d9ee1cda00c9c845be53b7070c3f3cd95c9e46966d95065bda1d22ccb8672a2cc6f712768a824dfd049a54cf340756ee51b3be9f1674a6b5d8d33427f4d5e7dd81afda6a7743b159d2569f3dd283a2f98e8e4f2ccd7efe21baad1f6bd1183e4dd9fd26e4b1f8e4ac21a27e00d0bb2e8fa6eae1e7be4b1324a6272503159173c9ff04143a23749b426327c5cd2493e77fb6bccf7aae0c474ecf8fa59b9d481c9836a94765b6a04cfd351281e11944c1eed5e511664e32ec28b1ea5b9628ed487e49ea3e8b8e7446688061a0d08d261a7e5e8a808866898cb4789aa3bed96e2feee92a7f1e434ca2be0bd616f689b03d626ec436330bed7e9cdec02ba93493af8c9afa4c10d8845d6a32ede5e88353fc8c866724e6d2827355ff6faa002d929b323c26d508539bd4b7ba2af283727b05a47be88949d09e858aae22fdb7a3e498ee4d39050de8ca88f0b5d4ab76902338ce51bcb111398cd66af814911832cd1a6492a192c55862190e77747f6aa60abc44e53b669073be00971843a76de4f7b89f60d399bc585e17478ae85e36de4ee8c8e0783232e31c980c8a2564a996354c9912e27f67c0bdc4f718148db1e62acddcdbb1d25efe0385240a151d9dae6ee3c85c3e3f3d3ef1fc94cc5d6ad0ecc87c5bd701bc9a5e494b730f44e597b6288a964a7c22518a3a24a63e3cdb5df255bba1a8df827873ca490332f6fe2e9037b0e6268377d435c292298e0ba62edd033b3a2b5cb345aa72ca04db3abb2d73b16389331331913d339acf17b0a45ebb40a3541967c4108de1ce10ab9f8c3066949b9093b79f12c828c0c365e104810f0bee582182707485337cb0387758effc152d7908d4dbce31c50260b289735c98c3ac52fb11ee9a0aba45612f6d56a4e6160e98d307dffe2aeb709ea8fa833423146090f48614111da86a4df224ec0e865bcce2cf741ef7e7eb0b408e9689a4052fc2146c31f7e76a91f48e7b5d0088db13f6f4a3631bf6605a37059d21adcc0a5659ce911ff52de29da30cfa94eb518659d3812dcd758911b16a5651c5b83feadf246d116794d74aa61944d219fef914703331e6478873c0eec4e93d3a7579beb3c9a2485ac4f8b1d575e1fd7554f4f6f26c3a853c4fa543c7e248e426d2a865b9a5a2343e78181c41e36daefc44f67f26e92aa1e5d9aab6b4cf6ca9c3d662acb88fcba7568ea73610d531e4d11c5d6e956f640f3bad15d5c2ea30ccdf3972fa0a855ba4fd1b8a122bdde67038b12035dbd5c367da2741ef07ba7e9c62416b07df08e1a87f8ff0340fe6ce97bbabe717fdb648ab016303837c8b241beb7a4cbfa0cb2ad8990a824b0ddfd70edf4d4fbf5fbffbf5fbdad15c9c6c545c878609fb8b02561f601f1483489d7dd21e81fe473cebdafa8ebf7aadf01441937446aa46092a2aafaff615433326b84516343d4ea5afdef718aed208932c0648bb381d66670666927abc200dc8f96828deff24c5af1a3b3a674bdf62dfa684a2c95f1c1785c7a1df2a2faad8aad5a95b482162135044b8acd6995d92b3ef4fc795846cbae805b2d5167a307f33903faf7013b8caae516a9d1b2c6cb87ad568d5b8f8369b9d95301f5064abdbeeb6df5ed7705304a8781575fe1fbd0f631f5a88ce728b2247870e86cd0f2cd7d676d38e8c66b4c3d7016350acaa662ecd7eda6a685f57d858dd47329f4dc279bc6542ba301adf221b2b675b61b2e113786f5db332230b6ce7cd3c6306ac721fc1ae73d0a6c333e2eaad5713bd938e376ab16323eff643af5a1f0544c6f5ffc3f214452c9c2b2cdd3b11a2453fd3155ce53bf7e660ea05a8ccc1a8fd37a8dd7b32d393fd38eec9a3876178f5372bd991944369b646058e3715ad2efc3b3122e1c0c87cf2d923cc7154fdf16696186b2640c4e08d3f8d7cd4db420582b8ac92891e9b1cfbb9e7324d56ebc1df6b053273b705d86d04b469d47f23855bf32088305c5e2e05d6ab31d8af22f6a6517b711ac8feabe7a8d6055af5faceb6efde1f7cba2b532cc9df9e4431410c36cab404de524402fc68bbd6dd54f14d2d6cfb5c20a6f361aebfa01bb974b9f20fc2bd39b1a39ba0254eb12790a2432407a861d8c4a51628099d48230a38f346faba0c5a4623c7298ad33b13bf8317f32320cd920044ff13a78b8e99d1d2b10ac62c84e81e123aaea4621741e23861526ef42d177e7b7ce630acd3b17dcf2dff4e5519a89cf50662a9d19f9bc6310d5dd71c547fea88e3a6fecfb4092982180045b7879fa1cb3948946287903929edab96abaa29740f994ccbbe2e62d2f73123579c346a881340a17dc4eb20ce18a3c341bfd513c335c82ae32a0b1428201079067ddd1e911d6a9e68975526f739126f1ec735be38de14d3ab55335a6b8478433ae50aaab8f7d916771f2393cdedd8ea8eb0cb26ab4e1012ccb28b854b86ac66eaa3e9744294a0eaf7de11685eb2a004e3a24e8a1725a7092c8885a55dc24ce8fe26cebbb766c54e06485d55cb68f37b7724d8d07b6c93065efc234d39d0c23fa306034c952e7c7277bb19948b271f8972968092c5fabd2fd4bcdf6728e798d478de9fd315dc2cfccd5ab9fbb6b331afa5e6457e883758f05e65611053e898acd99161fa2f318b1a676eab8a4532d69419a6c7d5cae7632d6af929d2842e7896b2b2c570c0bc3b6dd375200138d0bae3d2c658a813c3c7a211db9b197ab9334669f63570572fb23c911b58f40a4717ea18f5d0f3aa8eb036a2dcd3eade2529e5c0309c1327eecb0362ef803e6b6ccaa200459948947c4c582c5b3abdf28542b1d10da4d7babcf7b6dabae375141a4a2e12253bd60cd6b907150d522e47a82e1391d6259838350994e777f0df1126f2c1a1efe07ce66bf7f43c3de9d96068d2d5f368bdf27a80868ee6a9f908278a9d689fa6878fabc11dc2f369ffef93789191834d69f0e49574b8f1d78cbe620b1975e27cdee6e7287c8e90d424e4b7d578a5222b22b9e8e01b06b0ab21e3d1115bc50a40534b73ab49453b9467dd15d9cd258c8c04bee17cbe2c2d55c2a427419b1c582ee919ffef9af2861f471c03ba2b0a62c0563327333da8ff0838b6a1264a03b3305d88948a8bc45e52f78f2be17be0c3b8fdfd33bfdfa6920b51cc2413a5453ad65d7e1cf59aec1eaf6c2272e1ed9efca5ca2bd82eaba0e806052f6ec89e07c2d2b9b70eaeb68f93a6257021f04cdd38ee881229ab2b540af5fdbb6b8c8e5acccf944a2c32ac83e63384858386b7764a1b4247cd97529a7b454b9d5f12380db17b5b556f7f4a92f0cba2b7b76c458c44079826b3cc854ea1757264f61e3d41d62857608cce847c16334e4e07043b41697485f004322e1e5b147e97071fe93123a9fd90eb2725d40270bd36c27549cacd6ec7f7958aebdbc751c5d603ea9aad2a683300bd408cffac66742bd73b2ed9df5d3c6b6d280ee8c053726de6ad5aa9b4dcc4c8ae21af65fd4d7adfc9e4fb2ad3e7f82ac3fb05ba6d98c3a3d7e4555618d268441d82e921b8fcef2acc0bda2002d24cb40aa8f8aca4b84b7a9b02e80dc10f9724e04ebeb2237bd0b7c874e3d73a9c3263c693f4142b62ac0b2b2ab1b6543f0eaa85accf9ff9b2d6eef36a0d5d6a13b3f2bffe784bac7e6197967a715aae9afc75fd381d17f7a5f89eb1d19d1d53f42e1b42a1ea7cbe3127f8a3ebc2d59f52b32c2acd3ff2aae4a0cfc60042f61d5af60045a7f4f499aa6f3bc04aed4add0783d2c6a7f234f6957e790b4b12ef794c7c206b1c7f174b7e51560a67f0f67b5ec359e9d3d5caa1903e14e8ec7ef2461b5a8f1b40c19a1d29909f12a167f750871aac4b7b1d1fe95256902c2b9853c12b6e76c6a1229693d2709feefb25e3aa8d6eb65100667fceaf668c14f8f66050a6648fbef5da9e0a5de010f4e1cd1c44773893bafd664597d5c155ff582befc0c8c1a31030f0465cea7fd90372b068aa6d26322b87ed1dd620dd6c06b40f0e7cb5d1b195de5f8e931ab30bffb08db794519b9082ea361fb01bd00c36390b8ea8073a93528882d9cc3a2609f5974e38eaecfaf8e40db40db51cabf0415ce3e147dcbf9152fae7e0d9bf85298c730cff062198e79038975fbe2bea947d0dd66cc28f9ed0fbb91b2bf4ed1a1541597a71ac97143e8d44e2100b264f97d8b79e2e0f8e668dd1574661ab94cb07c0a65bb4d58b1486edaa3de20cba334f582d19a27c7179914e817af161fbf921a2675243f9559944d4a137017881f6f80e4da951a48070959a4fe72ec399f726060b5b7b1fb39065d966654fbedfb9e5b8531cd1e39248d01835d5db7eb56107b442498fe25cc6714226b8e8158f3ceda597f6c3b6bc9e7f802a8a6efaa5364d404c5b672c9dc443d66e3fd9f0ff75691429464637ca3abfac2e8e8f9c6cfaa53f05615aa2c17cfc1397d7541933c692d946f8f553fa643b809a88b4d3ee8968c4ba38882085aed0a2b485df0d0a76250330d95968010388ab1e65e94ac73b3930ec2ac0d86fc282cc60b1e6884c96934b9db0c6e85159d9809c59a239a1826a3780723e285963af4a68d43088ddb0209210e6206a2e925755dbf6acff9ffdc3860044e8d05c350adf9c39ae920c9e5223e811b6f15c9cadbfe92ef65d7211184f1320e39f7934be985f17ce224854dd0ec8225aa8fa48287da5af3a636ed6c3c762b9dbabc07e5e7f734eeafdfcbe8f9e30fbb1b8c81841daaccfc2827826aba77f69d04a0756e6aae3819e25a67df89e97a2ca3a08db9d748784259a272b76528f69a28884d7176f0ac5436291c074cfc7c85494f83b6284bf5333ca8eee5045f0812e8c6de2c007c94d92b325a56addb5664eed223e6ab702513e2b5d67cfae77f53226217d01a1c655131de496cb403eaab08b1207b0cb5715f86e99fcd3625f9a43471183b352004e392e1b7df34d915908a1cb7472011cd86d08f11012e513a02454bfdadda6abe26d0483822eb1ea6ed3102b28c280541b7b910da526576f3cbc52eb982df0134e44bbb821f2607b53ffc30813f7f41902a109469d1c9b6983fced1c2a9780469da57d883da9d7341d34dc92602b14d4126031356bd0a47097d645feadb8b9d1d02fb583e438edc86c221ae1ed18043815a17b9089012efd9a0016c5bf845ba6c5cc1efe01f9609556cfffc25aabb7cd5ba90314ffe27fced5e5b621b030959b34729c85370ef6cef10c744cc4ab5f53323c5fbe348d68bb970e39dc5441e77f10fcb10cabdfc90238a4f0a9de50c1ac4a5d2d3330d5520dcfd543cc6f018bef48d18aa77ed4037ed6c244e8375cc34192f30177b598b018137a10008021326df22fd4d625858ef090a032367a150bd149401d65106a32f9747a0d143025dcc421e36b7945dd1e20f6dd17100d2f6a69d3892f7c46a755d5edbddeaba7a250b67216bb651c153d70e66e8eda8b4df75fc0ad0f4f696c9c39c4fbf4eb24f7d71e1e8ad50bcc68caa55ed937c64110b62646783b38604cb3e7f92ccb77622be8e03ab437f16e4e5a0f5706931bac5cbdbe3cd63d15dc9652216b0d101f03c21999726a4e7606c9e3469c377e098c4e2f8918a5c282e5a410bb47f1950a3be34a35a95b88ebee1956d265b7086d56f5e7ab12aee9b0f980cb6c82c5ee34fde484e865e572d037e196d8dd030f3d21f7f291e105ee4e050039b79257004722bb87829d697a067a3224450ca04093b130383307469ed986792971fa63e23f020f28c4ba7401f7d048647e2d2b62fd2e03a9d9e6f8f0576177046d99f06424d78856eb59c59058903611f7ebf789db4d319f436f0c0298d27c48a69cdfab365f885153db3de59b7e617083de6408e429aa8ef2da0afea0ca48d615152cd8dc14b09dfbff6695caf3a37c679309e6fc3277a4e1c817d9e571d1c129e8a928cecb397c6a626afd90c1a2241b35ddb10774bc5e549394ed73fd75ca4d5e6d7c289ea623ea872f944ed22f86746e6effb2bec59b1311e5379fcfa9d48ffee41227902fe08ac1e6621bd9bd6679ddd9972fe080c5bed0fd913fb5394d2749ef5e4eab7c027ead97442cf4c264e97acf7004aafc64842d33f95199c4084139a0ed626e4e0dd69d61ff120a119df05ffaf6ed825434fcf98e6738f8740fe942ce2a6814665dac06410e327c256f919ff5a83a66be09172e67f2d1ac84f33fb8a910db437667aff2bb382e8d999fe8c7b625b4b48471c60ae8b86d9f0a0eaa0fa2b40585612c6f35b02dae31a6533fc046688fab32ff29ce59cbb2b18626efbbb2e18cf6fc9b324f5809097e9fc2822bd8e2a5306225256b600bb8b221f0ad74ad2cbd0b4c04200b8ad197386c46545aec24512eef32c01f5a52bc350d759c77068318c9a6e233d7bddb73a9cb10d707448552b98a9cb8c8b66d79ed92363f8b8e4097d5c30640d44476e58b1a6354090296aa49aa6201e2052065815dd7d3ba8da04ed5ab1927578b1aa335854f5b86bf76a850c82e24edbd776d6155e6a8fb82401ee14e25ec7915c363acb3886f319812a5000545747c03c65fb48aea9654042692783fcc98b7ff52528b387bf3887e0ee40ed9d90ad41e587db0cc1ee76a00c14c37ef00138e5093cd0376d0d14bd531ad20838e569fd7ef2c450763f17a1ba87c121b329016a5719199d267557d49f0f7c3769d2754664dd9102a812a59c81557d6a9c4d46a1fc23f07406a32dff7b4b3bb210e7a66e4a76d99c58a1c4119c1919c9e6dc3037e523dcbed243dbb4643afb65093f451597c7e348a78c9eff48b33c59b075494e86f28c76084b36e74a9f24e63201e79269bda7239f036c951a0cdf3cdfd8212cf68a7557a2180b7773b6d0c316997f9ca494cd69eb682cac679ff206b3e87dc00b0986c401acf9d88e6b764033af6b5b8943d8bb03bb0346e77ee6b154a63e48b7818b518d70a8fcb04787c65ef80d35b695970399e7aec50c475445a6f531d814bcf2ab688782739815361bdae3911b25a7486ba0491bfd368ce2e218a95f85740e16e8f551ff4ae8da07835e531608033f2dd1f3b1c16997b60dead4132ac30d5eeaa8e8ec0aa06fc325a196e9ac7fd88eb624982b63c8675e47fce12395afa377d04c5f822511eb773759d55a3b66b55ee392349ea1d187311bae7ba42eb5c328edaf5be0609a83844f27ab991f529363d5bfcd29e34b30d9657b0bde63e499d641679fd0d1668eaf8af2c0676604b2bcdb6a4876f2acfc4e611b244d59f948505b188a1b88f07c837f3591c86c2a13fd21ad8273407e2f46ad0927a14805897f6b89ee206feecf4821d23b6ec7c3d2c6c75e9a0782eb16aa1ae866fb378aa3feaec58c09ca4a11f59b2f8f1451fd19829750a72b6347b2be2f057263f2674c08ee2ed6010a6130d452db0e414f421794c9a3fcdcf7e72e063f70051556169e9d175eb801940947aebcd92008a5bda9e112465d17181b228bf9e795887e207a94e030483f03e3541629c31c2776613a3c84529b972191948bba7aa2b182135810af852c75251fb71e6a07f443d5730d37ab175c5deb06433b5bd5f0c8c9dc00834d4ef16753caf42e16744e172ae48bf6913cec06adcf60773b7ec708eddd524bc51df953c52270e043a5cf86883b626715ced99c1b8ad6409ceda942ae39498da6244e62b82e069b673bf46d68fb9ea8ead26485e78afa0d769e5c472c780e2d97903643834bb90e9274395dace6e9b24c996d7f65d292dd1f3e1b2c7e4984171bedb31ca5d914c194cd02f07bcfa1049914e47afaaaccee97d390a3610f79a0beb871ab7d39e109a3cb0cda62e50a3e25da757cd7221194725809b7152d2ae2ba36a2c544e08cf6086bc8db4613c411a9d52fb15d3fe47ef7aa21ab4c71b1cf6129ca6345bd3ad3939d6aef3a84eca1c2649d938ae22e42c97b672d71942d78dd237a494c0f36a79016ea6dabc2a1e679205fc14218c590d842046c41877e1f3692f66348d85b45a0ed91b09ee640dbc5395804a6cdb85745e88ababed9c3472319533dcb1946715b0d501e7e3fe21f2ab0536fb691efcb990afb78542eb1216975f82bc39e4494fc8a3b6b9d2845f6265862a3738a1332c2691d40781b08dc00f99c38806db1782ca48e1f1112f3310bb5508181cdea251f3cae6d5425ca4aa0d233f07005ce838fc77d6465025e473b610052ebca09663ee24cd5091311bc656c4c9cc9db8ec6604b3ae15c70776332bd7b3e3e64e254fff9c82601dd3d1d20123aaf946a2c429a95c2f80cfb090ba3c86396e9eea6b5f4314f0a6e4b334848adbccd554f112dbc89ec6d39f68fc7e219af43da64b547843174501690f1469df5419ff9f5211dba7b53a55934fb328d84c657b6ae35e0fd4ae63ec17990993308434615f62f1bbcdc0d04ec72e548f2600e269b29f22b40e8dd26354052da1e83097d21c447371f023270f34cc7a9864cd48829ab7ac19a1e30ab8d5d82f1add7ee16398d00cad20bc222356f292c106abb884c11ca843a2f4452f04c2c05e5910e454617dfda8bd5d564ed5d6213bc91f522d318635e79516503e33dc09bf8f1627a268329a1e7338acbc9647aa680dee4fcf9553871109e2715ecce07f5fd4d7cb365f44496c3f788881909e7fe60ade1244fe3d98b8d798a5d6d2e3101b9e35338c33e6b369fa5acae6ee4908d557840865ebe39a0ca622d77dcb8f758f1b4495ef2f9a0f7a0c2ed5d0222663a7a5fd727af8699f3b420db6f0bcadc116793757f46f979c35938498f2a028c73a46dbb1450920fdbea559c9a24a6aadb54ee384a1990751a08ea614b7bff752722afa976f77b4904f5466f5345199d48ee55812e2a57a25d87a25972cadb37da05ba8f247549c0921a8c04ad37d5ba69a9410a91bdc633db2a2fd2b4f157bc6a7d78bc8a0bc5513a0fbf1b74b1794a5a1896301f4586836dadb6fb33d1ecbe36a7a71d247c4fb6a3bef6b10371ccc84f2cba931a63ebf653dcfa294f188f99c82817e5ff0d7236e7311ee5e499dd09b97d3ca6419f11063468cfcd61d12e1e441d3d878c8f51302fee2acb1f928c7e8eb60e7fdeff8c7e3e992ca3be7480ce3f9373ce072da3923d29879caa9aa77d2c9ab244794246a95014814ed3caa8c0b11b3ae9071dbc01f8ff0340ee4dd77bba4e3abc27d996dc4935ecee0fbb1df8fc9436b607ac604b5e49b41c6ec7f8ffbface617b002978d5b89e220dc4ba23a889e9d39871ee2c6404af7fdffaba6aba63785a0f064092b0529583c4a56576f88c72371d82835d3eaeb2e51b32dc4020b03482f1ae0a06e96ba206a4a72810853094c13e9f5504105d5e172604643b3c3c5c8700361d9c3ca1d940de18ad91b3ac0e310b4bc6c36a56d1f63494dab2b5aacc82154a8cc79055012255c9a00ba841efaf8f8e41a2640248a415dd30557125021823d0e93e967563c58293e7c4e7df5d4a26e881b32ff84c3a3e21eade3799282b1657fcbc725df54ab35cfe59cdfbcbef0da9df9ff9f3783ffb74f904bf818571c47328ab238cf6e616e5281534da24d64a432ea4ad2287486ea0f5b8335e6cada9ab3930bbfad2577f006dd93f8795473932ac5b24a45b9430c2f9378ba0858df1a48ac2e21419d041164d30cc9a5ed8d2a5f1a2dc1642352f226d46a3cf6efbca4d981d1fca672113b983db6e84b292b8768401b3ee7ac7ca7349ca93ee692abbfab1ebb8b3eea4aa80eb921d84df3c291437adb75ac31d249668bca0fba2c8a742af41b95f6d4f74a6b28bb3edd92c7b13bc5a051e714f9941f5d7af6ec0a66f25a103b4f999d82af7c320d9a72c1eb0b6e3b97f570303a567954bd2971ac40bd435971c73ec9ae14b1dd65855238907e9b64f5590f59861dab4a1b107cfd611893b6668f48319a384f16aa7fb260de00c78950df20c50b804f6bc65ea26d383df4d1b20763ea442f653d081754362add2e209eff586899d924b1429ac1e2d263ae38e4d4f398554f9cd36da9bab7a497f58198f906494d0072c561db4788cdf3132e234716499a4bba03ab61937ea85912a16570b9baaf800de140cfa96e6c0a0de0653890833ae61a7fa8d91ffa0fcd616d36d50cd509b333c9a7bce1fa27b4c56e19b04ee17b5f034db023dc8d6f1f2d5642ac7ac87645ec20035b757208a4e2e0f7fe7bdd9866fb56315811f6371cd31bde2a064f9bf72f20df04c7d3aaf2276c7775a556d718d49185370ca6563d4187c9eafa7e9f42be09660f165c09e05e420c218ea60b08a4534531b14bec31102a6bc97d48c40056488b777fde8d33c2d819bd336576956f37bb4f7961e9dc2f3120c5c208d28e91e50e8eaedaeef1283dcd896fad25acd9acba321f267b22d8f7a64e4b8e24773d7265cc539c38d40201067cec8f74176dce9adcbdf88e5e3c9c01adeb7a87e9366816fca46a8b48ee9e6d922859a3396ca12e03d6f3ed193c184ba81954166bd530d82af21a877fd75741fbced59328747a8e3923210511d41e0ebc907cb7f733e97e08f6ca77c73a5026ac7bb34760b2809ffa70464aebf72a119f029646b3b82cd76fcc00bf64e2f10985c97cbe7d9cee0d7bbc225c1ce6fb96e695f7ea7f01cefe130cfcbe317a7f55f0a6509f49c3e37271fbbcbe85eac3eaf6f6e9f679b34131af534788562980eb1641ca8588e67cd1a10febded4e1804a87ab8be369957a268faa95e9867d03c5319a574e79c0c6cb8f094d2778235d461ec5bcc275118b50d061c4c01fcf7fb50614a2cbd540da9b0f3895c615cb52caa87464155a89a13f7e38e5ffde138ce61820d73ce1ff5096a671a0e4a1bd5dbb286af39baea432f41b5e7edd00f2eb7ac9af2f8c2ce2b2880bd95cf877d09910d32d0ce00784236e994ec5d0d16c6412a29a0fc720630a9f193c2dc3f0f4ba847351385303a228527ba0282dc3f5ccb3948522c9035ea18b57a882f048843e6dc522b2cba68c70bbf4e814857013d3683837511a7917dc0c957b72013cbe211d45eae044359bf05cc414091c910b47262455ba5ad592797aba553b8b5a24309258d0f468e7d7924f0f91cb0f78c3442e16b00f481f7a52f80923c71e10ea316a02985fd05edbd9ab4dc9f035890634890a46b9bd44deb0fe7293b2d46fd68fcade64425e8b28174983fc1543eb6754de1de58726291a4981c36b9546c7296a11f6d61bb0f73d9d66c94ad9892472b8b6882b5c99640801c372fdd78051f65c44b14cce220b99e41505c4155c9a014256a489dbceca5caad1a8bc8a05f482f2650ab03403c8e5603552869b20ffb6edcff784834490148c2b9a86a8dd4231b6c1222b28a189dfcb96101b283bbc2438e83d7f957b92f1db309f4fcdbb9ba2af37f02c8a7967360c9efdf53bf16f6c9ef172c94f0b273122464d8d32a120769e47c756e9c05d84a148407c561b16c184653cc48361dadfc08ed077647b722e7c3f933d5c4da37099551c55f8f63350158bbe3d5c8d9912245e674d0a9196850890d5b1fafa52bdd28496a3685cbcfaf4b0cd7940a800e9b2fb32484da784708051fed6bde9ed8fd8c11039a13e77f49c87779635dd33c81eb3a0a138c4bc1b00e43130d569c0c141c3780d949df20f7b1c1d4c7e1051145da680b4d54d3130b0c29c1459c590a7248d46aeb35a2d18fc4c7d8feb33ee193ce250633bf899fff4f4f87140686849c1f935bb5990d962c2f5822f0b2e96a430c324757ae3385a73514350e95d208e34b28975cf371b268857a140f80ce8c7c647139d1ad1c331c128a7465e08eac5f9140e5b48e15d9f5df0d19ae10a68091530992d1020367b91b19cdf44195b289c31eaa50c808052178164e598e4d1a56542e06a9075bb49ad3830bbe30fe85cf7e6213c79888f4d460f54ad6aab18f82e474f5b58d4a16dd7ca9c71606639deb45712113e3ab0a809dce692d7821536cc281e10624a0e2cc92e73ff475264797aee2958e9149ea34e70eaf3fe06ea5117841a457010c3d96930e0f4439b06e6eecc380ab3b4dd323194736e43782d4f5cc374953e9769e862311090467c41bba168490a7d35942cb8ea154b1917655c038984b5f869321d5d13449f726e68e1cbc144a69198166c763659be5551e0473d6587e19d8bba368f622a20cab4cb4c1bb4750649d829f0895537955c052b0c4f924a30ec0f51790b9da5326dfea30e6f1907f186006edf8faa0b5d7ce8831a4f0279f7d8266f40837a2ff3c071b003118b91b519837a1c438076f557120a28c9deb3a2c98511f60f04f069a5fed69ce1d4ab86750ecdf55d2a2adbb9bbcba01cd2afb27be0e70ccff065540ec156530b39cf2800ed146a5bbbb9e4e0712907011e11da7b5307d12da2c72dcdf25b546b899dac1847d019dc0583b06d037adfa82c228dfa3d2a42e61618d17e26b72234fd751855d3b80f4d15b3e9528fbe3cb6c0baf3b87f4d4c4bf979cb28cfa50cae9a278bb858d0b3aa42da39e33205ae92111cc7cfbc33b621c71766e300b43d05f156257c40b87435228a58144508895ca3423a2e15716feac0e746f9224473ed0d01e91934de6f97e5cbd2e1f28a856969b7c71ce44141c7503d14f9759579e76a94da37ed4dd06881da0157d5d618af1a1e58e3dd13229cb7ba490f0343860d71e32d81e41d323408590de3ecbbcdf4de874a177ac247249d5f8593d876412de5916c4a999de9bb6f1ca26e8379030c456a5f6bae0c73a34b80a000d347bc2603420c423870c5a2cce2342d6e392e2ac607c4634f915342bca2e9bc01563f927d56bbab335680cfd2dababc12cb83037e985427de19361789f83d9a4e303b420b718aad66429ba30e6004c6a78eb3372b815f24e5cab220ff1bff90490b25806dee058035d73d1ec853ebd2a2c41d1c63fbeb3f1f2999ff39799ee7241b674a706acbd12519f0679fef7fa3521ef60c71ffa66623c1abae18caf22c9267963ca7284d45a450234b64f748de1165a047c9e4852cfde905de85399d7246e7253c30fa6b96dff79ecfc7728d7af6e719bb8d91bf67feccbfe17bcaabf0e619c9b11871475c261e7149ad444206212c510791cb5f149514e1bf38d4c845903529ea9b5049d163edc26a2905bf5f8aba0c7508174136887843b5946206ffe5e82082ac7d51671165940a971c0baba5144bd392b48eb0c08544cadc1d43acff84c85da0643fbdb5c7313c7fc4862a2afbd1dec1e409871a931cf455f689040aa0186418b5737eb5944292db259775815e4d1a4ed74ee7107fd144a61982a46d99b25a6d832d10ba7e6e4da8d21e6490d6d3beb2f1871fac0727f21054d002a62c6570fe57d94c8d39a54307a522a01ae122ec32894bafb4148eb434351c63c07a32c74576671e4c9c702f5c6a5fe0cb290daa502af605c48930f26ab228f199f10606eb11f51b1377d6c52074137492c17d0ff0e918dc1c7dd331b8ed1fc09d05f566e442506de9ec3f822cdaf97598bdb815271f13121d131c557ce07c3e07a8a4f82e280cdaee54229124d9e4b6f9bfc6d3af2d027f40fd6543398d5a9328f668b8e8cb833fa03182cba4115861910bf8758c4f4aab2f049791896f84ba3e53a10b8b24bbeeb4b4f529907f3291d9722abfe0599a8fecd2143ea39c48792b20e257f2af542fcdd82c9c2eb8d1d3d82eb9f1351109e41472b8a21d99bb6c3136490aa1137a7e8ca87bbac9872a73aa6b45234bac28c2c55e4beedfff20b089fcf0fd6bf2372478da81424abfd7430e59b7514849d5566406d85f87bae3e127ff68aa4a80db354656efdcee046ac1022903a87c13222f10920bf7a1a049c3b722f3afdb24f3af372b88c58c7ecc38a5b9b982c4a8b02dd17eea41c9e75238367099089bbea80ec1a116678bfff84577c656cbb04950f145c83960167d176686ffffe40c3aad5a591199a3146512e7706a8b88492956a1e1280e84a835bc58e61f11649a356aad03611437331a5a36155a20ea218accccb7a09a12180bbd6038ea66a9be5bf087ae7908779f4e333f74dd3e631b4d3c0e19c6c1b1cade755c6b8d1fdf3de7ee991dfb0796b585d5ea37c679b9ed5f1a32cb5c044643a3883b3c59653da4ad031661b3e1072d4577787474fe3419af12220af9c348068c24352bac964168cd1c6011bd69f53913f14a14832900ed0fd08cbd8842a020e3753c1db03b6d17f18069467f676cdc01de656a2adfea0e3d2c9e44d6d561de7ebe79cec40ab8bbf3b844eb6abd9708282a0b18bdcad3ce489a5369a9bd07c1ef64415eab7861ce827abedf49f9782047f569c92f43f0023d33399cc13806938df227dfcc9d29337592845edf91f3636ef23229038b8fdf674611979b5650b1dd417556f4e20cd4e578f8f1b32c1d105568e98055571832765d71d9151db05a2e00e3d8952b3ae0ac3018c3c436a24729842c80452c5ed1011726f56ec51ea3d66c0c09cfac3d5e4a9a15ba3529268c5630142cd32b3a7416b04b2e0065bb6d80d2c34ca6cdf9845d48098a09a3d0eeddd4552e15a19c6c2eec3ae84af3b8415c31593dbebcf4624e464d8144a41d7f8aca60ae6a8631bec2e78a63c22e06b83421ec0760678c1fadc2c36ed0e631847d8785b5f771ff71eae616193c9314a166aaf1a6782e3d7baf21ee4cfa4ff756213ecc017d26419d3134b2688b35668f165d01e78c510ba6174ffef8fcbb77cfffe18fcfa73820a4f0f6944e815ef90661c2c474434e59117c21eaadbec519755aac067ca5d1552c580daa40888680621d429eeaf023436cf9611c460d955fe798e0f483f9fb51190f00b3d5a0730758da95e8cd28518eb94d329f2970943ccd6298ac2a731b33c599bbcb7c5e6a1371dd485a68378b8ae66c498ee893de4831abe45c8161a58264c427db37aac9f0f0e5dfb14a3d52eca02c2e5b2f98d8dc20a332cd6ea69c96d8616aca6724cef9f7c83453cdc6079f4df13bae842d425792830ec526307cb3efa8b5c761201ba23ed6ca4551da3711a5f0d0176e3aba59ead1ead1d7006268f8af1333f84af191ae5044e91cb6c09aae58648994e5f486e0b282ff7c4ac33d2d5ad52643e69c27794cce9a2cbdfbb45b1a7d95ca39d7945ec6ae5ca81f17f7748137d0fb6ed441d34463b1502a5add20dc3f852969adc48754e179888ca367d5765433480580ef79d3c12426c06161079a4a369352db62336926eb1f83d1586ff15ab72bb3ea6316e165c0b68e606c2e2d6e2d651ccce363eeb3ade4f7632f7e2e609ea60aa035c3a27feb68e7ff208da651bfe6f9526ae7ab8788758571cad4d37b5f9983ecb80540af54404c90d86814db19a2aca33d2214b9765ada7c77c3e79c5b2ef229ff6554c68831a55094918b134e1e0ac609de7c77b8eedc196d5356f7a004895d77bd4479de384ea0872fce606d00f8ff0340fe9f6a55b57f37eb9d402014a74ac99ee0f146cf052c7dd9ec20d00072b8dc145714d5f9f1cbfe9bdf5d502864361e4536028b45e2ea5495e8e969312f8837ffff0d3154d5bd1d677ec86f4348ef23dc2647d40885b26bc57493a305a1f0874cf9ff37ff1cb655ab9810e6818b777d1e10c571dd490ecc0b51e44575c3dcebb85c9c16c2356f823e3089f45c69ce389032d63b1301442f23a5249950fc2a6f725623c12f20babd6ef0c1ba3dbdc9d0ab6a407f7a12eeaebc05a37178cdafc17b61cecc14df5c6195ea0c8fa2969d30410170ddfbd7f2a8427da94b1502abe92bd4a97128bff1daa22ed22af14baac35ff22de0d998f30079778d90d3e298211c09ffc3cb6f69abf391b0c7724620b1f6f0d314f1fc0574e424464476d6438fa59ecfa41e10549c2aa0845a3177854b898ca79ce57791d51c0461658d1d062698c5d233bb0c76f608d784d3a89c6d3a181c8186e579c2a097271cf40ae25057fdfdaad0bec8ea8b3c7e75ed8c57c5f9b19fdb0e638f73e7ce5aec36bceb4e5747406286a9708be975b804a268e6a266150a001f52aac2df893dcb6eec9d13a31535f9a8d785cb895f425de5e1a749ce1c40142eb6081cc9e13d8685032b1ee0bbb6c00c86a234a86152838a0649f1e389277cf8247e6c84c5fd90f2517c0ff9fbe890deb0e471f8463464f4ce8a17d8ef2ee0b3dc32167e393226fa0a83bb40ac0b89b1a32b87b52292864f5b12d18477367646dcd2482ef381932bf543d689ff7bcaa2cac594c7c5f21f9dd8e09503baa128aaaf4cbc3512e9a5ba66c0abfb3778b70378b446bae237c676c10fcc0517828177818cbef01647ee9d852e8a173d4ef0f0492294c09bdd95c223222c7c890f40b9d25ed1dac6d3237c06952af98164b0ed930f99bf49a5a0249ffa1e64e9503eb7766b20004a9d12ca6003a7ea8ac1d9a81e21c3f6d01102c03b0e0e7b85a99e318922ea056d60757754ce60bf2d4ea0a3b9ca76305f6f7c431f4fec3c9a42abc5ddc02ee49e3204b1530f071f0b37b1056499b7f24de16cff5249dbae185d272bfab1eb100e56cef38fbe048b8655aae49a1d99b61a924fc065d99a64d5d8e8597d236710b9cad2bb6a2ce89419a58e6d31f7a614e1ff955b512d215847dd91c15c42d638f94a13ad3348b3a8d626fae7e29c8364c653d778c4e79b59e94bb050b03facf19811845f69543e6ad39c7d6d8b6481a35023778f287f37296f99968048529d4320fd5927b43f88e358d0026bae1fd3b5795cfa1ddee14217145347c6eab31db48df1abc764e408190725db8c5a9d6f08a62abf5d61309693a44c73e66edba55b757c3d80a88de597cda54b37b788030986a7590ae5c1bf4dd0aac7e169c6444bbc18c313d9118d5011a3138fae99bd9f55375da0cd508879cdf886dd73838153ee20fa24690a138ae4aededf6aa4ca55b606cf3882a66df42b87946ad2ac43e4864a3ecc897c012bd405ac3c61f5fcb48db3f392f97c50285004c1d4053bae6ac39bc27982e3594dfc8e2a094c1190491278cc5a5f8c8efd478ecea1aabe756b7322dd827bd6f515f071f178149b3512f5d7cf03a2089e0c812b653c5cd538ec85f210a4a05320e4ff2d3fd6e5fca1b61f42043fc10985d56dae0c6bf4a9e3b1741b55e99bfe7ff25ab5e74633bac50e7c1a7d1460d14b61c0cefba01564e31b2158680a877b47c0dd5a8e7e162e8752529168ae7e2815f7f6235b9001dee609678cbdd755148e802c81b1a42ddcdb111b01473482f5e6c6b78cf25c616fa17cc6d0cf419f0ca9433b37d2c4d234216d55db1ef60e5a5f6d1e3adb9d72c66b06477fe21959e2917a2621d39a43f357b8abd576b32f577c149f43101377e99c894fbbe6f1f74a094b15823421d33d45b0fdbc33f72a89c849731f10f822f9eba39335dbe64c988867025553e7ddd1dd46705a2679731c6385220147364aee456af7a36ff22a91f0e91eb534f8df7c71c4c918eecb13fae78d517f1b03fc8463d0efa5e3e47774d65ba26eed7c2adf30e3e43b8ef3f9412bde86edafdf891987efe8ecebf0b42eb3f2468bd362f9109019e683b35fb3ed8d9a7717c4db61aef036ec8a2decc82fce0c33aa946c860768d52b23dd3e3972ceaa3228cc16d10b94ce72681bb0263a8fc0d80e2300ddd955ab5f6e3f98c35eba675936b61e8003cc067a9e7b3689e1a4707b1a1cd17be81d3cf6f3a6ddc0a10c5dacff2f03ba3840ed7a81a4a7817d8c3f852a5b8fcebd30b6e5d5187d81aae927781020b93286c1a6e1bad3ca4989f7db58f660b5d09ccd5e2269b7d45b8ea7b34453a5adf3392f9a7636c9c11d9d13dad688df6fe56b49c9dfcb3908ab1c66c951bcf8bbe05a869cfe81d45560cd07071707e629ab2a4e0b0f3f6c1fec27982112f89eec379afc9f0a94158a36275126725d5399fc2271a50ea8a836efea6378d83ec4c5d22e1506a9736d2c0af9cff9a90952cd65cb5d2b210dc808bb5a6abe8a1bb6c60707532ee279b0a8331140201ceb0785dc307f70e541e33f6a800a463a44af182c4d65ec3a8c8a85de691d9d15f0a7e3e048a2cf58fa18e015b3f4711983857a24c97d3dfa0c0fa60d2245199125fd8f79fdb27d31ebbc7ec69ee02d7eaea540ad109f5f3c529d26d6aec7fd574cc372f5e8c781d3c3a42c523b9ad3321d92396116e131d4c6a8ab852bdc56912492e95655958ccc0c72554c3a7db2f657f4d69abce9f7082faa4b55375c25fb165f3ea5aa53692cbf6626ea33bed7172d8117c509939f3334e32e8095bcae5890ee799f8d09ea49bc40afbb9178a7bd3eb44d547f354590404ed60a05db3c4f46f93762aa19f157cae2467dccbaa07f79810ac3cc7bdc4b87c1b617c8a34199e9e9c30674703eb9bb8f1b49ed9cbad0c12033cda25536e819d202ac1b3d3ac215dd22227f7b134df705a564a202869b64f4998d22b45f6e53269d8ff3d1a6de4163dc150d3647dab198ce1038e109c461d55ce0663299f274111e0a67e321cb4d0b10fd56be9e87421f6f12d6d5a7619c97d9be2c1422f5cb4704a9fe329fbc53037f41124254692936929249324f2dca240cfdfbc99bf0749615db6cf935f7d9d18181c4bb61821aa0a86ec31666817206b72646152a6acbf484e3b6051e48649465bfeaf6d254b38f50130faf1b388540a683d29fac0648601330162d6db5e90b9547448c92a4286ccf50104d7b05852f083fca5808203b55242c2600716d191b37ea3bc5f0636c5788127aec5048f873c9131a9f81e56432dd838e3f70824079f7e9755fb53cf6d3eb38317f0b4124321a9013848f80a106334336afa0e3d6e61d20625ec65dcb42ce19a2bf4fc330763269e6a48c5aa7e1efcedc1af5ff8850b66cc5e500939e43397c2450f150f0f98aaaac3c20852fc508d0ac43f21dbab09d2175860e9f55798301a02d2ad24eb0a242c1f02528461d8d5459014fdd760c13dc47ba14b07f8bf6b751f161b145d66d4624cddbca104c0dbaa4172bd82904d0d08933b183527deba069806e9598abe2ff15ce714a81e96d3e86de53784832340fa3893c06b7b444cd7983239060a4a2220c8333892150384a9eab6c4e0b3a136316922190f2ff96be38eb127f462facd44ae8894a1efb712c5edeb34c748a4eedb0d73e289669a7fa28ad50c145482dfd493a8df2d713a5d15986239fd9168011210fb996e9527b860f0eb13421d143fe7454354f00b2327125cc25c2fd24e7b554662cd92730b9a3c131cf5224bd178cd7bbb4c6c1612b567d291b2035822021417ef3a380c61738986ee0e72579123d1d1a58d3de5c35f5e611a05aa314cacf1606fbbf4039ab4489b1e23110b8dad52960d506194d1b51840a7ed09dc9d490fbbb09cb85c6d438b09ffd04bb51ab80245b8f266c6600ced24fb0c79ca8e088eb7558ce8a1445ccf4cb0566b22119229038a8da533d526a1a26d2197f77f8389f9fcf23a2542ee03ac56e511d41079283c6013f2fa779946a8060690c8b6f581c67b97837c9978f2245fbd4dfc82400fded0aa935c096209e65a44974b6a53e12b414437a6039e12173326334b34d247e37b0f4b236c8bace8828459324e0bda4096b6707d5244d65a4ef40042d896fab983a77fffce8d59d83a24a976547c6842cc8e7c9d2947bde8c5f4a63cf8e9130cf34c5a8366cdc7092d9761c924f8dc037ad735ff54ba5435305c17355dc913a8c8eaa148806f59a0ee69b2582c857c458e4688de95976522250c47d30dbf13b5dd612de8445dc725ee1e85698943ee51cdb1e9c27101ce9ccfb385d6fe846ad49751f24a1a932de6371782586c4152338dbfc28b466e5e474b9a4123d14e917e950466037f1254be487039e138b680f318a8f000a3d4119402f696a8f1012e736127fad135abcbad587301f35942b86c023b866644494e24413c7a2d6f0d0e894913b29b93d48d3f31a835b7f877d922407881b02bea227f28d5993c6d776ac5f53f7a6b505de2aca58563163738788804cc26d12c1c37afc052e8b9bd44118ede08866ce4d46b408224739e05d58e5527cc579b62dd29f0982eeafbe7a0ad4455da6c613e0168fba230fc75f51f21c902a096eba5807738bcd93306bcc9f482cd4307aac9ef1cc154222ed85c31816d84fa4da9a993e4ee1f8d08cc35b795ecf6b3396d5a979647e016c9e5829092b868e5531edfb91de503f0ccad8edfd7abb4168d078eb02c8c5189940dc51ac294bab54ec8a53c1c5c510092e546306f0439a3cb1040d402aadaef47687a1256efec0d4075750a5da51c7021e4d1204c5b65196b48016e234aa07e7a332691ada7078aba0bdba676cf04347ddb6a4361f587596c2db245184019ae01065bd8ec6f3a0f0767bbd1b09066c944454c84834c5fa243d2a5501740326803a3ea9fb838576cd27f2fc3e5a3da3566b6bdb8c588aaeea845ccb6bb2a5b8d0c1828d2e365e496171b6c477a3b20666cd6f602cf17c60d31a320edacad6d38b53b2644046f454fb7edeea67921465de5442a42de35d5e8bb6a959c5cb2e4f2ed46dfaf9e5245fcbeda7d5d1c575612fb5a4835945ad0ee3f84edcb30e03a0a36ea3fbd46e73ddf5d0f1c03d00f8a79c55d3653f85853523c3d5daac83fbc94cf6bd3edebf0ce963e96f3e6d4e3657199bfd143c9b3e65cd45c7fd7b236481d990e57a5c664951d9728c5ea5cc8adcf8c947d3f8b471455325f1381a9342eef17b2df1f2738b16ae7d4e652886d494d1b672d5085acf45cc77567209051347f4b63c80c7ededf2c3c1455d31918ac79206c7b7944b698beb4cd3ac52373d6f28d6dbc02842e14aeedab61ae14c6234a82df8ff2e70e4958cdd9142ee6e168c5ff165528cc1484b9f5ad90749b660b0659ffb641061d5f2c6161cae94e4049fd72020bc796f84e1ce57a655d2906626d1c3bed2ffffef7fc38c0729b382b9ec95d2ed03a752cbbdd4b2af11bdb4610ab23861d86bb49cf378d4c30628dc8911cfab231f8aba9f71ac1e81f5c578d86d78ef030b636e7cd1dc894a95a061bcbbeb2849d646678297afbe63fd9ac7926759201baa800da266a3717e34352975c60217c17f15bd37b3c4cab9329cb8c19886bfaf4f5aab87b5328232e238a1766ba755a4cf78b32f3bfde28c93a92d809ed9ecf330e3b01684607a705167459ad50618f99d4af89d7578874c05b048b87607e10526845b5950f28a732750c8e3167523a74474163a0439ac6ef304210d44154a2fb728dbcb522898baccbec8aa4a80bcadf3ee8c5a35edcef8e4449b0f4672d1bf43671d0868be9aaeb7938228fb9e5931f63c5be0769730e16de37450455c107b1f04a0f92c5d2555ef8f7f581eb47967598f9333100d4b714a256bce879cac65b8b89fc74c3a01949e04afbbf7b525ea2dbe57d3675e66f81a0d59ab66b333f7c9a5fdd312c14851967299955d29dab2eb8aa2cc445dd6524470822d4757c281f8f15bee6171e6540397d285ceba7647b671bdd5c72c8a61718c062e5408e85eb3b754ab3e27a1bf7cf7b41d3d5e8f6e6f36e39c81e627074b6e83e5decb3d4fa97333094f9fd62cdbfc56be16161fcd43a76dcefb346858d77bf86cc09faae93b65fca3fe9f5630341c1c7dfaf9e1812307974ffddba7f97f9086dfa74729684a68fd34d0f2184506d46d3dafdaba31900cf38bd7d879017421e9ff258dc8781ef0ad19173c7865a5cab54e1109ff1d551d97669da02badd40ca842771dbfbba03cebdf04612ab22e2bafa4b3dfccafb8c81e4b50beec1e57659df90d953f10e61e7099c407aba017036cab2dd84e7c5d514d0bf6b019b38761801ac834b4e40243ec8fc5e09cb069f175fe46788a18199dbe6499505f94b106ed9164728946f2fb84ab770afbbb258676342cf77ca2357c28fd8c7a5e6358fd7f5de202442dcab408ab9fd5e2dce7092b27c4eaffab8a6fa2e037c16322c2d93f62ae071e0b4f7a9c37ae18842f2219c70a436139411958e74d3cec1c1c2724e4dd32af26f3ff0161ed1041b63fc6120a990fe5e2035000be90e3e1e962e1936e94400f06dca2b0619827384f18cbaf18e1dc27eb71b419d4d1bbd0e46e1c9d5089ae829dd49027a9c1e2af9719b276ec02d9515afa8d246c186f0680968105e4c26df4cc0e9db34a8cd5dcab212fde4dc048150b56042865b87b4810f53b68983748da3ce8877580ced9aee30185eaedcce653a3f1c0305ee20b61d4f7767d8c4c3bf5e606b7868c5fd5c57eb18ed68ee59759df00d767bf715d9366552eaaa800204f3eedc3914a580e9ec02dc9f18c7bcc8fc5d0e621f46f6a0e1088e584f01eb7ff9795ccd8de262977b2eabf9f42249e00e6b64fc589b2b23554ccfd0c84a17bd6e03ecb5eb1207e399bbc81e3fef39624b1c3c060f2e82c1ef67f9baa1665291f967c17cc024c2f06a5e3e60050dacfb20616d3053535f5d83f7f4c263934a33046b4e61144e97c42015c536d7bbb4ec827e163d035138faba45c15f22e0478228ecab8e4e2f2d22ee4744ca93c0b8423c87b0ed2fb437e0039a359429ff73c9a5f929cb1fff333554db989d67b0133a0660e70003c6539a9173fca7d9f546eaf0382f36a98f10ff390be5f2fc9b0e6d76fe2fb601aaa56b3e8cbc403c7599c2a0e1c0cf8af368f31134f4cf19a59f436ce38767845e7f17ab2cc7787b7c4eb4700f0274f6664347aadc9f0fed8b4e22c00872c49aec7021bd9faa26845bcc5cf458c79e1c69b917d96567d4b0af521c17e9eb2a8330845bcbefbe194b2d8fb7e7e50a30f45f74545d6437f5e2a6fa934590f1ca98beaa71fc60349d24769dc59243419f7820f9388c746bbfb1cfa6a18627317d371873075427fc351cbf1cc3d2e3b1d193cbc48dc136430d4f8303faf1800c88b71e11bcb364357b460311eb98d226dd1ff00c6abc2b9fcbc644a408ba4fa04c946f7ca8e914c31f54bde83cf131f6d319d7b1cc1d354c51ef6b045f3c1c399852544ee3bfbecb158daaf0f11f89e82420f1068be1a28cf16c3a366732e0c44bd357a41b795a51abc904cc1c211e06e18312ed4ae2673daf77d1cab0763f045b6f9683b55157d85c31ee147c809b27146ffa5d02d004e36692ba98f6537bb4f8d4f4bd9cf722a7dcede9c459125455efe9acb5ce3c49a7c3700f8ff0340fed4965fb52fce053396906e9b2a64267bda7bb0e43a841158f38dc45a3247aa6d8a5ffedf37ebf72d4b1f7702c4d00c292101e2c04c0dd8afaa06139476cf29a4eaee9ab4ab9422766286387343b833a734f78cce484236f44374f57b5a4f6b438110b6258294e56349e6d800c5bfff8b982a0ae938da932612b54f122db28de4b0f210c5914c8d5b2a4f2ee3e46f3b423119c8bf64e682afcc324e61b6914f59ee43955ad63356b6202a92b4be11c9c8ca157d295b132596ede3d9664ea1a3c1b4ec94c70d244fdf5cfe0b34ddb07a0ed5cf1ce17a9b88d11402087943274a964d765ff4d69ae27d3bc26811ca63c0c9e1b83f8435c88df99e990b1e2ab37c1b33f0e08c95ab7b002abab3354cae3726444b4b24f00b68486771ac6ea059cc83d2e8d3f1cf9c0dd1ce2e276743b4b7141de1df37a7e8fe708f1efe392d8aa4a6dc8ab38de3312883eb18cc0b470912ad3b1672903cc2f189f402b07a0af57188e60cdb504dda6309d3f15a99c159679431e94f05d03400cda1724fe9101cc84cd51702b1420d0cec46bef1d0d2e8e5da53b3db905cdf01672abdc36c3838ca8225ca2e543895980557bf9e345499b2f95d89f7feedccc64ab794f828bf33cec1f994e8506c75245acfbbd7eb76c38e8733b6460cfa474dc5f72dfa1de2c5968806fc1ef33ba098c0a8783f8622e3149399b76c2056228acd49533ca826103296897f529ed9a8f91b3869a3650297cdeff243fc249a0da27eacaf3fc95b908eb2e3bc99f39b1453e868c1100df79be8c2f4ab2b9095efd0d6edd493aa264fac3f17a251540aa4b10b8024c2679d0c11ddea895e772386411f958c0a611092f169b28b07bc02b14b3ae753a29c82ae102d2e8cc25b066e3f4882b35914bb0bc6ad1a973e49bd235b731c89812f49bd8d7f0a47967ec60a829a37a2091da617039e07d1c91c27b557b424c4782cc340cef74e1dbb3cd8744eb862963f94d16a5a0f86c60ba462b11ed1a47ed8e66b60fa41b29ad28eb102dcc3ab94d6a36e520efd8ea757d520393969e897e1dd102d36097c79704a4a4d5f1fcd612e93a3674ef319d047693d1634eac8bb3f899526aa4173ed509ba2ad2d263f6116c567710e1ff671f66fdf8840413547bad17b9396d8c44ac82fb6c3bc1374bc5676f0739e2356be0e8d7e01e8f9d2183e63b8c099cea7c3b32e42f40d69d2db8ef529d9df59e9a7b7c1c7bfad782bc9ba70073f157358ba7e157358bba9f3acf3b17ae70317a561dd5367273d4deab001bb17bde94e2f84cbfb9034ed7ff7620eaec92d87b4142513882f9b53181a58c285d65d15efa543ce3f61e26806c888a25b8811c17929892d6a5f023071863fcc037b22c7f4b46d30f79b2782aea2690fdb19b6353de13563108d262d13f2e619163dd20b0dee12e745c7a24ffb10a42c6a0eec36d178aa641064eb0ccb583b0479dd1aa7d71f69fa438a6fed5ba045b9d124e79759d31191d9d20c4c377010ab1957cb23decd08d4886be7e3ace5b1328e816a738441f0e08c15e5e6b539bee3e3bf961363c8463331139d230b5a08929a5424f96e7b1e73174fc69f2344bb39b6b3eca96dae6dfdd8217e05f9d51070e1e1e93a7c980b09a9b8534dcc32085e1bdb6896c93b9c2ac599465f291e261844e14feda117abd0069ccd850b107bfa15cc93de7677053515e835ad37e1ccda5557229e7634af2ecec6d93dca5dad691dc64565f7fd10b808836f8b9828b2dc3a0d07959c5551d18de897be2899cae5d51e057735c11a5843548451135ade143c059e089754b3954d34e5d8de5547b42ec7a5c89a1f0a9ad150890be732a7d5fe384a2d96d839fd2cbcae4a921afe520e3f32cf1196fdc86a79fbf11f59170e3f32f76990671bbf507510f0e49956dc1a1aca92dbf0d55dbcd2049b4c5b360f69c7c1fa52161e7557703610bb61037f1e522c234bffc83952c6c49b0958e8bb105aad74bd8be558985ed80514cbafd9fd3514fa0a6747f8b28113de3658414a46a8d7f844ae26286e5360491623bc4f322c7375811b62d3abe2739c5eac4d6aef5f658bb3185f46af11c15f5a20bceabc4d2750aa32a097f0f25ff4fdfc6e0122009194af51e6a80bbe8b1126109188f2710d669e32a92d9cd4a26d22be30349564806bc22f5e746b5bbeb51756e0f27fff184df0f19d1253900ceb955d5be1b85ca5dbcab715b1b3271f3096b604aaf5d9f52a42b0b74a7260a2d64055cc2453cced984a5feec955c5e4de5fc42449b3b3ba9abbeabb1e022170cf27b54c631d9d492988e2fae0f62be6140507a80bcf43546fd4b20433cf7e4dcd2e59082b3cf7d7bf99a7251096f0bdecc905ed5890249258640e88566b226944c8d86248b700af883d3242415f274401ea8f37abab8f9256605b38a9491d07b214996b4cb7f80b8b355d29c6a4f15e12a8af322942e636ba1af88de58d416f750fb0fe0accb07f3278b08f837bae374c25089f8634b493756f65b22fd8fa45235aebceac1b6f6bd8383dc238f266053ed1e8c8c7e80c984d083257a883f5c230c2397126ff591363412039d1f0f11a03c0d83ae7edf8c05ee999442ac2de31a097ed90492d602be226a2e6e7260b56c6b1c608652eabeb858e67906a21f647278d2a21e81a83ac51ca3340dedb237c775b9a497cbfcb3464454684c237959bf8ec79414b51f01af26b123a72652bcd91f9eaddc6e08cbedf949c51f63ec14e8e384cbd8dfe3e8d82c57bcade8e57d061aee062d09131a2d569f9aeb8a8b20a3bc27edf9a6145bdef572930d7c9729b52257dd33305750dc22cc5c9fa7e66d269f62c36dc44f455518c5461d405d604ca8ef5865e18b44d3c54bbd6019c95206edb0d5f3d6cd1804776c292e77ed1e83d0a80b816219a71433d0561abbdc1c31c4436a38c7e1bd01801aca929682e265ed09297e2adea139a95ea5e2f2415a5dcdfe912fc5d1f554e02dd511a50c9594a14af4ac82cdb34ef75972495ede6e941eda4f23d058335a2b2a61ea229050295016daf8d03b382c7da5677ce0254025edeb7dd8ce00ae6ba4afb052aea4dd8c774ef1646b8050a7c5a037708e3a7ebe2544350684322fbddfee181c98f37cc42a997aae1666198c6fe2873d5459c7c289c759012601b7cc083387dbe2c73b38a8b725d18eec160f046e8d982e1b236585a7fd379f8f8606e579e6a3b967e8d9d1d9896442c6bdc9b94ec855cc01777b52791aae5fdd789d896bafb37d7efb0154a1db8c1e1ba0f4279115f071df06bb858fca5d572e862e92c2f9a31cc57b0ca0274f2ebe5e0f9e95ff0e1009161a9d00cc618cfeaf2a65813e2c7bd2c02f5d5fe81099ef8828473e40988b89133b2e857a8297b342581b03bd8d57527241398805eaed8941ab734657a6d774532c39641da2bfacaca766ad7eb9be53008ff3c9d7b1cdc6ad2adb7482f4f9b4975f9b39c42755643ec7867cf7541545168eefe78755623fd3eef9bac2f2d6d4cc87964842c444c0c305c3e3c64bc0affd9c3b77366ded9e609ecb7e37ce69e5d059b61b88b3d05c9e8c72ea84123547318fd7b19556775f90460d3cb157e991b86cb0d47bcd0a7bb70487ab38a0b14a7d311eb6ed3a5d10a2396ea6e3bff37a17c2bb0b37c23f221124cf58475201101ee6ea35db8249c1f4a2dbcdfa3678a5a7be97038e063e2696cdc67aa50866244e1faf36dbc40d1a9ba19822beaba5059d39ab4ed907fa3eeee7e90189ca743526471e0b3c0f85cf918e900308deee1dbb8a1d2322dcfc49ab5ae9c27f7d04ccd1d93012e82b4327216abe506a50ff0c98f52ce482b6b1b3c002cddb690c3983bddc34bb19e9edfdc4c6f7bfa5d3ccb011fbd6b1de258ae3e3265bf917c6758b6b469ee7fa5c0e2753c76398628f770aab314899b8069c179dd5c64922d8b447dd55206f2fcc8a0aa811dd8f93594058714ddf7e90f349937f6f7047b15259cdd1c1729fcb417ebd7918c16d6abd37d5be42b2e0ba9c6f834d731b4529c766fb26602c4aead445902bab5c1dafc1a2c513579ae7f2be3b82a81a1d69ba27a704d307948a5c0f2f6a4389fb3228d6eed41a9565965cd6964b6c8b3156814a9beb3c0be76652acde39a543c672540b15aeea93fa555fa2c9603aa2d80a7d70200d20eb177ad1ffe42f4a9ed5d4b7250dfa942578240968f7d1ae4ef092bd5d0d32e3460d04255f51afe72e5fa2d90d680a33ec2bca0a494a90bcea831f507cba763b3efde29af16e812f667031d3fc18d943b563ccb04654f9cfdfe3576d6fa051d05bc987ed5aa606e169dbd9c4052b1c6bc49e4b6925d78d1ec1c8aa04f1e0de5efe2f7787b884c12ca48166d7597e53cba9aea2f58ed0dd43ae3f7747f2dac7b6bbbd30b083573a88c1c169f38ef6586eaf59366e2b018f09930229892eca8a15101d2b762f870151f30307e625293de9a0ef92b0029e422d30221c6325097b8f04d71e444a13d510c4731e4a836ebc3e3e4cfeb8148499a7fa076ded5e638bb9c7c7f0b2dec316dc1423a7cb1e1142e4f57e701a8b3562595421513496d432c344754c97ff28b8320dfa8e4e71519b8a32b99fa545d728c2bd106e609cebd351184547953802acb7d0989cb4b108082b3507eac1f347da7234b54c9d27785951a252ae8c17af98899cfc88d7afec06bc73fbd0939b2ffe528cd372bb76993d4523e4bdcd195727808ebb435c77fd696ff46a23049880f483bcabf117f4d6a2d3c3ffdf7c92d505ddda1aaaa9f9ffeafc03830c14051b1b9435d9ae93ed1dd443a82c56336a7e9824b1e8190655511f85f3e1c0ef8302457e695df6c993f36b97d0ad68918fcfd2f1342684a6aabd1b366333ed4131a27b6ec43130896cbb4e3ab07a5b2582388fb9ab0b23635141e48c2a6d43ccab8960cd44ff860691f4529657da3b2ef2a299efd399adc840f8ddf466886567b4e50c62c435c29f2a298c08d7ab9acb217e57547c11cf2832a1eee183ee79f15299a50faea3fe4ba0e391f3c953c25c63e04a3b3cb7a6c4d30b75d092ff1b58c487d7cc7020b2f59d37b0100d291b39aebc30156e32fa85121b0abc74d86dcff8a2946455d302a53a8b05c9c33d38bf295ecb6c99feaab48b36e79a20465202323a2147028b8ec388b2472398768349b2e870d0ee987154559686e4358178f264637ff4736ee45d850816079d91765e03fda781d3c6a050d88564b0cfc8f3ce91385b6ecbc4ba805d5726c187ae37ef294bbd20a559f34bded076f113fdae72c014d0f649e572c479f99735337fb46db9480810a9f93378e286b0ed8bca2c55bba579f4493a427f55d94908b223205db6cef6e82b7f0cc42f3dc7bd1716bc8f43c760345fb92a64e8b5cb472cf40ecabb23f4ee2ea1159d7a1762182d274e81be760afd5b400600c538a92aa6d3f3c6a2fb170f4782f5a908d739cbb7a00dcbb5badcf03294a22c7653ca4ec13b45e82aab0629979d32de15153be0ebae14b57d072c4a9366b5938984d6b92b698faa7dc95082f48c70fb91c9f725872feb8648272a614e619f489cb2e71f42d8c09c533294bf55b80366cf4b712449e146850fe4dd4c04e7a2073e6d4e3f92157bcd0c5237504fb525f7ba2ad5309259122fa8310525fc9f3dbbddd5b636559a9e2fb4018d2cef6f8ff0340fef7e7fabe7eef619b66484803d43f2caf5afa16dd12358e3903099b20eaf3ff7f6ac99385a1209d81007aef7b1f589681a79c13cfa6cd2e4a6fef3f7dc9b2ad990e665b49afb4554a026020b03c699ea40394131440e28f61faff3e9b2ecb1a8288080fa4f5182a60f9d2276a45216ba626f3fe13cf800f1ae2446faa114b71a04cafdd9a601a38cc427d727b01c090a7bca44d6eda1cfa87041c95560d2b2344bf08c67956461d3344f895cc12faac607b08dfac183732bcd7431e81cb7f5a9b2277d342e97ef044e284d36b28128a7010f4899e1ed8d9f4bd0aae4dfbfe844aaaaa411522fe7569ec0c9a16f47752508ed18fa41444607df72f556aace0f5848d728c7e4fa6fa51ddc9367b5b4e28266f591f583f96ef452a5d2f205391f641c2d48df2a9ede46513e2c935cb5016240cf716278699a658b017b58f56d8910f87af012df139cebb23f3902cc050fcd667b92b1c9e3a3edcb7e584ffdd4968582f395ed18703aeab72048db535898ebbb4e6dc3ecdbc531b4f73738606359ae273d2b4c51814d67107e064d22f2065daef23525fdb8675272edb65aed2cb853359561566d58c37ebbc313826d342e976733c18e6640ae1800a32bdd442657f196a9444dd969350f16ce74fef61415da6974b4a655280a49e2698dc41ef946e454f9068f138a365e9e36af0b0cfaf473c3231cfdd6c27335ce70750771ff3c2c1574ac1e3282c6f63643b2393c976c4cb0dc6c20ac9c39ccd1d2d2817ac47fa2793c78ccd0484ecfa2d9d0db1a17aedc631a81caa9823686a67761e0258494926399281f85d57fa5e9fdbc23983f64f952ef14dba55f86e4d83294b74ab1ce5d89d102cc1174ef605decdbf6e3165c9645fe02c98eb66db0c71eea4f64cf605573051b003d759e4b9a0c2dd363b75ec87dc7dd3e5c4c3cebf7cc708bd64daced20b7ea6a2440acddb2e24da1c537aa5697e47a7db927755c551724c0d46f11947798cb81c10f98be71b482e86449b8d2caedd6ba44b1d1a6e69052871ac5aef2a8b01ff02dde9d60e4cb0103b245e9c1c1c53077e69b81200d711742a7ccc31ba96aa75fe18351169a128444f4c9b6d6176bfa587f22808537292a1cb4ec9763b1888f47ae3a66c4f034964fe3a3493e4a4f13ced1ab632ec2fae58674ce8af3389f75de418289e93609c95e5b891349b5c282f70c8387417b68c89c805b8c805d6f205dbea08b52c4ca32ec9465928be6aed083f947befb26cb945b3a21f985673e5b3bd1cb1345180e9de8fc027ef2a6f1062bfbbfa8d4b3679848531133c0b3f113c8b3f100d29932001626aa199ac942f28553007df8fcd5f9b880def088dd6de6689131e4458111820b0f0dfcd4eb08d74058e6ab43e44312a2c018b44451d9d3214cc4ffffc911fb5fee1693f3dc118c191275126c91178bc5c9871c68109ac6090f0f4b2371be093819ca2a6936a7200186c4d912079e68f164e1488b84c500225aa920425d09e493c1674bb51e4d45fe4bd6a5ccf131815cbd68353620e01869d440a139505bb050605404e0c4afdb47740d50d6816592b626a8488a860a2ec004025b6961a561de1a66682b4a32567dedc44428e293aebdaa0b833ac73916178e6095677f7f2f909333ed76599b3d2c5e4eef6753e84cee66edff3eb962cedb1542baff80d9b17b0aa41b360124b98b2cd61c3ecad0b27c4c0415b7961297530c79b314a622bebe273ad351f0241815aac8e31e48131aab6d3f82889748402f09bddbaaaa4a9a7b2b80bd31287b9b91d183679c8967e0ba94e7df6d295e61c29000635302652f69ab048686e55ef1ad7371707d2dfdf46a90d14ef5edb00b19bdf19940a78197824c8475b377b121f3595d30d2d459d22dad19e84359788b3a55dc6412b24149edcb34af984e32ea7f13af424f5b39ee9c85cc3d3e2f8ac4f32f991a0b8f23f00a22ff294bb235a5dd3629db51fa27eaba21de4a93dbe8256f2d5b01ae5047689d3a559595f8269084369a27c256ad7a5de3285c05c20a51983037db0bd6980aa6c276a2c55283661c164f7423a6a3df0f0023fcbc0753755edcfdbd1067d63f798a9475c31361973b4786fdc4c36fb52707fbcf91e5bbe980fafbf258ed14a6b76c04634ec55e606cb568d524aeb52a085ec0c2ad28041dac696a5fe77772ae7eab1c838a245ad00b5927c231d0b0770290c324963002452e0477501603908903edf17632f065aa295ed4d45a0921dcc476e19a9204fac328a2f38e6dedb84c8c83fe2165f2afe15c96c319e4cff1d15eb31a962cef34ebfb671531b3115bbce6544a2d2e393223b3ad3041dda6d5cacfa1bcf1869d4e9920420e5ba2fa69618fec0800afe3b32c1e8476d55a6e5b5e32f23527154ea6c137a93592702ae60cc843b3c4235715224658194168db520f797e205fd07aa4afd7036b1ae5538ceec35b53559d229b6bacf00e6ae55f16117789bfb02428a5c2c4b026eeebc631739ca5c79b5740f5ce535b5ca636cc8ae38484bee01dabc56b30e39dcb77119689695b238c526b4302dc41296ce7a0d5a32326e9badf89c3c11b38b76703bc25b872b37b49b2fa1c82b5867b5b88a494cdf98cdfc4ced7fdbf852307b32e4150e248ddcaaf0062ac52cf6feae4db2a7b0090f047705416952d27b711498f0b1aea6c56d1009a31800084ddda2a02566037d6b1c1ad81a516005d0cd54dc6905c9517b9b972fffdcb52a9285a54d22de948ff7ca49ba4ea685abd32399224a3f7eca38f51aaed24d59b1989215af091a5105001a56e5578c374df93a816793203af1c2e6d49b8168d5b22bd0e30fb6b1e1d5ce827b001f403f069493cc834a5a74568ba2a0cd6043bd213e0c1f82700597c9f81f884ad17c1639b8be331a53133e6346baee0c751fdf24bc3faec99a5e1ca98d53ebbfb59802850470a398fb3779554afc3931fba17e4dc6097a09b2930cf6dd1998516c98b075d2f021d18086e2c741205fcdaad37f7deb0f8d961f2665ba72d1f55636160b38e272603a1f605900be04e866130dc550e303c099681ff5b8e0331dbd5e758a6a4efc9ce8146392e2eeb1d1385f87fe8cf8636a03835b3e745bc64ef9e1b1039783c777b6fad9ec5745976d38de453bcf5fefd3d917dbc91fc6badcc3e7b838453f9d63ffd9474ddc2a006c42f647d923028cc6f6b742d6d155ec0c9cb7e492bee898024063c217d84a7b2c42f3c57682d020a938c2b364c661ab207a608cb67d139c45d957f01a49d98b2be54aec2f36ce6888d3b02cec0d013522d10b08f18ca1c1ca6f6e75609ff8e708de120903bb5f37cf5399ca807cbcbb87d66ed7f6bd48975b408149089219d9b3b9f8ea9e577ceec54884aa2788c82319484d4fa139917bbb506efe09c31226c7e801f0f9822f6d7822ec5733eb73536b112cac759e08a10798a07f1623809067fe28ec9b1c90fe5fc29b62cbdc8bd020f6e541a55e45e813a430187538fa58063acf6a6eba82d5efd32f5f139649deaa54bca75904fa6072b49c00426b7dbe7bf4c90c02692f3075ae0efb800a8f19857539bbb754fe90ebbaf5e9c58334016d2197da88e108b5bab990cac9c3e7f28e7959160a49ff5504018436414b0d26cd2daf0cddd1facae15174f64c8a4c205257e49d4868b698358045526cea6a3e571151c52e0f927923a601ba8472569eda97d44ca6328386657641b780a84afd1ee4682501848cdb62e51b84095d6bd30780b3fbc28dd64dd0b5c2002e9cee7880af7ae72a934e914d93456317d1c1d9ca6b558d0ee23d9197c6d111c8ac56907ec6de2c3726681bb589d19cc1ae53242b64b363722676160c79547d89cbcb545c597e687b499937e187fb90bdd748ec76f94bf0fcd5ec9e9cab59a9e35bd81b53d6ba8bb9c848343cc0eef6acb2c22c4d6f81c6273a3464fa52342d0618487b743a039666b6929a7eaf9b7396a5e9a5675c719d11bfaa3064904a5afa74d242faa1a085093b68424ea8f9cd9bea7c66d62f120ace65c4a6c9213b302a5db34af5390aba23d3fb14ddb1b9f0def16dc0498a73fe4ddd9c3e51ce873fc49fdced21f77ce77573ce68468baddfdb9072c60a07e4aee5b777b5d55ecfd691b4c5f30fcd884658f93971bf67191aeb80500d672f9f12639807a9a3963f8029cd1e079d8dfdabdc0518cfd392a9406dad87a758878b9cdc6d08b30b7123be90bee07b5d4a2f68f488c76ff52ab28b7a8cd12914073429944a216cb299254ef473ce1a7ec5242d142a21a6cc35c0df446b422a8310f30112dbd65243a129b0a3ae181b9023ce7e1d9c7abce6e612da078e578fe5adc7c81d232efb51c7c855d61c23d87888bc8d41795613f51707cc347ac268b366425d128bbd5b1a8dc9e6c857c01868e9cdc0b7ca034f96e3d6e5164b08d8a0f7b749a2e891c3581134db4f9c23b8df3cb2899985d14c03652fa8b642455efd0826dc3b397991471ef206103aa2792c9dde8f1badb3198455b914a7f60d4d2fe9a789666d2f9ea2ad82714195ea46cc475cb33c5563f8bdbe045469359c50e8e0ec7ab0bae529d1872ad4779aba36a6d974b8d117b6d84e6f64d0114b67cc8c738af23766fae129612e997a87faa6c8e8be64a3885cbf00ebe7bdac0897bc6df1518461669ce2b8c32da32907d4343f93129177fb496a9790dee07bf7f90e4bf3dcc9f89eb2fa26f699ee76e1b293879e17949dc626a6950e95d7e1efbafb7b9192d07c9fef87b9a47977629524c43046cad2238c233d511f1462749bd859802143b4dbb443a3871f1512acd61978139f26d73da24f731df174fb8da1cfe5a98690a2d2c403d6d42b7b4df3ebdeeb09b2c007e1b1f7b2094e71c2f4c6e8b5d648b68be17c5c848e0f9993e0440c2e0e4748694b1904d5b0d23a1815320461207478f42084a94c1789633d56b95aa99c4704914e5c1619404b85c620fe648e6d2f71a2461e36c5692bb2ae64b890b2067df7e26141ea778528c7eb8265b450b5aaff19ec9bd4f470dafc30dcd0a36fbd8685bbc4c5eaf225317c53ad8a6114c3e8eded5f3a9b1735fb3c17860aadd63181122aaca144e25753e917a9a748f540412b18072ed64af94102092c60252a78bdc3007894025a38295f1c07ceb65094dfc27839e2489dadd2f99a09b1ce5cc82db014d166450c1759a53ae9391b980084d2c19e3d9c7c1a0cc80888bad0ac6163d5b9b3503478bdbb7bc5ea016dc0735272847f1b7466eba9f5eba08483365bedb27c64f23bb98aeeac379ab8327ca77b2e21179ea26eaba9cb168c5a7a9751de707d47f3b12f3820340a1d4d55d099a9d59597c3d806aaf39f2294f25edc86fb44e263ac3e093cd9d555e08cd88f2b28fd963743b07e9e65dcfe93ddf208980036cf623db8a0cbc3f3b9fb40a7378ed7b2d1ab2f96811eb5b6f76803bc21a6246949aa39958c0c9b9b96eb328fe0f49f1cd325f3309daed55a3fc3fce82800a6d5a4b278b6f493721ed7487dedeb16abb33966813571abbd2d25799437b735be37df3ed795834d0a4aa6fe0d082633298dbfdb8d38960d6059a2bf6593abedbee2fa875a014558dfb047b850698d9580a8359d8c89616a2eb2732a685cd2a434267ee038d6b3378d3b9b911fa7927afd582a08eba79c77ef44e20a11cbd49d034442b7aab36974ed053daa52eff65ee1b61aed4df3c52954b9b4ed0ee7fc047666ffa45c3a9a05dd4c691749159195d2cb68790128edaf3a9b4c6c694b9cd46d59d5d9470dd9db9a806da1c8ed2e05e8fba9bd9484b9c15e8089ac272bee7464f5e4bce9730cd47854b6d680071bad2a4e7e39c0b262eb42b1f377c24e3e6bf5d0b69b334eee77ffe49733919395e058de888979f43e0e3392fad2e10465eb4a28fb0855b7859958f50684e2ff08edca3e42dcb3fc176bc56c80100948fb04055448038fb9da69b5a8b1c5d551a12a61f74168e42e3a01c1ab01215207fe28672076dbd0f6dcf88bfafde2e95e3578f52afe65941a6ac0b04db4d6a4bea44600270a7af471a3b6e7d0eec73b53b12839b95e1bfaa2b8c51c9b8d0d6e9ce2f1d5ff2d60d16cc441a969f20d0f78ce6eb0518945d929926d0ca1afde279ef31229e1ec77fc4b8a192c5fb92dfc7f45b4752ac9ea0ffde8a930a4a92ed21f0029852dee9f9f155f95b66e8c375455b679eb4ef5f89de495b9963a09ce9fb5d7beac70ef59c0cc8ff3c5d76ba993cded2f9bcecec6a72bcb0b91b9c925e0375e2fc0684a5d1db45b72844a70e0e8b8eb25b445d904d51ce403c7da0f9aba07f6ca7e00cb92f8102a014bc26dfd1267e1f0bbf9a1fc653ac37cefea7f4f3bde4f1e37385256983f67f4436419c39ab30ba411dc590260f4207daab785db9ab6f52663a1947f97a3c5b037add1e68a19c6556dbda95f0c44f33508b54a021c2d23e4768834ca2a786075b8c37c325423e061cf72fb853ed742e59e8cea9e415cbef0b28b37c336f18b48d1bc31b7e113dbc62fa935e7bb05cabf91b4b43027d2de70e34c4f689649c84a92a035340a998db4d6f5b5290e89abc1270af2727cd993e981f436a46c4ca740fa6718fb9e285dff1a235eeda70a0da2fdd2309bd8826fd3dd86d2d556570e4bc36d520b3abb2d0ecdcf19e256ce74d6dbdd5da1dcfb028c0a5993adbddd9d2e425b6673b68da601bbf76021f84180c6294bdfdfda9d8d55b6d1c5ee7eabbab4da9ec7aa6d4d540e04ccfde6508a0d7f1b825f37ab90273793f6895a72e9948397c6c25f4f293500f8ff0340ee4d977fba4ed2794f12928c69392d9be66caf833d80828a23c9f0f9edfed72afdbd681156644464225cd17b6918313b87b31b8623aaaaff7f4fcf6c1f300b7bda04b4e8ee0352a7e312e162435cf1ff54bf6cbbda082130d83d60f49d7ac0ae46e6214fbcad5ef2159a75b7c1e1fc94d4da236fd87ed03a6cd011875cd92cb4e5e14624d7bae79fb7731672382234fbe71578bdb47718c91484a70e8a2fe66a6b632d248520124dad8a0fe38261d851be5b5e253a1b2ef9b258357ebd20deaf87772dabac21c70187641a9235b0d8127aa7b2eb35315b2979e02e9daacdc736a6660cbb34a547aa45beaa7236781ee4a7fb8585dd2185e1cf36daa90ba48c01ed5a66f58b7bfe4d81a29ed164285301af10cb80f4dd23e3a834e221424e4e8dd106562b4f2070357290e750ea95957bc42c65b763c00086f18d06190da7307599981eed7ae52ac6116ef3052f65db82afe4d15d4a1f9222ef12b1c971296d6e6bc542ee9a7d97b8c5ade3b50001083fd7b0734dc0cb02e6369e570c7758ad02a6187cd707064af27866c792c3f3dca6b61dadece30a1ad58eed31abf6b7498f58db3448a551a2c8b8b12bf6d87a2ca3460d9392de5960f4f220c9b7eb50bce8a8d4bf4ed534410334a34f9644ea91c8e0e93f1093c46cb9216617ac4b9931c26a1a536c1d71bd108a1519a532aa76c92b2e7efca6ee6f94a26a76c71aabae3403635b8f4100568492110f7cab3b48f28525523e4a644e30d9496a4c4cb954587e0e991900c46820778dd1a35778c97fbae6d132af36794f7e95dd41766c9180bd451e3e2dbae73dc6d3e7fe7cea757998a3e1e15a53d87b63cb890d291f316ff57a64f017c37f1d6627483988e6d7d9d1b98e019b8188a57bd093b22c35bb5671b963b78e8caec47a65e0c489c73b602a7c591b43226fe490be62bad2e8143398a3ffb0b214859c15624777690be4d449183c5d9c93b64bc7afc543dba5dea048ef5d73381c78631d2f91ee3ed266e438291dea30dc1987023cf77b2298e24c917939b4fe268139fedf5f493df826c41c60188ccc1758965f92256ad5e5fdcd14b79d330e4d839468b563da50bc38b23cbcfd59365268e4dbea964ba7f0e31208c023896a2ffc43b1f108401b016f851dd748ce5cd2e480170113dc3743787cfbf3eac7374de3aba06bc94e7f245186ad49f4f81674179bc7b29912706143db264ba6f216d9d65b8a046d17977e1b4b8c6e62f190045f3feed535b56b1efbb84aeacbe1e9fc201c65a419c1b3cb8a84be45ede5cf877eb33041bd713df767c79cded081254e175c5a6c0739314a51ba9f51a3460ec73aa6edf944bb13fa4bfa0ff2bc42cf4fda2e4d9f10ec00df840e073ac95113839a95a53393138ff98e28ad2ec5a4f8b597213480195d7ab63f211b4fe1a26cb4ceebffc1e4434ed8981449441e88b994713a42cd69e1baaa281f58f03ba8467ecedfb0d5528d8b4580cd06b19958c08c208fc653d84bc8b13c65fa0252d0e906b48df01b93e88bd77fe713749729d477111c821ad7117892a8861be4c42a642173c81c59a4041a205969f994a80f76d633d5ebab36525e2000ef5d80b71f88ac0497306401323a4280ebe1eae73a9ab9299416b04d3e8f2097f1fe6b50fefba3df9da7dbe0b6eba00d9e1e738e82b39f041f56d1b281324dd0acbd6270f96aa8391dd7747ff86c04891e6060ebc24fbc636bb3da14d780a7b237b085bbb4b62d21349a41425c466aeff4143d50d0f61f7c7c87dab7942d6cbc27d76e3fdea399ee07529cc2e693ce20a884b4049272ee5a7a528cf512831c52955896d8b843382d353487c6f9c912a8598c088de32e47340e6c768621886883d434d703c454e890dbaad55fa479b1b77242a3a72a242ab5880cd615113155719525d3bf1e2081fa18b966b9dfde1463b4931d35d14e2844f00e9ba27ceb9daea5274a17c3257314d2c31729bcefe4e02c4848a71febbf1feb30f9aa12e647191589e686f96e3ea3673d0723cd0559181fb1c14ba5486d10c4752af16da3cb95d2cae7a80c4c8af4a9aacc8495cd594bff15c303d6a8e76a39b808ca0a7eb18aa21f1a8838f931a9ec018da48e8256709e3e88b5133b3f4a570b36116ffff8ed1d93a3f68ee161fcbb32daaf4483dd76d824b610a92d83857cf4265c7396c8424eaa0eedde2cd15d4c33d7d4c65df87b02baa8d9c9a00335dc8089c14c61dee8a8250328702cf1f39c2b39f396e4d48e977e8d96e282eaac79b2c0e139a8fce82b398b1f2ed862740ec0539cb4a95466a237a3ba02fc8b304f3de0b517dee2ad72034115a2a71a8f644eedc848d8d447a627b2188e6b60899fff57b3337928926e1895088e82fdc16191512093c4499f854f569836d092dc9400eb13714acec05242da8d41c522428dbf6a6672247bf3f805c186ce4829706c1fa023b365bf8c87efc4c85ac09b8ceca0a2217cf60589003ed85b8f6963571f1ea4fcacfa4ca268da16e69622f2ac4fae8fa08f9ac986deb57f5d9c1c0b3802a03a6fac010f0fe9400dacabc42461a3dc00d6d0b2d016b55112601e0c5c4235930803749f5ac1fd45025d0533f9d3ab377518bf684a681535ecb319b0b7b4c6bcde1f651a190a32063ae3624790efa08302179b2cd313696736eab3cdf6e36426e05d8c1c73c63f5456a85f4492b91260ce79ad52bfce6795b35caed084bf78ec422c509fe7d25562a9f4a4741a7fa8db895e2b011b22dda29f567b6b69ed36d9bc67865c9fda55b5a4977aac47f7c444972876c58eccb012708c12b3573ff557dc51250a2e525dd9a2496e9a22ca507ee2bd624de2ef1973f5c2dd9993da78af1606f6dce1fce77756c666d749bfb77f23d9e79d6b3c29e5020de675e17e7d4a675ccca46daab5165737f59c35268407c2cb84279d6519013649e88092b925cdc50a0d67b5fe489ac182a0ce79c8b35b0d79236ce8c8cea632c9b11e5f18c420e642dbcc5582526fb722db2e3aebf111f2263ec64586fb43b498094efb21286c510ea21cede296b576d34ba7b6b1153078826da9c0e459197f67e768dabbf01014d83b53ba1b94aa047d214cf4eeb5917f84fb3c7046a0254b066858f1ad31b38506f79e2872f89cf1b9457358f0fdff7a63bce0ad59ce1e54c7ec3685ff7e5528e0d4349fc71acac174c13b1071e0d6d3f96ef329c1c3a9b9bed6698d40d31b241a4b9abf9863bdd6e3dd8c85159395fb0c36b14d41c426a530e70633e01277abac5b93cfe02969ec558ba78a2c024c7656dbce683859a0dcaa2f5a8bbb61e727a7064aa79341de81032abf8c31c45a161ee510071348a1b6310393abe759e7568f2d2201b9f0db14ab2644ccecf6a7e60d5cc61d238030c0b0131688500467aed7a905817713b638b26b205727e395a3aab5d7b66814174f21efe07693d4eb5a5f0593bac29d33557badeb0712489b544d8aa6514b694437a918ba0c162526a3c60d2648edbb85389a927080aabc5f1f3610ca374ad2a5e806a014867dc4489fd57eff9e3b35f1672c1e5a43f8e5f89e3ef7df8fa5a627d3890fc3462fc2d26d75bc20cd56c1e0d386cf5088fa1e625ee331186b9397b1bdf0b00c54caa4fb8bd91f309aa86248383204f22d391e370a0d1b7b3508a26bcfc141104e304f533b5886cddcb7c8eb891d2da05b637e55783448ccaa659c6c84dc0d5c1d0c702149621c06df86b6a08b02f90188cb2fb39baeead6980772e60d088dd35318046943b8258d3e7a85293d8472d75aa04592d98020b5dac3be35f5dab537885a496c697071a8ab190643c019c724fcf1fad3dc86a5b0178f3c1c3b5225dce0fb8ce7dc24eec396e3c73cccda9dbe5b8895e37c9748dbaccc8108288803c819b37761d9a7842364784986d31cb180ab9c0818a1796457888636fdafa14911531e9c2ba4b548ade5bb454024953750ad07d8ec6c7e70057ea41436f08d4b598e0bae203c67dcca498ba47eb46b0a15b1ab9e9653023326ec87626050a239e86043fe010e645b8ac6baa36701ee7620677014beb5a1c71a9603929158f97e7d03298a995b4a9158d44898fb9fa51f87a9672b082a3dc97d863572dd5593ac7e9818685f8843d89a21a07da3109ce5202585a705018d0fbf1fd921428d87d4bc03e7f910854c881233890b730c293daba1dfc1da64a5730ec9370b72953065ff9410520667f943d798c016383226a284168b689af695597a3420ab7a9f00bca019dbde3bef1e8c07212f014c868ea306765abe7719a564ef28ffad7e7ec01933be51368c88b8ed8070efa836ca1e16f06c02abda306a2c90ee0145703a8ac17f072a144a638a2944556c9c5536d59f51fc15ec5e55c7d948c4e0a20683787d946de452bfda86d85448b1a37e039e15cab6042f9a828e0f894f2fe8fd505f2e0beafc8b6110ae160eda4a8b19a65c3f67bdbfbef5e6f403f0553f09491c07f2f49f609eb755bf09fd463ae6622ebf873ce02b876bdaa8739b600de6557fe9641d3af68ef7eda36d8d6fd0527f79cc565c6939ef31900e44d94603394b0941958480a587e0958a4f246ad976fe8aa4ff20668e6c27ba67041ff79fc242be55263f3d77af52632d86879ea3e6967164f1ec0e1802016890f65696a6cb72790cd46c71680894a42f3e9f9ff6063abdbf521e1366ce7fe6b278db94d85142b85d51549ed05aee41d03c8a710a2d77edf0e844fcef07a4216871e7d423ad7728dab3e0eea7821be9a98bca65ca59011254d3388bed90127d648c9a4a34e46a403f9a50144ead5ff9e8d1a2cf749753ac92b174e5b66e678893ba49aebd9969b641629a2af3c0263081b00a59d8d984b803f663cf2528f96bd18ba07c1c2c67c5164f991abcef0958bd67df046c1cd50a3d7f6a6c085d947fa5bd174909dacdaa0c11cfade44ae315041164abb67cd9a5fc333c5123cf12cead4881c023e79ab0acd7e6853d8bdc8c0eadbe269671bc1e070f6141c167fd54d410be5f4fef0cc11cdc560e81974c4bf23d70b4f4266afae67a1b39dda21b83cf8a9af396b6e48f8436e1bdcbe0d54c6e437c2e48277cf61aab6c8054501971103bbdb4fd20090c5e2196d09f35576a6ecad824a6143f2a35e3d76749ec9416949a214bd985d514439f0dfa2a1f203610111ba9841050764d13a27b94268476c56b78d67584445d368994a65a659441c4c2c88174ae93637131807caf705eafc6601e4d23ae68fdbc2258621bb42ae9224de3aace2717906f12eb97080e09a52cf194338c2ce3bb26e65b3495952c7bb03d7bae5194e180b7faf8bc0a4cba1b20bb9c5ee50455fdae5cbf43af9bb34312de0b7952bacf57f18829bcc4085e3c87ce41e9f0d10cc10e7a087c9f323e1a8140511f097b1570082527beac6b4105e0ff6d1e3c83bd8a3731d20faeb478ec421961d0332b3aaeffa32fd7d5457572dc7fb5564016b43dbd69bf498aac8d3e933b3be11d1e15f7411de97e1e67d0ef885ca7388359f0ff8ea18ac1edfe738e2683f164aad2fdf14dd8bc4acfc3644a96b2fa72a826b2db7aaf26f2fd984865f58f3e8d8c180798ae68e7c56022697c75d7b7d96d8ae89c4ba8420915b80bea75647602c36869856b59fa132afefb933adf62446bc9867ecdedd21ab35fa6b00afa6aa6d7d11883f61efc3c692f1bb42986664bb8715cab75818e048bad842b83dfd0e9f4abbbcca4a48f77e695fc6aa13a2b145c606df6c41727a06dcfc8bb8a980c19d73be827b4b7bd4af6b2f596ad7c3167996b28a9a1cb2d4b200843575a13690461a6bfb63f7e18d839c56ddb8cf6acf1c7c200f8ff03402e9bdaebbb77dd135696a0e7e738a59513b0018d85c4216107bf9af609d0dd51ec0cb8117d1d80c23ac5d0d333a3d5ea528cd475c56d63644824fde0949009b78dfe37feafaff2cb3eea16b13080ff43e05c64513c4fe2dd3ab2a64baba5a4fadf6171d78a25e2b6840ec8e9a36a1da668133e10bc3005eb7c5d6a11d48adb8dff0212d024a01a51c730d35120a02e442714208830ea509456ed9c0ac664d54734bf7319a80ca935216783d68823838cdd4397af3301345b568d2ae5eff516951dccfd72ba211561a7c8efd3b17e4030e29c49b676a9fa7f72c5c28885a873a4163532045a5fa3aebfe6e2485c45b9b8e52804df2a61243b1f1e5221e8cc4081884050dfe12ee72d1c91c95056dbec707b91b198d7cc71e9f872a45256cf888833a798ab34d40ff4b40b58b8d8f68f2bfd3f514bd6af10ee7970ee4fb202d5e064214eb74f990f985ea353730b672c5b79ea1f5771a8a638dd2ec63cd0e95f08d38ce367e85052821b59044753f1b07ab6fe4e726cb795d2a565f763bde9c216f7e8bb782a96aa7ef317a0e8cdfaa4c77808bbcec944af91a99bb655760b99904d2e91e73b9cf619e1cf1537161ca4847fc49866e01970b0f2f92fbefaafeda65162e98a7b4de28a4bb1de60a572cdc436fb46e73e261c0c6e803cd5c5a0152d945dfd12645a2546d78c83cc13dd656038aae25026de32c264b293445ea0f8ddc06d22be36b2357ab8097f4d677bbc2876041f140627a2ef610e868c89248eb7c329642cd49921c3ece15d5497ad2008ebcd403d168b0f3dd20f747282928afffc737a82417ac2cf48121e9f43d31f3a0c0c4e9a1a1ac91a3ded77ed582cd0408999e4ecadc71d85d3a24d077b13196718e9b6689302bd91a64168ac3d814b690b90fe1bbd18ace53428f1b493ecfba9d156646177c331e97d2b6d7426b34068cc31379ebc98fdfbc525a32445b9e6d2cb2e9fdfc13046b34064b0e8168d9746bee72727122645980a5d51a8dec07e5ea0fcc69a0158eaf980b712b13cb3411274d313e0e43b9082a62bdd7a25f5d29c2caaf77bfb99996c8354577eb143ebf3fa36ce4b3fbab9c8a3284bf2304f449abb74eb8dd24f03bf464315ab1cd49ef8c88ac1ff4c1c27eb9134d2fd4552a795d214097f117295af74d034412e311f6b17569703429ee36fe1a0c0fff741f87b757735e289b8c86c84773ec8fedd42d2bfcba0e83279c1dec5d0355c2860d8c815dea5d87142715d9f165489663206cc28f502f7158c489ee89d4d8c77911a3a69e214d0d9263ace0e55ca3c78ac51b8c5e4293323af020ec3d8c14c58c4a5899b0f538a68e0775d745ebe5eb5d234a46df32adfbc21ef70a0cf815c4be27d19041a8250664e8e094ce27e0003f12a2d6314d1234060c4e0c67e69f61232312f894cb5b53b4cbd1e5d93b79ab67e0dee3ca7e15bc1ad5f51ecf6dcfcc141d1fbf594853e5a71503843726968eb30f915271414f4dcaca3ed8630b0d9e7caeefd49e4515e5a11f55a4d24ba142d8030b9f2c5ce346fd76c0d7b1bb89cc592b94f9be5b066aeb5d6c62534216080228948e1d1d49c3fdd49bc3fb58764bb71cecdabe13b2be1665c4d4d73c7149e9dbd7b2ad88409db1a9c35e49d325b8f79ad4a16aa8b5e9e432324607268f1f7c81e77b82c2bbc58de7f7d54a4ea777981b224f348ff38619168b43fa174f2d14b55c2f92b32769167d56ac10ba787ef61e7be484daf3e70224dc3275e454c1348c9502c36bf41a13174538399e29d256e55dccef016a282cbaf64d5ddcb35ab537356707556b7dc6555c850efd267f4147f1b173f7855ad91c1b9f9f8baeb70017f4380faab60eb7e3228c27ca5084aaf7c8b4b7b3de5796857f0c13e8f114bc00326150a4923f5f58ac2f101b98d56c7e614462bc00f1a4ccb26515fc562f5cad787b856184d333c15a3ab15c3471a9a54e414853afa05f516d05e8a1415a14407680569486fdc4d16605fb15b06e31d5c4ae5845aa51bb2981592524b0c4e47f8958383209cf1b1a62308cb103aa2d23a21a625288ea7d0763c50931782a8c393609b2a5a5b300ebda216276b3fdf46a996e19505ccc356b22e8488763d11be5d68d8a3be37976e0a60be6bfede2761508dcde21bbbee293640633facd2d63466ad10a359becb6b1c70be965f116504894378dd40ce26ce2df35553656b1f31bc9c45b6436c2092f73b94d26b425fb56490663dac55decfe0a1250365e5d87655d76939673101011b6080574a2b90e00f47cded80aa4e29b7299ee0e1917019291abb5a27c17b82dfd5afbbd66eaa79133f6a623e4c5dfe2574eee543018df6304ae4bc5a6940447b0c8c436794b453fd4ef6add23795b4d9ec5090e9cde98ba86be9c51ad180ec679595a37cc164c36717a6898a9b222a647f7dbc2b9a394f0c95aec3a450c17503a164e4830a5d72850175adfd865111b1f6ead5db2a8bd8ba550a94d0ea1040ca0a6d88033da37ab9a156c8dd131e80378d1d1d1e850743e4c0bb0a6625d6bd9d6d1ba8ee338af9e18ea5bda85a753661c6bac217a6c51ef112faa956e2b54144a95674fdc2a7c5464e2194484f5839841b5c0f559d59a465b14a87c1410cd50fe55157608d3f363ed29710376250f2a7f62a47d2db439bdd2a0246916101f29ba74ecf1cf9ffa9d151c8d53453a800f09fefdf2debdf40364b53f4c6f9662ac2d2a6669cd8fa56610d2e5c62a66c650025e7180957f19beac11076d2725ec66065648d8132998a98ae18e11b3741dcb8ed170638914f77cc30b66f5f4d0476ef62f6e5eeac13a8975c921a3b14d9a7abe0620c7a05e969476d7ad2843a8a081f534247b5cafcb243d89272231a7423bb21e6c9af3b18f3e4d71d8c79f2eb7ab394977b751f9ea4f118d34e01470c4f5d50fda73c075de100ec12ad8604740b38e8eedff3196d7df83a3a0cbe7e978e1275312f990cb264aaa2d9c8d2a5dfa278c7bfb896c36456648b4ae7e78d0dc995d1446cbe116dd0fd49028ec093837f051bdb252539f634126b65739c1e89fa9ef8ea1a7548e627962c7ca36aa56f127f8fa4fff2186c45c090d337609b18db99c87a93c2282abaaefcf204c4f66389447781e73ac45a0b08a0f8f20f78eb5197b4882c1fd7065e7c863305bb663c544ef7001716513a3390582672de430ebe98000c697cabc5e5d12d121c2729489c3c6067ca059e941e0abac36e68fed2f5e9e1fe12fa8aa932ac35ae3ba393e1a75a98348b9af81492af3b1e1a911766c362a2227f545ba6f237a59b455947669f56948865f801697433f0cd53134f5904131f1237c006db5b4adb34848b931862534d7b7981719e39dbd29bd171860471dc7ccde960073b2ead9199ccc5f8650dc9e842e9d1c84139956d4a657b13f31d3cbd7c5094221e81ed45c877e0a27eb3b43e9e2d8ef015544d1b8f1ed7d6340ab1c60ad66af5d1c44688ef5fb1f32004999e6c54851fc103f673cd62d267a2a6b3e7291b2020843b93481e32919de862e29751886ae9c648b55c4a346c07ca091f616ecd457131c1273c3bcb184bc9e703189e86fd3f65063d21341d89a5f59b6e7c4bc6c23a622106f26aa39a7d02f1a5df9a01bf8c5866b27d674500955f6b03426c2b1a7af11c7d025f13186b06f0d67e01048b47819865ed173813f37a72c56d04fe59057a5381b4d3404c132207e646983bc05bd05ddd1db5b1900131bff94629d3cc3b83cecbe11b8a6ac58cd951c1b5185c87d6cd35db6bfe80d6e2d26b6cc3e562e2d5296d98733d4922b7180f004dbc9eb6c304d00e5ab256f02b4b1ec32c570981d5777a31d6b7ca344ab981a49e77062b7fa009ee86159f5fc642dbc04d46f1f2ce7c63ad3c19b8ee2bf4c7ec8689b0c4b560a2f1caba3283f580d438b0803fec717bb477d3207a483f7c35e229e322e379dc4031ef0fbf7954c08a65f355820d3b2a6c094bcee8026f947ceb00327f72fcb9952c25b6d54f4be3a1f181fd9a325cd42f420019e6bd4eb6d7546638ba885aad73bc19deb9907d4934077e72227fa9b76828ad73170d5ebc30debcf1f5cea1f9489526d83ecd09e6cf44185a41472ea5719c034157746a788e3c9d24d27c4a7468de6d8e3cdda1b0e0dbf49a2bc6667c0c5e918e56025e624208de212548cc063a7c4c873ee7c6bed713c87d3b3e0aae6aa993f323d25423cbbd6d96ce1b9e6bab56276524a17acca359821502b5ffa4ec157c3172a8e633b02932a350961283a813f340d8093239f700908c1f1f14b9735b488bd8beefcbeb77d5a1d4cea2c4c6da1a9bde87a8c57e8dd7ef6f8bfbfd26b72f20aefaf55325bb7daa47a78be48794159ca7719146459a46190f7931fbd1c759f8ef1102dc8cd24783f1a1b2377ee4ff79e8b21fbc174c01116cc60682243cc271bb94f52689b1f5b30b43e49da170ce049ff5f17ce08f83733abb7ba10e942c6ab5b5777351c25aabdba61b52f897aea9ae958787e137a52f19d109e01196dcecb1204c4e987bb10fd1171a8abc48a0e84c595b5175da7ebcf39bfd072052a02cb982ea5de0106ab011805c571d213c820f0f94125fb234c249cd8d1c567afc66ff611c8a7b55afe3e53f20adfc005c544ac66499927e27f0f7e26239a36195c1be93d81bc41c5b09112c446af901a3dcf48388269894f793fa2ec1819c2ce1e5d09059b6fec42d3df397cc3729c16dc3e21a54669a6b4b1f0b0acaaf66bce2cf6fecb08a4c405a443886c41afd1bdbd9b03cce3d74f0314fca8dcf5744b307385bde32b9fa02fc2da5a3d95686296d2d6f0cc14a2429be5162e8e0c3f0f73eaa998e113125214c62eec2853fe281df800d825896cb6209884a3a1e6110264b2608e173cff146b0382f2ead834165b04986c02118c5ab1e66b5a3a4506dca3da08189a3216d00f8ff0340fe74fa4eeb4bba8b2a208453b1936e52fb33c8b6ee836423d98465cbb06558b20ff1fbd6faf7f880d56854848e70b7aa5aecce7e82470184eaeaeec17def03a10a90fd429b99def78922e322641671abbb7781a10b691b51d4a40047156fcbd75aa1b71a34ec84562d064a3d5ed184fd2f93844d28e8e0185c8ad7a65a5343edadf3b56361cf0b0c629e7426adc8f83818d537f0b47a0a9798673177af8420459990318c6f332993a7ce4a9b823b54577850cb4ebc41bf9977ad7566b2d34b349d8253947fb9c59c2f9f10324c60b5c734f790c2dc46c356599e8262b4f7911c7f4ce6a92e11a6ac8d48254bd196d674a88c5fcd1a2d75a03f4dadfc1e8ca3aba30da45f767cadff1b453753c2f5fc56bdc7c874aa49de7506eed9a389efcee17420d193662d183ebc6dc0da0a2899a8782b50b872bbd993f79ce3b5e1233589736751c2f1ad5729a7be3e2e78f0f596051822abbae9e3abf43d9eb2627b2b88d7bb4efd4e5fcd33e96b1cb2608a85987d77f9f0a062d95a18a31e8e9c5c99889c14cbd4f68436440b5c44187ff0df11aa90b3265bf452501e4fa7ca8e5db7ab73ced6903b3f1dac3cee447ccc08f9fe325a63366c7ce3b6b84c519120d6226791404c9e9a5d8e1613a76740aa043babb5f06668d45c8fe4ba25731d08e76a3c39171f226b84ae55f1ad1282155e84a247104b5bbbac4805395e5320a19744b532b1afe4609cefad008908c30286901dc0d03b807919aacd7c393aceaee3534ec1d46e04afaae2643c008c53e5746790fc943d029411bcf4fde21188077ffec4b2621fb0ed597020386a9e7adac8ff1406942726e519c2e8779a55cae299c62c5307a8c53b3ba650ebafef455bdbc3f2d54929e74b1412676692648a6cf112ac9a30fb32d601464f8827036b135759e61be68c6d2f2612493d22832eedb3cddca114d0d985c329c82d962cd01ee2b790669ff9f5ba029c3d85f0203ec8d75711bd22b4b57b724d1c0aeea6ec63403e960f97dfe2c903e7a64f58429c351e0042b0be3d82f2159923def20862927091642c3f3f5d47d36157264e4a8b250e5723c7db5dbe4cc109ab8df432d85554dbf681fd1e939493ecd412729aec4a1c9f8df1a47dd6e9f8a5e2ffb235e891d65d92dd3d5e17b63ebcd471ee347b249e64e1da1bbe37b1037c7f60ddd63a1b8d233c6bea0e149cffe648c50c63ce583f98fc3cd7f8e19b236d02d53c062ec628334079a6b299d45f70393c57cf16bf3992fbbc224c73c2b30e24f1c3924868cba5047e3d4d7dd5202869a1482e069ac513e7ee8d6d6f4cc8166abebd4b89e9cb6bfeff10b8cb6bb2bd223d71b93de4fb5928dd5e51d088ff065f3263cde774c779aa4298ac64aa52a2dcd9e64092c7581ab338120596ba444d8e30795687a8eb7a8219905a871eb39313c77a68ad7dfe79910e64e00e639b5099480e2da977ea47fd3a59b1ad1813df55a77f1b404e674d52a42200e73281a0857cef992208c95b639b002821ddf6e1c589c19908100721e46e989be58914a6203ec84cc0082fd456365d959b484c021dbd841aab34e06243a18b2e24875f186d8873c7877259d67f8482afbc2846f15191ae923c89d0286320b4d2416c7294b8ccf0808c86508a94cbe046af75a6d86cc849c3d224506a1a2ce90d628ecd8be644e83309a9f8122a6de109a8db14c11fe4cc60948d7ae6a362dee95d5e7682e87d8efae6a40a67ca63e0467edf84060cba049d506558ef4b3050949fa34dec4504113703817ab20820691164b40d3b746965ad94644d80a81c92251614bfd6c49d5c66e3b8bc479bd08c537c21a1d9478bfbfcd4b72fdf95ef9b7366f28e60e69de150629d72d0e39675ea433f870eb4bcd6e79d0534782700234d0da0aa5860e59d17f70ebae5a8e8863c39fc0b01bed63c81ee35105d4955d7c2de38a46d17c62060847428191c88e518964235d957dfdddb4966f6c8da46a729fb7689c4c9ce4d6cc23ac0ce312e9306dd24ef4ce615a86b2f59e09b500587cd49e9816118e149b51993d1dc904a529e153d246ea28b58d2739d33cc2fb3dca7f3fa9a67e81e3130502c1caa908674f91487e728a30ecd2be2464ddd77c8da38bea2e45a6acc5f1d6901366363af40083e14b44a09a85363fa38c1c2dc23fe448d8101f99a5873a9ce0d507a1c2288c13147a7870fc75f317fef78c75959961585f343ff0d45626d43bb38fba4e16dd1ff28d845e489deef3aaaa9b58c87f7d77956887a170a776bb90a8ad4a5d76ed972891415e4d6ed62be192b526e2a686463d5988a249f5dadddf70edfa1769b63fdad1d9ac8508a357bc7e5b5e21db7abb9e361a800c9b6bcd07852481fd2ed908e1e484133e52e240baf8cf3743274605fec31471e2be0e1e411b9ca8cb7e9fd2b156212d224b2e8cc609a9e30b318c6a5b1890f802433978f938323dbaecc5bd26952bc6b2031769ea9646f5af8cc4a152d4ac0c788447ea6288a99ec6a4591251205ea28de897f291c5b67169d63a90382be04f2214592aeaf9a5b5a66b3b820ad3cba372e462f98a30f7243ecf27edf64714e3a3cac87b19c88148b91621a7aec6b98948ba9e7b0003faeb65d734bf6c9fd7557e0b794c70812c76bb8ba3d71e593bd0a8433d943c7e1e34839f31bdb5ae98995b0e18f059397928350ae7a0077fd1464e399b158a6badb5fc1ba9c8d05cb7c55002e30cd65510287a0dff7b82068d96883989eb67cfd7d2e68f974019f6d4cc44dc46d8f32d7b5b5f46e6f8ec5b8d8ce030ec4e636236c9b17987d8711844901d9df3ad9ba6661593b3d2e721e58dbea1cdb402ad966d206224087d1d0f4e86c422958b841148a93374f6697f1b9daeb41287bbcba76d9c93a2f02426476429fb780ae09f8fa8ad24559dc54a6b13c5fe282a225b7dffba46d3b321366cec787e69706c788b0929fb3ccf54f47b94fcb39130e103fb1d41b3e033dbda49ad24030e334d8e275478016375006804101fe3b6a3e1aeed5e6a5ad35697ac0e00bb0c64d988f19056bd7850cb2065b5d84285a38a3c5a7bc7d5b918e33a0b3caa7d408454f6d1827ac6abed80f9034600e5809e69fc36ad79cc073c3cda605f4a4133b5f29359ddc76ce1ba8ae45105448e1b552cec90177069cd703eb8a27d6e2338029a2ba56a0013b540ce69dab826bb619c321efdfe1b8cc21add9a51007ae05903d07a83bfa716d2a71ebe206f1ec3f6e0e6aba08b7534157546912e144bbac699a9f037c62ea1ad56658ed14e6e5148a1c492cd97031064674397da7353c6308cfc2f6f0d53852bf87012081928d287dcdba1de90882e08a27dd8311928e7668c8c383fc169e84018ec8650a97335a46f42f840f85c031e5fb00e5b6686018190536900c5e70ae248fe31d910f9e9322920727f625175aa7427120d75c2422c9fa018ad8dd00a3c5d6288be411c184db10e63dabce8a97d10d7160a16a0ecdcf0ed8b421f6f5ae3c17f6be966b56e9a2c1266d98c1bcd422d447c58d75d76412c06ffb6e1d8e6fa7db29894e3281485102f89a321eefad57adb4b3f605954e51459bd36a82ecd12c6635a48bb2a652f663424f1e0e6ef002fd07a6182de64bd824adf01ad3e46dda734d23be4c3de3cfb8b0be3d8738a3d04a11139ac7ec97f55e6437dd78692b072d14a8fc62d6e9ffff193a8cbe1b8185ef5be2f58d83be563678e8f848658b0d55af6d718c3806b9e83b86892ce8131eb1a88516e33fd3a65a3e28c49d6b7d94c5c3d515f17e18ecc11c78fcb45c858abef02da1e28baa745dae873b4158aba950b2cbde895469d6e39feac59ae08e9de945699947554861b8c6155d2918169da1e49151464fd8c6e5252da8dc122fe648011be280e8bd3a4439eeeffd967209fffffef94792b3e75c8782486fc977f48211a0aee85b9467128bd125086dd46912cb491de37c8a4c5ac5f4a178bcfd8bed2c30a32443ba19c73323a8343c72bb0e182fd462e0dddeadba1008c3b8df57567b8cd5da36005a47372f8d518ef37203a8abbe9efbdd9370cbaa0b78fa7c33a18487566175a022abc77d7bccececb7a17e22bf13c6a87f97b131905249f7ffebb040a11ae13189bcd1c47c3821a0bfa3f7796a425f25506e9a88949cea6c5345ef06e8075a4887ce2813e36fb09bdc401561759daabf63b708c5c5a32f132e27944f7ef8d5f4b62e5f4788df52179dbd4d542bff8987172cf0246fe0cac642603e23215e2f4131629c4bd30331d4eb3651c3f6ccc0f928bade3050572618c7bac7360272e21881db6714792e62ddebc89009d7d3b176f0456bd56317e8eacefeb0cd6cf3cc623734bc123c0f557593a3e328e89abb5bfca17e52272db005327bb8a60e997bfdfc03b0a20db9279a2a9400686d3c5c4153ecac73b1d8f06dd743c375a882358ca1e3ba35d92774c6cedd42d4c0ddd23f11a04a5527300b3b633670d898e094c09d3aa52df085704431aca8b9510f7bc3df3c8b76e7c89967fc3a8001aba33e5d295d05f22a0a0be850aa56833cb3b5f9543c483aaf722558c9e05f394c09fbcec199cc3dd1df3212c24b4b7e21802b9ba8e2c11532da764d88103453e9303a0aa8532fed5f112d065eea7dac0ba2ada14bbb5a7796132b1494edbd6441bb98dc3b79580bb03adc3768e899b95c69d70269f2fc4b01ce09bc5ba9f0ffd3941b865e227eebe5bb870b7ffa103e2a53ba1855db9bb3fc4a308c2c103345e2657c774e92a94aa2b3c320e85f8067e9c75b4808d5cecd574d561e9cf3d3c493b49fc5088208dacc369269f912c9c3510ee085ec2ebc589257bd2fc66585fe79561a3a030c473201839b081cc98e07551430f33721ce53207946685a334b73ec3cf86d752d2b8bd9d8732a363cdcf95ec1e0ec70adc14dccc5bd1153243f37d02c2aabe89e1eddbc74a0610755a5a3df9a3c0210f595e841c48d6b5435ac3b5938e0b86b3e6ac03af27c4615247dcc88fcfd1254dbc7d9d49f8b2864ce46d68cc50e02cb406a4a936b5ac56b98ab2e03df3ba748d8ce7b0cef9c203bdc784c3cf82ba26248afd291b9f2389b2d55c83f3b9d220af61e5fcd8e6e00f8ff0340eed7f43b5d674bcb1302a891dd5bb2f597522638fef082e202a6f97d6bfd2bcc3fb11a35cb2859b7aac5ccecfbb42f04545d5d3d0b0f507c20d42192912ec2469a99d90d91f0f888b9ffbf67dacb92380e61db5948c16026da6a3ca2228d2238f7718615401bead8ab9bbb434fe7f6e4f00c3e3d42f7e3e7fd24e68f07b447e65ba6f1c61e7810dbf9ec58343cb9f3e5d9d46798aaecfd7650399968ee2ebd069a860af5fb6f58bcccc4df78fa4e0ea7f7d180c33179cc98ca1b209eee1be6fa10a4c6b6e7110b6c9d03242f6626a3a0308933774c16b4427010a96607308c428ebdfd4e197b0c4a0b542d705ed1406a295304c3a8965e59bf0c6f41946f98a58436cf1ce46117c8031065ccf94d7522f2dbd66440b3d6356c2be31a02cfb3d89d50029e012554de0ab1eba9d19eae1a2469368828b25427b624fbd48bfd2424ea93231f0dd4d536bff1c2212a31b2dabf3b16f67da7ebcaf8be6629d88db00e0263bc220328ed5816ac6c317e0d01d054ee1918161aa31a4587af146e511f549fc7f896229cda5c7aa8686d9b4acc0cf4d2a0304c99d95c16cf6690c2d630723c20561407b4ebf4037ca87894a6a5a5b58fb4d33cc0f7d3c85ff166ebacd7b54e4c5947cfe7137c342dd776e2597df099ce1ddc7396303e2c6387cb999ab162679e9983531649a4a9ff64b2d4b242eef6b95c10b8050dfd842472ac6f96534d33780ddb5462c649a527c821b15d0a1f2ef07752b6559e848b142cd3772861ba6025ee563a4f31cd36e7a79933cff101fda808d72d910ad3aac8ac02d47c3c940cd1702202a8b8fe7df6dfe821b0e98b69c6aba14b16cd786cbea43bb719e095c7b82d14a28a42a50f3731ef5f213b27df46c6c4181f408547de4558b78aabeaa1e07ef2714514b14ba8b193ad4bf25e4bd6380ce7e23feee48599adbdbd8bc13dd668ac9ec16e65486db7643730917be6c3260dc16ea9a285d8055f53510c858b459516832c226d7badd8d094619d7d3913b8ed6c52146ce9f6ea67b24e966143a87c3d024a3854400d699713cea050f775da4a2bb2b8976a4751baa6746ba2c348d049e2514515f7af156055b1c25a73020d894bbe0a4ba891fad772c78faa5b830cfdfdd4680226b300df81ea35d000bbef31bead059e77816f40579f4093df4e64fe29d82662015bca79a81eefdadf317d5865e4dc82c13e87d255700fccf6e7db6e7bc41300657d232ee68f27e70ebb25cadb69c3cf5c8d0d3eb8d31aa3d15af3f667a4c5b994e0b5b8f43d93147560988c4941dc722a189235401a7b51a29099c69043ae1a9377648e7a4c327664a8f56e09a34091a1119f44614cc29929a52825df9a0025469188481199064d8f3f0eb9e10c388124b9f1bbb3a63e32e76a042916470ea13f4314225c7911f5c90243e73e9a4ce52f9bff0a7c9bfa04ed371b173131486ebf98f19f6622c259ee85638514d077de4e281810cae4300a4db04817f8981653a2c0e1a4f3478c951ed0b6adb2fb386858081a5195bcde5e6a261cce9668ff34c435b18c779da1bfa70af1a644e298c3cdb165986bc92d43204e4ab5fc2add71d45bad33ed9ce76827e91cf511a2265410a94abec5b16b439ce651af50b93a233899ab8581d0af867dad8d9f0ab76df1df0371673c27bd42c77b1ce5ac65f254706487ca9ddd93ba2a82d0eba2d48b2b8e73ec8a6704cf9c0a982ff25530284267acb026ef59c1d0ab633e15ac5996c9df60d52d535b4357271d35358bacdcb19cd6e58a3356f3d5fb5138df7582d059f85a71dfbf19fb064de73379377ffdba5da6fca7fd629c302d04b62d5f29de6a3b785e8a5ddf611f55efef820e2331e9227340a4365cc094d844541501136e44fcb146e3f713bea955cca84867cde4e6d93db43fc4346aa5390f5d9fbac30f2f9ed3c4757d9bd53277b16a1e45e69718eca0f6801bd39b04c2e47eb0e43113f4d2d73ca4ea3f7818ca655f9d39fde2d8a310e027f9f689c20fa6a0a8916329847f94e3bbb9828d588e4b3cf8cd1cf61aa8895a03057ab1e883a977290870ebb3a65f76e507038f8ddc05e0ba7c79e5100902aea59cd04b5481d4a265af63f4ebd6f8daa8f8e8539f7b08eb992ba22cfc2d303ddde3167a76c61458ee977a0cef6b284b80ff2d48b03f4b96142d34e801b1887ad06892cc873a28ac1791568b7f77ecbbcb3dec0c8174edf2882539e93f6162d21455b8cb8776ec5deb83172f0b1cc2c9e1917741f7504f0e8ffce12f6b972a4c10e69292b0f787a6ce51f01a1fb26948216ad86eba07a2ee98390ad357e3ff7b494b645bcdfffd4884d1281fbc1a1d5b391ac5d2d2a88028ed5ad6475c86212d9ac19d4d41e24b2efdc6fe250c79cb68d4525fc505a7439cf4f022d33d870cd62a2605309342f12ef38746d56e38c783353f4ac608ca6dbd8706778c981e282bd0208fbb99e27585f42483879f3ec01a0ff61ebef211d074a6b6a428e2e53f8692e1dfae4d4b33891e00c5b75205d6254c7e78c6d7b4e453ecf70adde2d119c22fe6d7cd5b0fb19208a300d6b5ef29f654fed276de3d5faab8103ad70ba8a2db49c97b211dc37c3bc9a70fda2be86ae5e90951d0fa78a62b631af3bd6c4a2d567eee9bcf3338f46f363c3cb9c6ae9ee7e9f3255631e7da6d7077351b6b64907ffb363176dd3a57efbc3ade9d6d8f76cbf21bf505d521da1e7cd87548c065db51bfd886a3a67cef7e1a4a3c0236dcc4c599e1e6845dbf9e1396fd1cb18ba7dfad53cf48d13b2d2a6d13496dacb1bfc2ea77bbab8ab2d8321a040f0728a7b51382f9c35bcfc3aad6b96f62d0285484985f16ffb538081f9b0d16bf7f00167ac09f0d22a34c78b24cfb8f696c3b1fdc8a52880ee8bcd5cf913f0b186d4ba4fe9b82c54a4e694548df4ef349792cd42a3f830b2ad89708090a0ec3abd30600a7921ac537b7c5a67d1694cfc849cb6de0cd1f424a6a418bed2c4a6862244265cabd48df5b2702102ac57699032ab210e093cff65f1109a6ae4783e0035ca76333c8a44fed9738cca465e8c935a9025ff6acddb2e52e9760bb79f8e7270d630c12f69a0ec4b0e7dc0fce0f3b9779ee5af6828fac1d6d8ef9e0460d7bb7d3d4d129ce24eb223824c269905b076826ff6949999b32f261f138e9a1521de80553a90491b03088e414488269c7e27fb4662a1680b07020a63d6757d809b94fd101e0d06bd4f3b4fcabef5d3b68ec5df2a546f44d284699b42565a7464d002fd09f129073ee279984431b4d4139f86058f0ca478664c26b9649ed3b365e7873520988372cbe649111dac8059f0bf2766c09e7fa2a15efb6e766a376608ac195ff39bf3785b73a97b8ec2b0b394b66411cd756aa2b0d6d2bc72a8dafcf3c23f5cc952985cc1ec31c13dd6f10f689bb1f3b166f3ede0b5816ce93f075522c2717ef69dcd047837c1cb7b2d6b2b7679c656445025b9b503d9abea1e3d2c57e32a7aca132dd04649196ba3247f556259b0177faa1f51e6d703ffcb607e0b184cc39de8f55eb10c3e8922fd112dfc0b88d803da35580b046207f6de0dbce671789a9e935b0e9b9185422f8271215c7ad1311ec817c228071f6c626359816d18cdbea7fd7009d88e13b65ae3a7cce44f4cc2591fa7cbe467c376ca2c455015f4a3098689d59f3a3729433f0b044f3a805f2551cdab2288d4b8fa073703a0848480edbdff7d40d7165d83c6a0d6718017ff3eb85da83440ae5aed7c163913bb152064f761f08cbcfd1f0b5122d890d7f06046bd9d83505919254703f958db13e1efea6c7ae0b0f8cc2e07fad914518fcb416616d97d444b136b07c64bd3cef2b73aed3f84e818ee080f7f263a488614429bb263c8102855e2b5ac654c082215bc43550fdc8225738c1001c54099553869a78a0d78ffbe9082f8f1c52bf24811f978c83c8a4c197ba74f19057f5bc6fc88b29fb92a7c8dbf152d262ec1ea972ed7bc1a83fde01156b369e6d83d1b412d9e9209ce59107f104f156e7a0424a7c22891c6298891e0457418c4c08578252871f0517fc048f1d834b630ac33fdf43b555763fe6d4e606f46312fbf64beb228324f4e90a40a74c3728cb57ff3c0cf9cec185fad3bdb212fa713f8a3139f9081ec4538d9aa86a041019d351f5f5e694ad09748ab719602d09c93f999f34567dde25dcfa3f0931292b6efab0313d73715da6e4b331924b10e4092bce5279e801e20d15c587ca84526b4a2d5a592d03c6f6f377b4ce408a12820d51d7c115f14438272988124fce0c3021cc055472568f0e2d85893388a70a27989b5974f9f37b946af80b9b0a087e57c5c70b7c3cfc481b3c2fe6742076fbad894a6d451dbab34df2706671a17e4540346da4ebff55f86ecad8ce553a167fd00fe38f12d5f66993e2da15df43336c88780cc3dd10f26a92c1aa38b9c788ca331bf7d3909c3c79c856634c6a9729b0a6412f6b0a6fc0f0ea283151b098765d63718b5209a997feae3d04fb5ad1f70b1fb76d8f694116c7adadbbee1bdac5e0a3851de692571c6d383fd18cad1457b587759f0cce7d2431eda53474d50470d534dc063cb50f125e6f638beafe291045bde01d6b8c600236b227852bb9b28a28a2ccb3afc2e1e51a6f4d4c28ce13b2402f3459e7f5d221f880706c0b1284d591c437ae2d012a0098fedc171e787f8d054285ac1389f323202317833b1372dec4c0ea70f03849c758d5049e4cda0ebcb26fac86e8a1c100f32ddc1715b73c718b2169a9405acd06c84103f246b79ee202c764f5472f073734cb04a51f55e6f519ff1645e7e6c30064f997b1cbc10d6c1d7830dc25b91078127a8d38dc5878d2c3b16dda39a149846277f074be476cf0731f7cfcfcd717fa15c055370d27191993f92ec5009071088a6b0c59ebe0d162d4dca9c8ab4cc1f002ab8335844e195e68d8e9c183204328f21847ba9a59974210bb9954669c8f5cf02cb0138e0f40d9cef9ae6bc4c8fcf1bbfc109cd715dad6e86a0eaa43919ab6b1730fe89bcb6ee74e60e4ee2eef461a340cab995a54df6ebf959d8fb6d6c84b1580c60e6ec1006b7f2751e86cbbbc638f07d5c8fb35c40a8fc00be4e3464909825344409c54fe212185db208a0f655119bc9660a6f71bf4eb45e1a111745191a61e43ae798939f029caf784115d83cc56b7e4e339c366c1bb84d2dbdf42648c152db331b5f17c9c97448d53140a8cf6dd4ab7e5b1ebb6e8adb60bda0f0f40c556e62d70966f6e9410208a83fb42206178a3140a86e5fcd1fcdc24e7dd52616adf8d4d9d2b6555cca36beb9cd680ec14f309abe6d92ecfbefee3e1e2fcc7e597317f2c389fc897bbc287d434469bd46066f20340c8b25a12e9ff1ed04e3ec5d9a70df8ff0340eefd69f6f53b49aee07d48684433d749a966e394eaf5bb15201b9d41c30961c2e15aa12f590f2c2ca091031159107b25e0c9248b8f705f209684b2ce9685ae9397bdff322b12cad4c648ebbe97aca65cec0823c26ec2bc44c672b9a2af8878b2a6929bd01e96801a7aaba2480b9d1ca831115d2968c89ff9eac086d06bfc1d50848e06abf6a485dcc5d55f4ee650290f000503a51df855ea0f9a3537604f1c8460befb686b68746d18e9c34c8dea75eb219511e404b82c81b1a668af7abca467e107f66bb18ea847ebca02b694a5f8de2af4ef241ae7e923603fadf33be047d59ae9edc1510f4cdbbc05b8f18437175df495879ad464ff59e9a82b5dd9166f879cf1b2705a1dd2aeb9e825360bcaf7c960a37df2798aff4cc89f5340c17b3fc2705bbc2f9546a2536f837ddeb7a399cc6fa94adbfd5090ab4383e423b0552b1af6100882eb6df4bd8b13945bfd070b3d68a9a6deaf2e83e14f4db0fb0e26ace907c38188a238f8f495e6c6d3bebf8db004d4bf48ef37dce0787a21d7a36770e5df8244877d1164dfb1ee147713ca9b8b41a648a45b55105184677d1e19ddd5eac7db99e2efb759acdb24324cd804901d7e5144585f6b2f9a1be346beb647198621c0c921384daf0df62a4c77132c381ff6ff47476a89e9de0e395b10cf006417005379ed8d6acae7dedca8817b7b906a764379bc871a7bb7faa17a12057b8198ea25631563818a12b3593be60dc9442605d02c4af3bd8680fa563bb88a4c1a60509a562271e4ffb54e4688611a4402a01994c444463d81de991d5a6a3a16d8ba960010df042e36cec05d114f5fea90d53984d0fb67f9418f2085c4246b135bbfedbbef61ab188c8622fa0b2d1d6dec8b141baef549e63b65f31fdeb25881617ade2dcd13c362daa8e2b8cb63f674ff9655b6ab02cbb644f29dc0c14e421f9ac6990a555d4ca57a3cacf75458c1201b5092ebe07444d06840c46557f96f6e748f4745cf60b7abf87275e760c235934ccdc9c1a5c099cd07daeef6d92174c2bf748ce95749a1013242f34dbe84264ee0c23e45f1f58a8a123265d8a9a07c52b1ef4f422f8a2f5cbe825ed9766ad4a843742886a9195264cfab010a19ec819764392e72b5109e613d823ab1024d480519784a24acae4b004eec3381413cde52925b21330e532b19a23ee1418e09a66f5fae55c05030d30f219c7ac3c2c9163f136ca36b437ae2b4202c1116d784a6467fa9ab4cb828302b244a0486b57b447df2605aa6e24296ea9305e159e35c433687e89e9d65f540c75e001386ba5cfc5fe1c77cc7d0fcdf1ca02266db7b70720ae9f719d78474a86ef302365b723e1d00309006b140a48cdb7b2bebf0939fce59a87d7bf6477dc9402d0b97e104aee32158ba12a742b71605e45bcbd49b35fa9bae16c9cef50b8de73e653b60bfc864ce8369ec87d34cd5a7f215229a81169cf3204cc46abe655590b2dffcfdb0ae4630d2d0090e0a366de26f36345f06bf4eb034b103a04ba911c39c2c00a61f7a5a5baf76fe02e0c5100b559aaeda1c0c1f50e93586c9e6582f816093b1ce69dca7897451329f64f153cf16bfdd31ded8f563f23140d99a8177371810339038f7f881afa636387b4070e218b0386b189110ed90bb6a07876a2ffc859966b95bf19f6c5a12ce358a0d2490099e320c521d4622071084ee72410ee9e0ee61b93df7ee212e4b98312e41b007b46ef04675e448e20bdc3808f121a3b1c9eda22117e02bfc4a604a32c2809b8599878ae306b6c6ec26f11021e22f8966abcbb8060ee8040ab6fe498e0db9150d5833f3fff5963c346e6e8ceab399cfbd50a0c5b8fa4d4b120112fb444adaa1528444ecbcec9e1021d3e14ef365689c4bb0ba3d05acdf749d947b40a78c90fad78de565fcf2a6c175022b1d38ca5888101ce8f33568d4cc77da2bf81350dbd7fe29b7041fac8960bb2fc66a867b2d0f6118d533f2b031f1a543bef4631786e82f2c2373d0a416b70fd5c9454a889999542e6e6bb890a8095a7f702c95a571364ade32f987f30e956f0f8f5ba1b23ed6295f8523234c244d0a2f5dc3e155a525dd6e22d55b4d109cb46ed989dca25cbbb1c7b848e2590ace9f7f8f0ae80449de5f83041df4783109ad588f8ed025c80f1f875ecba50f26dd478ffa209a1f318c95d69c1f38e3adfe2156d1f320e5a39f64c9915cf4294ae4b4cddbe3a1307565a25364f38264be375c8842eb7b69a961132396fc2aaf2eca99a7fa9a8c4ff9645b234c0fd5610aac31e516765cfcfd3e8467eff78d12cc36540597268f14695a62b140c8f73a9ec2770677027dc3ba0822a1a00c97903916c10cd0e775d463bd3e4bbacac95bc3458694e0184743ae0690841801544cb01b8779f4daa055a6672b6e8f364bd92a3dcbd2cda5253c6a95e276d892ce9cf743c13563616b3412d6ea9c67b12bdc082a48f2b8ccf3536bedd5d2aff2df784179dbdc554cc01ca14a334eaf9de68793b0820ace483ec63337ba2c25d174f8a952d32f53d4168f0454cf54e391f9ba421c0ba59fa771fcb4121c53d516aca2c9af0e0a7f7f43d8e194b248ff14f302f633dc7a5614294bddb49c4e74ca6e5741f2a32145da1dd8357ea19e3b441270482eb609b9317982e7a1282f3896c313cbe12ebe2e66049eb56bfb4cb95a8d6dcb87de1220ada7ffa7e9943b53dbeebd2475b630bb7b791ceb8614941d909ae572cbb34cdc4d1672978d8087ee0da16dada3181cbc4776f6c54c2495f8ba2ed59c51c6d161830dbf7d0ff1c9b6a6480369370d0fc15b755aa7fb71f5afa0e52db815302bb73975b9f8ba59fe1e324c92972a78ec6f2c4bb37152c238437d19239cd0f1f10b69bafde9495176b6d8f9a9f8d8459ec6716506c98f4fd822fa78e4ea8ae5603fe1ffbbc13af943b38ec764317d0b39036e4849f9640994945d085b513bcaea454c64e3dff33d00a518f4311904189f0ee9f1587e674f7e001039adf17030fd3692d83513be3fd71335aeb5728ae58f75c90aa8d7c845b92efe5c35fa6512e1373b8ae5b5c1a408a27299c23bbb23612cf36df57a206b7aa3a272eaba9d19d4fbbd7fdd15f9e3e5b97e3c737f51564728057baad689d1897da09606b6a3f765806d6a7ab5f0051719cd382a06e6f323e73c7a96d7ecff9e9ceaae450e6ef15411e83ecdc8c3fedaa011934d0af035c27cdaee67a4664f3db27696c553cc1e9ebe9b412c988805fb1cf78de685f20244d5bc5e120ad6300a0520462025c37806dc2428b9c9c94d85a1e951fee19cdd30b2905042aa3c0c05f7f059018064fc4085a3f8483691809a04c06b4d16cb9db2ed2ecf9e633c1c4abb743ae51844ca449d069b50d3dfc453dfdee73ab3eee18c88c134973ce85c70b8e73c062d7fb043fb0af5c580afff25531408f108f2b49c4f5d110f50dbd096bed3c32d79786ad44076974a81ebfec9967c7be1d15c197e1ad7e86861963cfb9ab0e15b7577a59e8f660787969ae9180485fcf56accd1ec8d3dcfa749de8f49e4d33dcbddeb4c2113690c79f3420702207a1fb64c6447ff6c0125268705de78cad0b15b7cd7da3128b349bf6aed18f7fa3b1bd59d8b1bae5fec0616db8245d1dfa46028efb5ff10351279e3f49fdae5f853ef1716cbf32fb362ecc9dd4501ccda83d69bcd9cdcfd1100ebae006b340283169af82ea895bb5ee1bd0803f9e566877903982f98599641a89f8241500f8994e0ab116eaa7a8b12792430adc41bfc64ab07bac1dded2a3626e75ce102eea1c4c3440862349d1096375aa0c0e85a89e6f482beb9077a1e01a69b71009d688f85f730bc93aa501990eb39fc1844970504f38558d4e6618f7f547d2ba654e55748c92eff6e26de7feacca89ab048ffac0f14214a4d8333dc078f218a8c8d044f3e9f1751d5d5f79a15859452a5fb026fc293b21c9de9e1f30855dd376b7940ec1f8822bbc131bb24c7a34b0b019518e5db5899bb04f37bf8478c59bcfd408fd7589c3c5fe23fb2edec6a63a34ed78db15eaecf2a30c8cd98e492d6302b8fd1176275b059b14d63b614ea5c2eb30ae874491f08da3697d840c37ee68a88a701325ec89fecb09bd99a9c491eee6c58cf7aa93b4c26902fcef854c79db55fb32b69983c50fbfe3fb4891066bb8bd2af3ed2977213907607dc8d70c778af59916ed3dd0899b89c5d84ddf20e72224ef105c626b76355c78e98645ce964245f5afb63955ba9e5bab08df3fb7e085c623c3e76a39fd87a95765fe9c4d66bb6fc8aafa376eb07081996d89489c8c88a87dc235e891aa7bb90f244525fb94515dc184a90a36930bbb67a5ad329bf49876e1aacbafada0bacca2a60f63329a4daef297e65234b2d124d5d55544b5f735ccf83ea0d5965a261f5ddbf17c3d0cb2cb27d88bd2e5f5143d21c76ec6f50c5b92e603cce3c34ce50adb63729a1ee4fbd00306e6c223d89615c1747cf53adbea34afde0309fc557efebd9392ca1d4157f0088721ecb172dda3256e5e41501dd282b945ddeab2960328802dcf0baa015d98893ac9ff070217aaab7e1a474e1168a522d9c683578f4f0a307bbda1fbe747956bf8214aa7a07d2c5d4cfdc363e2e4caf4757fe019aa76fb545525ff6a6ec92f82b99e4c59f20efc084c532210e1208553601c2422e4e61b1bcc8fa63b78d6d02bc47384eee7e01a807c7253c2eea1962c7236cdd3cf6bae5a4a96d5432654136b4934e122778da76062cab5cb7a4d23425047686c07b1fcce80532bba41a36ca37a65c3c7afff439040a344429a1438be2aad9c0f0f903a0ea4ca0028b6d8dbe3b3580ef6424bab727db761d77b38007988918937c40b0b2feaf6d8cc926572823c20278243f9e2e5ab4ba6a2c22b60a71d46ff0e5c31c08ce63602a9dc17051c4a4d0d62a78c30eee92de8013d30b9b105ac2cc131d779003b085c83352dc49647ff53c569a0d5da059341f52b8008fe7d4d94fd3491c2acd8acd12182c98044b48eff3e84c09d000ef26f096c0b18983a9b11d4c6d5d27e51978060140ee9df395bde77725b043b458081528c9e083dfff7eadd7556a993b33b836f1f4fb9e798288249616a9911cbe25c442a3045673a6ee79baef00e39001ebbb3afdfd713cca01c2695f70a6c12184bde3b268679bb0da07b1e5c7ae433943f8f3f09492840aa183daa3e3920e734677a9b26a0614b5f19bdb61b8ff22c975930f24ef66dd1178b05dc1e8cc2ced28e635455e07dbe96d51822abf392e0bd761583ff672fab79d354a5326137b7903a96b9415193aac9cf57d264d7ae64c763bbc6c67e7236e1d5cbce715ceb533d9ede0eac0a2fe4814ab921ef8b1cb288984f05095c333258526b5852ce92771ebe0d87653be92e654e2950d50191cd058f17f350272cacd5341e5c1259e96b2101d09367c3b4e76c09edcd6c9a79df42e6eeefc6add0d30f93987da487fe420334f67604f53007dbcc0010d2f59466524a9e43d5df6312baed680741736f03a781982d221c6763760dc21d387d8668465a6dc3c2e64055cdff8eaf47706f8ecb66aedae204c18a2fffd9428c0e68b2b2b054bb9b2d7f63e3791d346664d1b401acff54e1ed6696e0f0a1d3bfcd332de6a3382d012376384cd51b703aae4f91d5149f99a560219aea47073421a3856582e6c49b46a7120cc39dfbe0727a26952fb9d3c1f2a2af546259009852d8f93089d7724480fd628df1f98827f8b290d018217b0fb620f9a644b6429d34c25585cd3601986716e0478e5711c19fa9bac58e27436ca33c0d25b5db999be39e38ed501308e012a182ce6d3b1cdb85f065fda59fbdf3a1cafbd3c8870afefb8bafde36e2199db201e22a10810ae3d2233abb755cf1d6f83de91d566bcb888ad3517948a4c57ca796c2cb9a587412a5372e3613d016620d7066b2d0a25a12e0afdec5c092f537d0aa173185716d456efdafda5c88eedd1f4362cd1c76cda67c61a9237aebd67b7d5fb75b17b7551cd19bbf78f58aeedb9d0d4fba7d606aa2959fccdee8693d2c57a34b2638713189b11dff34e050786a20370de70f95f62ad1b02b6d7c8b69af06feb7a4e4561dea266a777cb7d29cf7949f99779a512f1891558941543abc07ac36d3ffe685447e8237f37940ebf47dd52ddf65fa5ac096a1d7ccec82a796a32b8f4278a2d127bce0141a00f603051271c3567a8f880878d0452cdeabc5f4fff3648e2f439208d0e17f3424a2d2a21680fbe8792f8c3810414c3b77f0303"
],
"rawHeaders": {
"access-control-allow-origin": "*",
"cdn-cache-control": "max-age=300",
- "cf-ray": "9358ea26bac719db-LAX",
+ "cf-ray": "93ed4992bd5b0906-LAX",
"connection": "close",
"content-encoding": "br",
"content-type": "application/json",
- "date": "Thu, 24 Apr 2025 22:07:38 GMT",
+ "date": "Mon, 12 May 2025 22:17:39 GMT",
"server": "cloudflare",
"transfer-encoding": "chunked",
"vary": "Accept-Encoding"
diff --git a/src/api/providers/fetchers/__tests__/openrouter.test.ts b/src/api/providers/fetchers/__tests__/openrouter.test.ts
index 4874575b3f2..4be52c69cd0 100644
--- a/src/api/providers/fetchers/__tests__/openrouter.test.ts
+++ b/src/api/providers/fetchers/__tests__/openrouter.test.ts
@@ -6,14 +6,15 @@ import { back as nockBack } from "nock"
import { PROMPT_CACHING_MODELS } from "../../../../shared/api"
-import { getOpenRouterModels } from "../openrouter"
+import { getOpenRouterModelEndpoints, getOpenRouterModels } from "../openrouter"
nockBack.fixtures = path.join(__dirname, "fixtures")
nockBack.setMode("lockdown")
-describe("OpenRouter API", () => {
+describe.skip("OpenRouter API", () => {
describe("getOpenRouterModels", () => {
- it.skip("fetches models and validates schema", async () => {
+ // This flakes in CI (probably related to Nock). Need to figure out why.
+ it("fetches models and validates schema", async () => {
const { nockDone } = await nockBack("openrouter-models.json")
const models = await getOpenRouterModels()
@@ -66,12 +67,12 @@ describe("OpenRouter API", () => {
supportsComputerUse: true,
})
- expect(
- Object.entries(models)
- .filter(([id, _]) => id.startsWith("anthropic/claude-3"))
- .map(([id, model]) => ({ id, maxTokens: model.maxTokens }))
- .sort(({ id: a }, { id: b }) => a.localeCompare(b)),
- ).toEqual([
+ const anthropicModels = Object.entries(models)
+ .filter(([id, _]) => id.startsWith("anthropic/claude-3"))
+ .map(([id, model]) => ({ id, maxTokens: model.maxTokens }))
+ .sort(({ id: a }, { id: b }) => a.localeCompare(b))
+
+ expect(anthropicModels).toEqual([
{ id: "anthropic/claude-3-haiku", maxTokens: 4096 },
{ id: "anthropic/claude-3-haiku:beta", maxTokens: 4096 },
{ id: "anthropic/claude-3-opus", maxTokens: 4096 },
@@ -94,4 +95,40 @@ describe("OpenRouter API", () => {
nockDone()
})
})
+
+ describe("getOpenRouterModelEndpoints", () => {
+ it("fetches model endpoints and validates schema", async () => {
+ const { nockDone } = await nockBack("openrouter-model-endpoints.json")
+ const endpoints = await getOpenRouterModelEndpoints("google/gemini-2.5-pro-preview")
+
+ expect(endpoints).toEqual({
+ Google: {
+ maxTokens: 0,
+ contextWindow: 1048576,
+ supportsImages: true,
+ supportsPromptCache: true,
+ inputPrice: 1.25,
+ outputPrice: 10,
+ cacheWritesPrice: 1.625,
+ cacheReadsPrice: 0.31,
+ description: undefined,
+ thinking: false,
+ },
+ "Google AI Studio": {
+ maxTokens: 0,
+ contextWindow: 1048576,
+ supportsImages: true,
+ supportsPromptCache: true,
+ inputPrice: 1.25,
+ outputPrice: 10,
+ cacheWritesPrice: 1.625,
+ cacheReadsPrice: 0.31,
+ description: undefined,
+ thinking: false,
+ },
+ })
+
+ nockDone()
+ })
+ })
})
diff --git a/src/api/providers/fetchers/litellm.ts b/src/api/providers/fetchers/litellm.ts
new file mode 100644
index 00000000000..ac143b8acb3
--- /dev/null
+++ b/src/api/providers/fetchers/litellm.ts
@@ -0,0 +1,58 @@
+import axios from "axios"
+import { COMPUTER_USE_MODELS, ModelRecord } from "../../../shared/api"
+
+/**
+ * Fetches available models from a LiteLLM server
+ *
+ * @param apiKey The API key for the LiteLLM server
+ * @param baseUrl The base URL of the LiteLLM server
+ * @returns A promise that resolves to a record of model IDs to model info
+ */
+export async function getLiteLLMModels(apiKey: string, baseUrl: string): Promise {
+ try {
+ const headers: Record = {
+ "Content-Type": "application/json",
+ }
+
+ if (apiKey) {
+ headers["Authorization"] = `Bearer ${apiKey}`
+ }
+
+ const response = await axios.get(`${baseUrl}/v1/model/info`, { headers })
+ const models: ModelRecord = {}
+
+ const computerModels = Array.from(COMPUTER_USE_MODELS)
+
+ // Process the model info from the response
+ if (response.data && response.data.data && Array.isArray(response.data.data)) {
+ for (const model of response.data.data) {
+ const modelName = model.model_name
+ const modelInfo = model.model_info
+ const litellmModelName = model?.litellm_params?.model as string | undefined
+
+ if (!modelName || !modelInfo || !litellmModelName) continue
+
+ models[modelName] = {
+ maxTokens: modelInfo.max_tokens || 8192,
+ contextWindow: modelInfo.max_input_tokens || 200000,
+ supportsImages: Boolean(modelInfo.supports_vision),
+ // litellm_params.model may have a prefix like openrouter/
+ supportsComputerUse: computerModels.some((computer_model) =>
+ litellmModelName.endsWith(computer_model),
+ ),
+ supportsPromptCache: Boolean(modelInfo.supports_prompt_caching),
+ inputPrice: modelInfo.input_cost_per_token ? modelInfo.input_cost_per_token * 1000000 : undefined,
+ outputPrice: modelInfo.output_cost_per_token
+ ? modelInfo.output_cost_per_token * 1000000
+ : undefined,
+ description: `${modelName} via LiteLLM proxy`,
+ }
+ }
+ }
+
+ return models
+ } catch (error) {
+ console.error("Error fetching LiteLLM models:", error)
+ return {}
+ }
+}
diff --git a/src/api/providers/fetchers/cache.ts b/src/api/providers/fetchers/modelCache.ts
similarity index 71%
rename from src/api/providers/fetchers/cache.ts
rename to src/api/providers/fetchers/modelCache.ts
index ab6dcce0210..9ab4b851fc5 100644
--- a/src/api/providers/fetchers/cache.ts
+++ b/src/api/providers/fetchers/modelCache.ts
@@ -12,6 +12,7 @@ import { getOpenRouterModels } from "./openrouter"
import { getRequestyModels } from "./requesty"
import { getGlamaModels } from "./glama"
import { getUnboundModels } from "./unbound"
+import { getLiteLLMModels } from "./litellm"
const memoryCache = new NodeCache({ stdTTL: 5 * 60, checkperiod: 5 * 60 })
@@ -36,9 +37,15 @@ async function readModels(router: RouterName): Promise
* 2. File cache - This is a file-based cache that is used to store models for a longer period of time.
*
* @param router - The router to fetch models from.
+ * @param apiKey - Optional API key for the provider.
+ * @param baseUrl - Optional base URL for the provider (currently used only for LiteLLM).
* @returns The models from the cache or the fetched models.
*/
-export const getModels = async (router: RouterName): Promise => {
+export const getModels = async (
+ router: RouterName,
+ apiKey: string | undefined = undefined,
+ baseUrl: string | undefined = undefined,
+): Promise => {
let models = memoryCache.get(router)
if (models) {
@@ -51,7 +58,8 @@ export const getModels = async (router: RouterName): Promise => {
models = await getOpenRouterModels()
break
case "requesty":
- models = await getRequestyModels()
+ // Requesty models endpoint requires an API key for per-user custom policies
+ models = await getRequestyModels(apiKey)
break
case "glama":
models = await getGlamaModels()
@@ -59,6 +67,13 @@ export const getModels = async (router: RouterName): Promise => {
case "unbound":
models = await getUnboundModels()
break
+ case "litellm":
+ if (apiKey && baseUrl) {
+ models = await getLiteLLMModels(apiKey, baseUrl)
+ } else {
+ models = {}
+ }
+ break
}
if (Object.keys(models).length > 0) {
@@ -68,7 +83,9 @@ export const getModels = async (router: RouterName): Promise => {
try {
await writeModels(router, models)
// console.log(`[getModels] wrote ${router} models to file cache`)
- } catch (error) {}
+ } catch (error) {
+ console.error(`[getModels] error writing ${router} models to file cache`, error)
+ }
return models
}
@@ -76,7 +93,17 @@ export const getModels = async (router: RouterName): Promise => {
try {
models = await readModels(router)
// console.log(`[getModels] read ${router} models from file cache`)
- } catch (error) {}
+ } catch (error) {
+ console.error(`[getModels] error reading ${router} models from file cache`, error)
+ }
return models ?? {}
}
+
+/**
+ * Flush models memory cache for a specific router
+ * @param router - The router to flush models for.
+ */
+export const flushModels = async (router: RouterName) => {
+ memoryCache.del(router)
+}
diff --git a/src/api/providers/fetchers/modelEndpointCache.ts b/src/api/providers/fetchers/modelEndpointCache.ts
new file mode 100644
index 00000000000..23c486e4204
--- /dev/null
+++ b/src/api/providers/fetchers/modelEndpointCache.ts
@@ -0,0 +1,82 @@
+import * as path from "path"
+import fs from "fs/promises"
+
+import NodeCache from "node-cache"
+import sanitize from "sanitize-filename"
+
+import { ContextProxy } from "../../../core/config/ContextProxy"
+import { getCacheDirectoryPath } from "../../../shared/storagePathManager"
+import { RouterName, ModelRecord } from "../../../shared/api"
+import { fileExistsAtPath } from "../../../utils/fs"
+
+import { getOpenRouterModelEndpoints } from "./openrouter"
+
+const memoryCache = new NodeCache({ stdTTL: 5 * 60, checkperiod: 5 * 60 })
+
+const getCacheKey = (router: RouterName, modelId: string) => sanitize(`${router}_${modelId}`)
+
+async function writeModelEndpoints(key: string, data: ModelRecord) {
+ const filename = `${key}_endpoints.json`
+ const cacheDir = await getCacheDirectoryPath(ContextProxy.instance.globalStorageUri.fsPath)
+ await fs.writeFile(path.join(cacheDir, filename), JSON.stringify(data, null, 2))
+}
+
+async function readModelEndpoints(key: string): Promise {
+ const filename = `${key}_endpoints.json`
+ const cacheDir = await getCacheDirectoryPath(ContextProxy.instance.globalStorageUri.fsPath)
+ const filePath = path.join(cacheDir, filename)
+ const exists = await fileExistsAtPath(filePath)
+ return exists ? JSON.parse(await fs.readFile(filePath, "utf8")) : undefined
+}
+
+export const getModelEndpoints = async ({
+ router,
+ modelId,
+ endpoint,
+}: {
+ router: RouterName
+ modelId?: string
+ endpoint?: string
+}): Promise => {
+ // OpenRouter is the only provider that supports model endpoints, but you
+ // can see how we'd extend this to other providers in the future.
+ if (router !== "openrouter" || !modelId || !endpoint) {
+ return {}
+ }
+
+ const key = getCacheKey(router, modelId)
+ let modelProviders = memoryCache.get(key)
+
+ if (modelProviders) {
+ // console.log(`[getModelProviders] NodeCache hit for ${key} -> ${Object.keys(modelProviders).length}`)
+ return modelProviders
+ }
+
+ modelProviders = await getOpenRouterModelEndpoints(modelId)
+
+ if (Object.keys(modelProviders).length > 0) {
+ // console.log(`[getModelProviders] API fetch for ${key} -> ${Object.keys(modelProviders).length}`)
+ memoryCache.set(key, modelProviders)
+
+ try {
+ await writeModelEndpoints(key, modelProviders)
+ // console.log(`[getModelProviders] wrote ${key} endpoints to file cache`)
+ } catch (error) {
+ console.error(`[getModelProviders] error writing ${key} endpoints to file cache`, error)
+ }
+
+ return modelProviders
+ }
+
+ try {
+ modelProviders = await readModelEndpoints(router)
+ // console.log(`[getModelProviders] read ${key} endpoints from file cache`)
+ } catch (error) {
+ console.error(`[getModelProviders] error reading ${key} endpoints from file cache`, error)
+ }
+
+ return modelProviders ?? {}
+}
+
+export const flushModelProviders = async (router: RouterName, modelId: string) =>
+ memoryCache.del(getCacheKey(router, modelId))
diff --git a/src/api/providers/fetchers/openrouter.ts b/src/api/providers/fetchers/openrouter.ts
index db0ac5a0cab..f8e605aa08f 100644
--- a/src/api/providers/fetchers/openrouter.ts
+++ b/src/api/providers/fetchers/openrouter.ts
@@ -1,51 +1,87 @@
import axios from "axios"
import { z } from "zod"
-import {
- ApiHandlerOptions,
- ModelInfo,
- anthropicModels,
- COMPUTER_USE_MODELS,
- OPTIONAL_PROMPT_CACHING_MODELS,
-} from "../../../shared/api"
+import { ApiHandlerOptions, ModelInfo, anthropicModels, COMPUTER_USE_MODELS } from "../../../shared/api"
import { parseApiPrice } from "../../../utils/cost"
-// https://openrouter.ai/api/v1/models
-export const openRouterModelSchema = z.object({
- id: z.string(),
+/**
+ * OpenRouterBaseModel
+ */
+
+const openRouterArchitectureSchema = z.object({
+ modality: z.string().nullish(),
+ tokenizer: z.string().nullish(),
+})
+
+const openRouterPricingSchema = z.object({
+ prompt: z.string().nullish(),
+ completion: z.string().nullish(),
+ input_cache_write: z.string().nullish(),
+ input_cache_read: z.string().nullish(),
+})
+
+const modelRouterBaseModelSchema = z.object({
name: z.string(),
description: z.string().optional(),
context_length: z.number(),
max_completion_tokens: z.number().nullish(),
- architecture: z
- .object({
- modality: z.string().nullish(),
- tokenizer: z.string().nullish(),
- })
- .optional(),
- pricing: z
- .object({
- prompt: z.string().nullish(),
- completion: z.string().nullish(),
- input_cache_write: z.string().nullish(),
- input_cache_read: z.string().nullish(),
- })
- .optional(),
- top_provider: z
- .object({
- max_completion_tokens: z.number().nullish(),
- })
- .optional(),
+ pricing: openRouterPricingSchema.optional(),
+})
+
+export type OpenRouterBaseModel = z.infer
+
+/**
+ * OpenRouterModel
+ */
+
+export const openRouterModelSchema = modelRouterBaseModelSchema.extend({
+ id: z.string(),
+ architecture: openRouterArchitectureSchema.optional(),
+ top_provider: z.object({ max_completion_tokens: z.number().nullish() }).optional(),
})
export type OpenRouterModel = z.infer
+/**
+ * OpenRouterModelEndpoint
+ */
+
+export const openRouterModelEndpointSchema = modelRouterBaseModelSchema.extend({
+ provider_name: z.string(),
+})
+
+export type OpenRouterModelEndpoint = z.infer
+
+/**
+ * OpenRouterModelsResponse
+ */
+
const openRouterModelsResponseSchema = z.object({
data: z.array(openRouterModelSchema),
})
type OpenRouterModelsResponse = z.infer
+/**
+ * OpenRouterModelEndpointsResponse
+ */
+
+const openRouterModelEndpointsResponseSchema = z.object({
+ data: z.object({
+ id: z.string(),
+ name: z.string(),
+ description: z.string().optional(),
+ architecture: openRouterArchitectureSchema.optional(),
+ endpoints: z.array(openRouterModelEndpointSchema),
+ }),
+})
+
+type OpenRouterModelEndpointsResponse = z.infer
+
+/**
+ * getOpenRouterModels
+ */
+
export async function getOpenRouterModels(options?: ApiHandlerOptions): Promise> {
const models: Record = {}
const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1"
@@ -53,59 +89,21 @@ export async function getOpenRouterModels(options?: ApiHandlerOptions): Promise<
try {
const response = await axios.get(`${baseURL}/models`)
const result = openRouterModelsResponseSchema.safeParse(response.data)
- const rawModels = result.success ? result.data.data : response.data.data
+ const data = result.success ? result.data.data : response.data.data
if (!result.success) {
console.error("OpenRouter models response is invalid", result.error.format())
}
- for (const rawModel of rawModels) {
- const cacheWritesPrice = rawModel.pricing?.input_cache_write
- ? parseApiPrice(rawModel.pricing?.input_cache_write)
- : undefined
-
- const cacheReadsPrice = rawModel.pricing?.input_cache_read
- ? parseApiPrice(rawModel.pricing?.input_cache_read)
- : undefined
-
- const supportsPromptCache =
- typeof cacheWritesPrice !== "undefined" && typeof cacheReadsPrice !== "undefined"
-
- const modelInfo: ModelInfo = {
- maxTokens: rawModel.top_provider?.max_completion_tokens,
- contextWindow: rawModel.context_length,
- supportsImages: rawModel.architecture?.modality?.includes("image"),
- supportsPromptCache,
- inputPrice: parseApiPrice(rawModel.pricing?.prompt),
- outputPrice: parseApiPrice(rawModel.pricing?.completion),
- cacheWritesPrice,
- cacheReadsPrice,
- description: rawModel.description,
- thinking: rawModel.id === "anthropic/claude-3.7-sonnet:thinking",
- }
-
- // The OpenRouter model definition doesn't give us any hints about
- // computer use, so we need to set that manually.
- if (COMPUTER_USE_MODELS.has(rawModel.id)) {
- modelInfo.supportsComputerUse = true
- }
-
- // We want to treat prompt caching as "experimental" for these models.
- if (OPTIONAL_PROMPT_CACHING_MODELS.has(rawModel.id)) {
- modelInfo.isPromptCacheOptional = true
- }
-
- // Claude 3.7 Sonnet is a "hybrid" thinking model, and the `maxTokens`
- // values can be configured. For the non-thinking variant we want to
- // use 8k. The `thinking` variant can be run in 64k and 128k modes,
- // and we want to use 128k.
- if (rawModel.id.startsWith("anthropic/claude-3.7-sonnet")) {
- modelInfo.maxTokens = rawModel.id.includes("thinking")
- ? anthropicModels["claude-3-7-sonnet-20250219:thinking"].maxTokens
- : anthropicModels["claude-3-7-sonnet-20250219"].maxTokens
- }
-
- models[rawModel.id] = modelInfo
+ for (const model of data) {
+ const { id, architecture, top_provider } = model
+
+ models[id] = parseOpenRouterModel({
+ id,
+ model,
+ modality: architecture?.modality,
+ maxTokens: id.startsWith("anthropic/") ? top_provider?.max_completion_tokens : 0,
+ })
}
} catch (error) {
console.error(
@@ -115,3 +113,97 @@ export async function getOpenRouterModels(options?: ApiHandlerOptions): Promise<
return models
}
+
+/**
+ * getOpenRouterModelEndpoints
+ */
+
+export async function getOpenRouterModelEndpoints(
+ modelId: string,
+ options?: ApiHandlerOptions,
+): Promise> {
+ const models: Record = {}
+ const baseURL = options?.openRouterBaseUrl || "https://openrouter.ai/api/v1"
+
+ try {
+ const response = await axios.get(`${baseURL}/models/${modelId}/endpoints`)
+ const result = openRouterModelEndpointsResponseSchema.safeParse(response.data)
+ const data = result.success ? result.data.data : response.data.data
+
+ if (!result.success) {
+ console.error("OpenRouter model endpoints response is invalid", result.error.format())
+ }
+
+ const { id, architecture, endpoints } = data
+
+ for (const endpoint of endpoints) {
+ models[endpoint.provider_name] = parseOpenRouterModel({
+ id,
+ model: endpoint,
+ modality: architecture?.modality,
+ maxTokens: id.startsWith("anthropic/") ? endpoint.max_completion_tokens : 0,
+ })
+ }
+ } catch (error) {
+ console.error(
+ `Error fetching OpenRouter model endpoints: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
+ )
+ }
+
+ return models
+}
+
+/**
+ * parseOpenRouterModel
+ */
+
+export const parseOpenRouterModel = ({
+ id,
+ model,
+ modality,
+ maxTokens,
+}: {
+ id: string
+ model: OpenRouterBaseModel
+ modality: string | null | undefined
+ maxTokens: number | null | undefined
+}): ModelInfo => {
+ const cacheWritesPrice = model.pricing?.input_cache_write
+ ? parseApiPrice(model.pricing?.input_cache_write)
+ : undefined
+
+ const cacheReadsPrice = model.pricing?.input_cache_read ? parseApiPrice(model.pricing?.input_cache_read) : undefined
+
+ const supportsPromptCache = typeof cacheWritesPrice !== "undefined" && typeof cacheReadsPrice !== "undefined"
+
+ const modelInfo: ModelInfo = {
+ maxTokens: maxTokens || 0,
+ contextWindow: model.context_length,
+ supportsImages: modality?.includes("image") ?? false,
+ supportsPromptCache,
+ inputPrice: parseApiPrice(model.pricing?.prompt),
+ outputPrice: parseApiPrice(model.pricing?.completion),
+ cacheWritesPrice,
+ cacheReadsPrice,
+ description: model.description,
+ thinking: id === "anthropic/claude-3.7-sonnet:thinking",
+ }
+
+ // The OpenRouter model definition doesn't give us any hints about
+ // computer use, so we need to set that manually.
+ if (COMPUTER_USE_MODELS.has(id)) {
+ modelInfo.supportsComputerUse = true
+ }
+
+ // Claude 3.7 Sonnet is a "hybrid" thinking model, and the `maxTokens`
+ // values can be configured. For the non-thinking variant we want to
+ // use 8k. The `thinking` variant can be run in 64k and 128k modes,
+ // and we want to use 128k.
+ if (id.startsWith("anthropic/claude-3.7-sonnet")) {
+ modelInfo.maxTokens = id.includes("thinking")
+ ? anthropicModels["claude-3-7-sonnet-20250219:thinking"].maxTokens
+ : anthropicModels["claude-3-7-sonnet-20250219"].maxTokens
+ }
+
+ return modelInfo
+}
diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts
index 5e9db97afea..d519d5e6295 100644
--- a/src/api/providers/gemini.ts
+++ b/src/api/providers/gemini.ts
@@ -3,32 +3,18 @@ import {
GoogleGenAI,
type GenerateContentResponseUsageMetadata,
type GenerateContentParameters,
- type Content,
+ type GenerateContentConfig,
} from "@google/genai"
import type { JWTInput } from "google-auth-library"
-import NodeCache from "node-cache"
import { ApiHandlerOptions, ModelInfo, GeminiModelId, geminiDefaultModelId, geminiModels } from "../../shared/api"
import { safeJsonParse } from "../../shared/safeJsonParse"
import { SingleCompletionHandler } from "../index"
-import {
- convertAnthropicContentToGemini,
- convertAnthropicMessageToGemini,
- getMessagesLength,
-} from "../transform/gemini-format"
+import { convertAnthropicContentToGemini, convertAnthropicMessageToGemini } from "../transform/gemini-format"
import type { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
-const CACHE_TTL = 5
-
-const CONTEXT_CACHE_TOKEN_MINIMUM = 4096
-
-type CacheEntry = {
- key: string
- count: number
-}
-
type GeminiHandlerOptions = ApiHandlerOptions & {
isVertex?: boolean
}
@@ -37,8 +23,6 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
protected options: ApiHandlerOptions
private client: GoogleGenAI
- private contentCaches: NodeCache
- private isCacheBusy = false
constructor({ isVertex, ...options }: GeminiHandlerOptions) {
super()
@@ -68,98 +52,22 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
: isVertex
? new GoogleGenAI({ vertexai: true, project, location })
: new GoogleGenAI({ apiKey })
-
- this.contentCaches = new NodeCache({ stdTTL: 5 * 60, checkperiod: 5 * 60 })
}
- async *createMessage(
- systemInstruction: string,
- messages: Anthropic.Messages.MessageParam[],
- cacheKey?: string,
- ): ApiStream {
+ async *createMessage(systemInstruction: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
const { id: model, thinkingConfig, maxOutputTokens, info } = this.getModel()
const contents = messages.map(convertAnthropicMessageToGemini)
- const contentsLength = systemInstruction.length + getMessagesLength(contents)
-
- let uncachedContent: Content[] | undefined = undefined
- let cachedContent: string | undefined = undefined
-
- // The minimum input token count for context caching is 4,096.
- // For a basic approximation we assume 4 characters per token.
- // We can use tiktoken eventually to get a more accurat token count.
- // https://ai.google.dev/gemini-api/docs/caching?lang=node
- // https://ai.google.dev/gemini-api/docs/tokens?lang=node
- const isCacheAvailable =
- info.supportsPromptCache &&
- this.options.promptCachingEnabled &&
- cacheKey &&
- contentsLength > 4 * CONTEXT_CACHE_TOKEN_MINIMUM
-
- let cacheWrite = false
-
- if (isCacheAvailable) {
- const cacheEntry = this.contentCaches.get(cacheKey)
-
- if (cacheEntry) {
- uncachedContent = contents.slice(cacheEntry.count, contents.length)
- cachedContent = cacheEntry.key
- console.log(
- `[GeminiHandler] using ${cacheEntry.count} cached messages (${cacheEntry.key}) and ${uncachedContent.length} uncached messages`,
- )
- }
- if (!this.isCacheBusy) {
- this.isCacheBusy = true
- const timestamp = Date.now()
-
- this.client.caches
- .create({
- model,
- config: {
- contents,
- systemInstruction,
- ttl: `${CACHE_TTL * 60}s`,
- httpOptions: { timeout: 120_000 },
- },
- })
- .then((result) => {
- const { name, usageMetadata } = result
-
- if (name) {
- this.contentCaches.set(cacheKey, { key: name, count: contents.length })
- console.log(
- `[GeminiHandler] cached ${contents.length} messages (${usageMetadata?.totalTokenCount ?? "-"} tokens) in ${Date.now() - timestamp}ms`,
- )
- }
- })
- .catch((error) => {
- console.error(`[GeminiHandler] caches.create error`, error)
- })
- .finally(() => {
- this.isCacheBusy = false
- })
-
- cacheWrite = true
- }
+ const config: GenerateContentConfig = {
+ systemInstruction,
+ httpOptions: this.options.googleGeminiBaseUrl ? { baseUrl: this.options.googleGeminiBaseUrl } : undefined,
+ thinkingConfig,
+ maxOutputTokens,
+ temperature: this.options.modelTemperature ?? 0,
}
- const isCacheUsed = !!cachedContent
-
- const params: GenerateContentParameters = {
- model,
- contents: uncachedContent ?? contents,
- config: {
- cachedContent,
- systemInstruction: isCacheUsed ? undefined : systemInstruction,
- httpOptions: this.options.googleGeminiBaseUrl
- ? { baseUrl: this.options.googleGeminiBaseUrl }
- : undefined,
- thinkingConfig,
- maxOutputTokens,
- temperature: this.options.modelTemperature ?? 0,
- },
- }
+ const params: GenerateContentParameters = { model, contents, config }
const result = await this.client.models.generateContentStream(params)
@@ -178,7 +86,6 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
if (lastUsageMetadata) {
const inputTokens = lastUsageMetadata.promptTokenCount ?? 0
const outputTokens = lastUsageMetadata.candidatesTokenCount ?? 0
- const cacheWriteTokens = cacheWrite ? inputTokens : undefined
const cacheReadTokens = lastUsageMetadata.cachedContentTokenCount
const reasoningTokens = lastUsageMetadata.thoughtsTokenCount
@@ -186,16 +93,9 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
type: "usage",
inputTokens,
outputTokens,
- cacheWriteTokens,
cacheReadTokens,
reasoningTokens,
- totalCost: this.calculateCost({
- info,
- inputTokens,
- outputTokens,
- cacheWriteTokens,
- cacheReadTokens,
- }),
+ totalCost: this.calculateCost({ info, inputTokens, outputTokens, cacheReadTokens }),
}
}
}
@@ -279,22 +179,19 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
info,
inputTokens,
outputTokens,
- cacheWriteTokens = 0,
cacheReadTokens = 0,
}: {
info: ModelInfo
inputTokens: number
outputTokens: number
- cacheWriteTokens?: number
cacheReadTokens?: number
}) {
- if (!info.inputPrice || !info.outputPrice || !info.cacheWritesPrice || !info.cacheReadsPrice) {
+ if (!info.inputPrice || !info.outputPrice || !info.cacheReadsPrice) {
return undefined
}
let inputPrice = info.inputPrice
let outputPrice = info.outputPrice
- let cacheWritesPrice = info.cacheWritesPrice
let cacheReadsPrice = info.cacheReadsPrice
// If there's tiered pricing then adjust the input and output token prices
@@ -305,7 +202,6 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
if (tier) {
inputPrice = tier.inputPrice ?? inputPrice
outputPrice = tier.outputPrice ?? outputPrice
- cacheWritesPrice = tier.cacheWritesPrice ?? cacheWritesPrice
cacheReadsPrice = tier.cacheReadsPrice ?? cacheReadsPrice
}
}
@@ -313,23 +209,17 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
// Subtract the cached input tokens from the total input tokens.
const uncachedInputTokens = inputTokens - cacheReadTokens
- let cacheWriteCost =
- cacheWriteTokens > 0 ? cacheWritesPrice * (cacheWriteTokens / 1_000_000) * (CACHE_TTL / 60) : 0
let cacheReadCost = cacheReadTokens > 0 ? cacheReadsPrice * (cacheReadTokens / 1_000_000) : 0
const inputTokensCost = inputPrice * (uncachedInputTokens / 1_000_000)
const outputTokensCost = outputPrice * (outputTokens / 1_000_000)
- const totalCost = inputTokensCost + outputTokensCost + cacheWriteCost + cacheReadCost
+ const totalCost = inputTokensCost + outputTokensCost + cacheReadCost
const trace: Record = {
input: { price: inputPrice, tokens: uncachedInputTokens, cost: inputTokensCost },
output: { price: outputPrice, tokens: outputTokens, cost: outputTokensCost },
}
- if (cacheWriteTokens > 0) {
- trace.cacheWrite = { price: cacheWritesPrice, tokens: cacheWriteTokens, cost: cacheWriteCost }
- }
-
if (cacheReadTokens > 0) {
trace.cacheRead = { price: cacheReadsPrice, tokens: cacheReadTokens, cost: cacheReadCost }
}
diff --git a/src/api/providers/groq.ts b/src/api/providers/groq.ts
new file mode 100644
index 00000000000..2f4e763b8e5
--- /dev/null
+++ b/src/api/providers/groq.ts
@@ -0,0 +1,17 @@
+import { ApiHandlerOptions, GroqModelId, groqDefaultModelId, groqModels } from "../../shared/api" // Updated imports for Groq
+
+import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
+
+export class GroqHandler extends BaseOpenAiCompatibleProvider {
+ constructor(options: ApiHandlerOptions) {
+ super({
+ ...options,
+ providerName: "Groq",
+ baseURL: "https://api.groq.com/openai/v1",
+ apiKey: options.groqApiKey,
+ defaultProviderModelId: groqDefaultModelId,
+ providerModels: groqModels,
+ defaultTemperature: 0.5,
+ })
+ }
+}
diff --git a/src/api/providers/litellm.ts b/src/api/providers/litellm.ts
new file mode 100644
index 00000000000..be88ede5f60
--- /dev/null
+++ b/src/api/providers/litellm.ts
@@ -0,0 +1,113 @@
+import OpenAI from "openai"
+import { Anthropic } from "@anthropic-ai/sdk" // Keep for type usage only
+
+import { ApiHandlerOptions, litellmDefaultModelId, litellmDefaultModelInfo } from "../../shared/api"
+import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
+import { convertToOpenAiMessages } from "../transform/openai-format"
+import { SingleCompletionHandler } from "../index"
+import { RouterProvider } from "./router-provider"
+
+/**
+ * LiteLLM provider handler
+ *
+ * This handler uses the LiteLLM API to proxy requests to various LLM providers.
+ * It follows the OpenAI API format for compatibility.
+ */
+export class LiteLLMHandler extends RouterProvider implements SingleCompletionHandler {
+ constructor(options: ApiHandlerOptions) {
+ super({
+ options,
+ name: "litellm",
+ baseURL: `${options.litellmBaseUrl || "http://localhost:4000"}`,
+ apiKey: options.litellmApiKey || "dummy-key",
+ modelId: options.litellmModelId,
+ defaultModelId: litellmDefaultModelId,
+ defaultModelInfo: litellmDefaultModelInfo,
+ })
+ }
+
+ override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ const { id: modelId, info } = await this.fetchModel()
+
+ const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
+ { role: "system", content: systemPrompt },
+ ...convertToOpenAiMessages(messages),
+ ]
+
+ // Required by some providers; others default to max tokens allowed
+ let maxTokens: number | undefined = info.maxTokens ?? undefined
+
+ const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
+ model: modelId,
+ max_tokens: maxTokens,
+ messages: openAiMessages,
+ stream: true,
+ stream_options: {
+ include_usage: true,
+ },
+ }
+
+ if (this.supportsTemperature(modelId)) {
+ requestOptions.temperature = this.options.modelTemperature ?? 0
+ }
+
+ try {
+ const { data: completion } = await this.client.chat.completions.create(requestOptions).withResponse()
+
+ let lastUsage
+
+ for await (const chunk of completion) {
+ const delta = chunk.choices[0]?.delta
+ const usage = chunk.usage as OpenAI.CompletionUsage
+
+ if (delta?.content) {
+ yield { type: "text", text: delta.content }
+ }
+
+ if (usage) {
+ lastUsage = usage
+ }
+ }
+
+ if (lastUsage) {
+ const usageData: ApiStreamUsageChunk = {
+ type: "usage",
+ inputTokens: lastUsage.prompt_tokens || 0,
+ outputTokens: lastUsage.completion_tokens || 0,
+ }
+
+ yield usageData
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new Error(`LiteLLM streaming error: ${error.message}`)
+ }
+ throw error
+ }
+ }
+
+ async completePrompt(prompt: string): Promise {
+ const { id: modelId, info } = await this.fetchModel()
+
+ try {
+ const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
+ model: modelId,
+ messages: [{ role: "user", content: prompt }],
+ }
+
+ if (this.supportsTemperature(modelId)) {
+ requestOptions.temperature = this.options.modelTemperature ?? 0
+ }
+
+ requestOptions.max_tokens = info.maxTokens
+
+ const response = await this.client.chat.completions.create(requestOptions)
+ return response.choices[0]?.message.content || ""
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new Error(`LiteLLM completion error: ${error.message}`)
+ }
+ throw error
+ }
+ }
+}
diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts
index e1104f4f9a5..2d9c7f8b8a4 100644
--- a/src/api/providers/openrouter.ts
+++ b/src/api/providers/openrouter.ts
@@ -8,7 +8,6 @@ import {
openRouterDefaultModelId,
openRouterDefaultModelInfo,
PROMPT_CACHING_MODELS,
- OPTIONAL_PROMPT_CACHING_MODELS,
REASONING_MODELS,
} from "../../shared/api"
@@ -21,7 +20,8 @@ import { addCacheBreakpoints as addGeminiCacheBreakpoints } from "../transform/c
import { getModelParams, SingleCompletionHandler } from "../index"
import { DEFAULT_HEADERS, DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants"
import { BaseProvider } from "./base-provider"
-import { getModels } from "./fetchers/cache"
+import { getModels } from "./fetchers/modelCache"
+import { getModelEndpoints } from "./fetchers/modelEndpointCache"
const OPENROUTER_DEFAULT_PROVIDER_NAME = "[default]"
@@ -58,6 +58,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
protected options: ApiHandlerOptions
private client: OpenAI
protected models: ModelRecord = {}
+ protected endpoints: ModelRecord = {}
constructor(options: ApiHandlerOptions) {
super()
@@ -94,7 +95,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
}
- const isCacheAvailable = promptCache.supported && (!promptCache.optional || this.options.promptCachingEnabled)
+ const isCacheAvailable = promptCache.supported
// https://openrouter.ai/docs/features/prompt-caching
if (isCacheAvailable) {
@@ -106,7 +107,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
// https://openrouter.ai/docs/transforms
const completionParams: OpenRouterChatCompletionParams = {
model: modelId,
- max_tokens: maxTokens,
+ ...(maxTokens && maxTokens > 0 && { max_tokens: maxTokens }),
temperature,
thinking, // OpenRouter is temporarily supporting this.
top_p: topP,
@@ -116,7 +117,11 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
// Only include provider if openRouterSpecificProvider is not "[default]".
...(this.options.openRouterSpecificProvider &&
this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME && {
- provider: { order: [this.options.openRouterSpecificProvider] },
+ provider: {
+ order: [this.options.openRouterSpecificProvider],
+ only: [this.options.openRouterSpecificProvider],
+ allow_fallbacks: false,
+ },
}),
// This way, the transforms field will only be included in the parameters when openRouterUseMiddleOutTransform is true.
...((this.options.openRouterUseMiddleOutTransform ?? true) && { transforms: ["middle-out"] }),
@@ -165,13 +170,29 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
}
public async fetchModel() {
- this.models = await getModels("openrouter")
+ const [models, endpoints] = await Promise.all([
+ getModels("openrouter"),
+ getModelEndpoints({
+ router: "openrouter",
+ modelId: this.options.openRouterModelId,
+ endpoint: this.options.openRouterSpecificProvider,
+ }),
+ ])
+
+ this.models = models
+ this.endpoints = endpoints
+
return this.getModel()
}
override getModel() {
const id = this.options.openRouterModelId ?? openRouterDefaultModelId
- const info = this.models[id] ?? openRouterDefaultModelInfo
+ let info = this.models[id] ?? openRouterDefaultModelInfo
+
+ // If a specific provider is requested, use the endpoint for that provider.
+ if (this.options.openRouterSpecificProvider && this.endpoints[this.options.openRouterSpecificProvider]) {
+ info = this.endpoints[this.options.openRouterSpecificProvider]
+ }
const isDeepSeekR1 = id.startsWith("deepseek/deepseek-r1") || id === "perplexity/sonar-reasoning"
@@ -187,7 +208,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
topP: isDeepSeekR1 ? 0.95 : undefined,
promptCache: {
supported: PROMPT_CACHING_MODELS.has(id),
- optional: OPTIONAL_PROMPT_CACHING_MODELS.has(id),
},
}
}
@@ -202,6 +222,15 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
temperature,
messages: [{ role: "user", content: prompt }],
stream: false,
+ // Only include provider if openRouterSpecificProvider is not "[default]".
+ ...(this.options.openRouterSpecificProvider &&
+ this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME && {
+ provider: {
+ order: [this.options.openRouterSpecificProvider],
+ only: [this.options.openRouterSpecificProvider],
+ allow_fallbacks: false,
+ },
+ }),
}
const response = await this.client.chat.completions.create(completionParams)
diff --git a/src/api/providers/requesty.ts b/src/api/providers/requesty.ts
index 9fe976bb51c..fe8bba7e6ec 100644
--- a/src/api/providers/requesty.ts
+++ b/src/api/providers/requesty.ts
@@ -1,11 +1,19 @@
import { Anthropic } from "@anthropic-ai/sdk"
-import OpenAI from "openai"
-
-import { ModelInfo, ModelRecord, requestyDefaultModelId, requestyDefaultModelInfo } from "../../shared/api"
+import {
+ ApiHandlerOptions,
+ ModelInfo,
+ ModelRecord,
+ requestyDefaultModelId,
+ requestyDefaultModelInfo,
+} from "../../shared/api"
+import { convertToOpenAiMessages } from "../transform/openai-format"
import { calculateApiCostOpenAI } from "../../utils/cost"
import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
-import { OpenAiHandler, OpenAiHandlerOptions } from "./openai"
-import { getModels } from "./fetchers/cache"
+import { SingleCompletionHandler } from "../"
+import { BaseProvider } from "./base-provider"
+import { DEFAULT_HEADERS } from "./constants"
+import { getModels } from "./fetchers/modelCache"
+import OpenAI from "openai"
// Requesty usage includes an extra field for Anthropic use cases.
// Safely cast the prompt token details section to the appropriate structure.
@@ -17,25 +25,28 @@ interface RequestyUsage extends OpenAI.CompletionUsage {
total_cost?: number
}
-export class RequestyHandler extends OpenAiHandler {
+type RequestyChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParams & {}
+
+export class RequestyHandler extends BaseProvider implements SingleCompletionHandler {
+ protected options: ApiHandlerOptions
protected models: ModelRecord = {}
+ private client: OpenAI
- constructor(options: OpenAiHandlerOptions) {
- if (!options.requestyApiKey) {
- throw new Error("Requesty API key is required. Please provide it in the settings.")
- }
+ constructor(options: ApiHandlerOptions) {
+ super()
+ this.options = options
- super({
- ...options,
- openAiApiKey: options.requestyApiKey,
- openAiModelId: options.requestyModelId ?? requestyDefaultModelId,
- openAiBaseUrl: "https://router.requesty.ai/v1",
- })
+ const apiKey = this.options.requestyApiKey ?? "not-provided"
+ const baseURL = "https://router.requesty.ai/v1"
+
+ const defaultHeaders = DEFAULT_HEADERS
+
+ this.client = new OpenAI({ baseURL, apiKey, defaultHeaders })
}
- override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ public async fetchModel() {
this.models = await getModels("requesty")
- yield* super.createMessage(systemPrompt, messages)
+ return this.getModel()
}
override getModel(): { id: string; info: ModelInfo } {
@@ -44,7 +55,7 @@ export class RequestyHandler extends OpenAiHandler {
return { id, info }
}
- protected override processUsageMetrics(usage: any, modelInfo?: ModelInfo): ApiStreamUsageChunk {
+ protected processUsageMetrics(usage: any, modelInfo?: ModelInfo): ApiStreamUsageChunk {
const requestyUsage = usage as RequestyUsage
const inputTokens = requestyUsage?.prompt_tokens || 0
const outputTokens = requestyUsage?.completion_tokens || 0
@@ -64,8 +75,80 @@ export class RequestyHandler extends OpenAiHandler {
}
}
- override async completePrompt(prompt: string): Promise {
- this.models = await getModels("requesty")
- return super.completePrompt(prompt)
+ override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ const model = await this.fetchModel()
+
+ let openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
+ { role: "system", content: systemPrompt },
+ ...convertToOpenAiMessages(messages),
+ ]
+
+ let maxTokens = undefined
+ if (this.options.includeMaxTokens) {
+ maxTokens = model.info.maxTokens
+ }
+
+ const temperature = this.options.modelTemperature
+
+ const completionParams: RequestyChatCompletionParams = {
+ model: model.id,
+ max_tokens: maxTokens,
+ messages: openAiMessages,
+ temperature: temperature,
+ stream: true,
+ stream_options: { include_usage: true },
+ }
+
+ const stream = await this.client.chat.completions.create(completionParams)
+
+ let lastUsage: any = undefined
+
+ for await (const chunk of stream) {
+ const delta = chunk.choices[0]?.delta
+ if (delta?.content) {
+ yield {
+ type: "text",
+ text: delta.content,
+ }
+ }
+
+ if (delta && "reasoning_content" in delta && delta.reasoning_content) {
+ yield {
+ type: "reasoning",
+ text: (delta.reasoning_content as string | undefined) || "",
+ }
+ }
+
+ if (chunk.usage) {
+ lastUsage = chunk.usage
+ }
+ }
+
+ if (lastUsage) {
+ yield this.processUsageMetrics(lastUsage, model.info)
+ }
+ }
+
+ async completePrompt(prompt: string): Promise {
+ const model = await this.fetchModel()
+
+ let openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [{ role: "system", content: prompt }]
+
+ let maxTokens = undefined
+ if (this.options.includeMaxTokens) {
+ maxTokens = model.info.maxTokens
+ }
+
+ const temperature = this.options.modelTemperature
+
+ const completionParams: RequestyChatCompletionParams = {
+ model: model.id,
+ max_tokens: maxTokens,
+ messages: openAiMessages,
+ temperature: temperature,
+ }
+
+ const response: OpenAI.Chat.ChatCompletion = await this.client.chat.completions.create(completionParams)
+ return response.choices[0]?.message.content || ""
}
}
diff --git a/src/api/providers/router-provider.ts b/src/api/providers/router-provider.ts
index 5b680b1b1d0..a0decdcab41 100644
--- a/src/api/providers/router-provider.ts
+++ b/src/api/providers/router-provider.ts
@@ -2,7 +2,7 @@ import OpenAI from "openai"
import { ApiHandlerOptions, RouterName, ModelRecord, ModelInfo } from "../../shared/api"
import { BaseProvider } from "./base-provider"
-import { getModels } from "./fetchers/cache"
+import { getModels } from "./fetchers/modelCache"
type RouterProviderOptions = {
name: RouterName
@@ -44,7 +44,7 @@ export abstract class RouterProvider extends BaseProvider {
}
public async fetchModel() {
- this.models = await getModels(this.name)
+ this.models = await getModels(this.name, this.client.apiKey, this.client.baseURL)
return this.getModel()
}
diff --git a/src/api/transform/__tests__/image-cleaning.test.ts b/src/api/transform/__tests__/image-cleaning.test.ts
new file mode 100644
index 00000000000..cbb318531a1
--- /dev/null
+++ b/src/api/transform/__tests__/image-cleaning.test.ts
@@ -0,0 +1,336 @@
+import { ApiHandler } from "../.."
+import { ApiMessage } from "../../../core/task-persistence/apiMessages"
+import { maybeRemoveImageBlocks } from "../image-cleaning"
+import { ModelInfo } from "../../../shared/api"
+
+describe("maybeRemoveImageBlocks", () => {
+ // Mock ApiHandler factory function
+ const createMockApiHandler = (supportsImages: boolean): ApiHandler => {
+ return {
+ getModel: jest.fn().mockReturnValue({
+ id: "test-model",
+ info: {
+ supportsImages,
+ } as ModelInfo,
+ }),
+ createMessage: jest.fn(),
+ countTokens: jest.fn(),
+ }
+ }
+
+ it("should handle empty messages array", () => {
+ const apiHandler = createMockApiHandler(true)
+ const messages: ApiMessage[] = []
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ expect(result).toEqual([])
+ // No need to check if getModel was called since there are no messages to process
+ })
+
+ it("should not modify messages with no image blocks", () => {
+ const apiHandler = createMockApiHandler(true)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: "Hello, world!",
+ },
+ {
+ role: "assistant",
+ content: "Hi there!",
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ expect(result).toEqual(messages)
+ // getModel is only called when content is an array, which is not the case here
+ })
+
+ it("should not modify messages with array content but no image blocks", () => {
+ const apiHandler = createMockApiHandler(true)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Hello, world!",
+ },
+ {
+ type: "text",
+ text: "How are you?",
+ },
+ ],
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ expect(result).toEqual(messages)
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+
+ it("should not modify image blocks when API handler supports images", () => {
+ const apiHandler = createMockApiHandler(true)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Check out this image:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/jpeg",
+ data: "base64-encoded-image-data",
+ },
+ },
+ ],
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ // Should not modify the messages since the API handler supports images
+ expect(result).toEqual(messages)
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+
+ it("should convert image blocks to text descriptions when API handler doesn't support images", () => {
+ const apiHandler = createMockApiHandler(false)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Check out this image:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/jpeg",
+ data: "base64-encoded-image-data",
+ },
+ },
+ ],
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ // Should convert image blocks to text descriptions
+ expect(result).toEqual([
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Check out this image:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ ],
+ },
+ ])
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+
+ it("should handle mixed content messages with multiple text and image blocks", () => {
+ const apiHandler = createMockApiHandler(false)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here are some images:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/jpeg",
+ data: "image-data-1",
+ },
+ },
+ {
+ type: "text",
+ text: "And another one:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/png",
+ data: "image-data-2",
+ },
+ },
+ ],
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ // Should convert all image blocks to text descriptions
+ expect(result).toEqual([
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here are some images:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ {
+ type: "text",
+ text: "And another one:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ ],
+ },
+ ])
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+
+ it("should handle multiple messages with image blocks", () => {
+ const apiHandler = createMockApiHandler(false)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's an image:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/jpeg",
+ data: "image-data-1",
+ },
+ },
+ ],
+ },
+ {
+ role: "assistant",
+ content: "I see the image!",
+ },
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's another image:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/png",
+ data: "image-data-2",
+ },
+ },
+ ],
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ // Should convert all image blocks to text descriptions
+ expect(result).toEqual([
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's an image:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ ],
+ },
+ {
+ role: "assistant",
+ content: "I see the image!",
+ },
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's another image:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ ],
+ },
+ ])
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+
+ it("should preserve additional message properties", () => {
+ const apiHandler = createMockApiHandler(false)
+ const messages: ApiMessage[] = [
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's an image:",
+ },
+ {
+ type: "image",
+ source: {
+ type: "base64",
+ media_type: "image/jpeg",
+ data: "image-data",
+ },
+ },
+ ],
+ ts: 1620000000000,
+ isSummary: true,
+ },
+ ]
+
+ const result = maybeRemoveImageBlocks(messages, apiHandler)
+
+ // Should convert image blocks to text descriptions while preserving additional properties
+ expect(result).toEqual([
+ {
+ role: "user",
+ content: [
+ {
+ type: "text",
+ text: "Here's an image:",
+ },
+ {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ },
+ ],
+ ts: 1620000000000,
+ isSummary: true,
+ },
+ ])
+ expect(apiHandler.getModel).toHaveBeenCalled()
+ })
+})
diff --git a/src/api/transform/gemini-format.ts b/src/api/transform/gemini-format.ts
index be08d7ff7ba..ee22cff32a4 100644
--- a/src/api/transform/gemini-format.ts
+++ b/src/api/transform/gemini-format.ts
@@ -76,9 +76,3 @@ export function convertAnthropicMessageToGemini(message: Anthropic.Messages.Mess
parts: convertAnthropicContentToGemini(message.content),
}
}
-
-const getContentLength = ({ parts }: Content): number =>
- parts?.reduce((length, { text }) => length + (text?.length ?? 0), 0) ?? 0
-
-export const getMessagesLength = (contents: Content[]): number =>
- contents.reduce((length, content) => length + getContentLength(content), 0)
diff --git a/src/api/transform/image-cleaning.ts b/src/api/transform/image-cleaning.ts
new file mode 100644
index 00000000000..e5987bb59e5
--- /dev/null
+++ b/src/api/transform/image-cleaning.ts
@@ -0,0 +1,28 @@
+import { ApiHandler } from ".."
+import { ApiMessage } from "../../core/task-persistence/apiMessages"
+
+/* Removes image blocks from messages if they are not supported by the Api Handler */
+export function maybeRemoveImageBlocks(messages: ApiMessage[], apiHandler: ApiHandler): ApiMessage[] {
+ return messages.map((message) => {
+ // Handle array content (could contain image blocks).
+ let { content } = message
+ if (Array.isArray(content)) {
+ if (!apiHandler.getModel().info.supportsImages) {
+ // Convert image blocks to text descriptions.
+ content = content.map((block) => {
+ if (block.type === "image") {
+ // Convert image blocks to text descriptions.
+ // Note: We can't access the actual image content/url due to API limitations,
+ // but we can indicate that an image was present in the conversation.
+ return {
+ type: "text",
+ text: "[Referenced image in conversation]",
+ }
+ }
+ return block
+ })
+ }
+ }
+ return { ...message, content }
+ })
+}
diff --git a/src/core/__tests__/read-file-maxReadFileLine.test.ts b/src/core/__tests__/read-file-maxReadFileLine.test.ts
deleted file mode 100644
index f8508694549..00000000000
--- a/src/core/__tests__/read-file-maxReadFileLine.test.ts
+++ /dev/null
@@ -1,408 +0,0 @@
-// npx jest src/core/__tests__/read-file-maxReadFileLine.test.ts
-
-import * as path from "path"
-
-import { countFileLines } from "../../integrations/misc/line-counter"
-import { readLines } from "../../integrations/misc/read-lines"
-import { extractTextFromFile } from "../../integrations/misc/extract-text"
-import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
-import { isBinaryFile } from "isbinaryfile"
-import { ReadFileToolUse } from "../../shared/tools"
-
-// Mock dependencies
-jest.mock("../../integrations/misc/line-counter")
-jest.mock("../../integrations/misc/read-lines")
-jest.mock("../../integrations/misc/extract-text", () => {
- const actual = jest.requireActual("../../integrations/misc/extract-text")
- // Create a spy on the actual addLineNumbers function
- const addLineNumbersSpy = jest.spyOn(actual, "addLineNumbers")
-
- return {
- ...actual,
- // Expose the spy so tests can access it
- __addLineNumbersSpy: addLineNumbersSpy,
- extractTextFromFile: jest.fn(),
- }
-})
-
-// Get a reference to the spy
-const addLineNumbersSpy = jest.requireMock("../../integrations/misc/extract-text").__addLineNumbersSpy
-
-jest.mock("../../services/tree-sitter")
-jest.mock("isbinaryfile")
-jest.mock("../ignore/RooIgnoreController", () => ({
- RooIgnoreController: class {
- initialize() {
- return Promise.resolve()
- }
- validateAccess() {
- return true
- }
- },
-}))
-jest.mock("fs/promises", () => ({
- mkdir: jest.fn().mockResolvedValue(undefined),
- writeFile: jest.fn().mockResolvedValue(undefined),
- readFile: jest.fn().mockResolvedValue("{}"),
-}))
-jest.mock("../../utils/fs", () => ({
- fileExistsAtPath: jest.fn().mockReturnValue(true),
-}))
-
-// Mock path
-jest.mock("path", () => {
- const originalPath = jest.requireActual("path")
- return {
- ...originalPath,
- resolve: jest.fn().mockImplementation((...args) => args.join("/")),
- }
-})
-
-describe("read_file tool with maxReadFileLine setting", () => {
- // Test data
- const testFilePath = "test/file.txt"
- const absoluteFilePath = "/test/file.txt"
- const fileContent = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5"
- const numberedFileContent = "1 | Line 1\n2 | Line 2\n3 | Line 3\n4 | Line 4\n5 | Line 5\n"
- const sourceCodeDef = "\n\n# file.txt\n1--5 | Content"
- const expectedFullFileXml = `${testFilePath}\n\n${numberedFileContent}\n`
-
- // Mocked functions with correct types
- const mockedCountFileLines = countFileLines as jest.MockedFunction
- const mockedReadLines = readLines as jest.MockedFunction
- const mockedExtractTextFromFile = extractTextFromFile as jest.MockedFunction
- const mockedParseSourceCodeDefinitionsForFile = parseSourceCodeDefinitionsForFile as jest.MockedFunction<
- typeof parseSourceCodeDefinitionsForFile
- >
-
- // Variable to control what content is used by the mock - set in beforeEach
- let mockInputContent = ""
-
- const mockedIsBinaryFile = isBinaryFile as jest.MockedFunction
- const mockedPathResolve = path.resolve as jest.MockedFunction
-
- // Mock instances
- const mockCline: any = {}
- let mockProvider: any
- let toolResult: string | undefined
-
- beforeEach(() => {
- jest.clearAllMocks()
-
- // Setup path resolution
- mockedPathResolve.mockReturnValue(absoluteFilePath)
-
- // Setup mocks for file operations
- mockedIsBinaryFile.mockResolvedValue(false)
-
- // Set the default content for the mock
- mockInputContent = fileContent
-
- // Setup the extractTextFromFile mock implementation with the current mockInputContent
- mockedExtractTextFromFile.mockImplementation((_filePath) => {
- const actual = jest.requireActual("../../integrations/misc/extract-text")
- return Promise.resolve(actual.addLineNumbers(mockInputContent))
- })
-
- // No need to setup the extractTextFromFile mock implementation here
- // as it's already defined at the module level
-
- // Setup mock provider
- mockProvider = {
- getState: jest.fn(),
- deref: jest.fn().mockReturnThis(),
- }
-
- // Setup Cline instance with mock methods
- mockCline.cwd = "/"
- mockCline.task = "Test"
- mockCline.providerRef = mockProvider
- mockCline.rooIgnoreController = {
- validateAccess: jest.fn().mockReturnValue(true),
- }
- mockCline.say = jest.fn().mockResolvedValue(undefined)
- mockCline.ask = jest.fn().mockResolvedValue(true)
- mockCline.presentAssistantMessage = jest.fn()
- mockCline.getFileContextTracker = jest.fn().mockReturnValue({
- trackFileContext: jest.fn().mockResolvedValue(undefined),
- })
- mockCline.recordToolUsage = jest.fn().mockReturnValue(undefined)
- mockCline.recordToolError = jest.fn().mockReturnValue(undefined)
- // Reset tool result
- toolResult = undefined
- })
-
- /**
- * Helper function to execute the read file tool with different maxReadFileLine settings
- */
- async function executeReadFileTool(
- params: Partial = {},
- options: {
- maxReadFileLine?: number
- totalLines?: number
- skipAddLineNumbersCheck?: boolean // Flag to skip addLineNumbers check
- } = {},
- ): Promise {
- // Configure mocks based on test scenario
- const maxReadFileLine = options.maxReadFileLine ?? 500
- const totalLines = options.totalLines ?? 5
-
- mockProvider.getState.mockResolvedValue({ maxReadFileLine })
- mockedCountFileLines.mockResolvedValue(totalLines)
-
- // Reset the spy before each test
- addLineNumbersSpy.mockClear()
-
- // Create a tool use object
- const toolUse: ReadFileToolUse = {
- type: "tool_use",
- name: "read_file",
- params: {
- path: testFilePath,
- ...params,
- },
- partial: false,
- }
-
- // Import the tool implementation dynamically to avoid hoisting issues
- const { readFileTool } = require("../tools/readFileTool")
-
- // Execute the tool
- await readFileTool(
- mockCline,
- toolUse,
- mockCline.ask,
- jest.fn(),
- (result: string) => {
- toolResult = result
- },
- (param: string, value: string) => value,
- )
-
- // Verify addLineNumbers was called appropriately
- if (!options.skipAddLineNumbersCheck) {
- expect(addLineNumbersSpy).toHaveBeenCalled()
- } else {
- expect(addLineNumbersSpy).not.toHaveBeenCalled()
- }
-
- return toolResult
- }
- describe("when maxReadFileLine is negative", () => {
- it("should read the entire file using extractTextFromFile", async () => {
- // Setup - use default mockInputContent
- mockInputContent = fileContent
-
- // Execute
- const result = await executeReadFileTool({}, { maxReadFileLine: -1 })
-
- // Verify
- expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
- expect(mockedReadLines).not.toHaveBeenCalled()
- expect(mockedParseSourceCodeDefinitionsForFile).not.toHaveBeenCalled()
- expect(result).toBe(expectedFullFileXml)
- })
-
- it("should ignore range parameters and read entire file when maxReadFileLine is -1", async () => {
- // Setup - use default mockInputContent
- mockInputContent = fileContent
-
- // Execute with range parameters
- const result = await executeReadFileTool(
- {
- start_line: "2",
- end_line: "4",
- },
- { maxReadFileLine: -1 },
- )
-
- // Verify that extractTextFromFile is still used (not readLines)
- expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
- expect(mockedReadLines).not.toHaveBeenCalled()
- expect(mockedParseSourceCodeDefinitionsForFile).not.toHaveBeenCalled()
- expect(result).toBe(expectedFullFileXml)
- })
-
- it("should not show line snippet in approval message when maxReadFileLine is -1", async () => {
- // This test verifies the line snippet behavior for the approval message
- // Setup - use default mockInputContent
- mockInputContent = fileContent
-
- // Execute - we'll reuse executeReadFileTool to run the tool
- await executeReadFileTool({}, { maxReadFileLine: -1 })
-
- // Verify the empty line snippet for full read was passed to the approval message
- // Look at the parameters passed to the 'ask' method in the approval message
- const askCall = mockCline.ask.mock.calls[0]
- const completeMessage = JSON.parse(askCall[1])
-
- // Verify the reason (lineSnippet) is empty or undefined for full read
- expect(completeMessage.reason).toBeFalsy()
- })
- })
-
- describe("when maxReadFileLine is 0", () => {
- it("should return an empty content with source code definitions", async () => {
- // Setup - for maxReadFileLine = 0, the implementation won't call readLines
- mockedParseSourceCodeDefinitionsForFile.mockResolvedValue(sourceCodeDef)
-
- // Execute - skip addLineNumbers check as it's not called for maxReadFileLine=0
- const result = await executeReadFileTool(
- {},
- {
- maxReadFileLine: 0,
- totalLines: 5,
- skipAddLineNumbersCheck: true,
- },
- )
-
- // Verify
- expect(mockedExtractTextFromFile).not.toHaveBeenCalled()
- expect(mockedReadLines).not.toHaveBeenCalled() // Per implementation line 141
- expect(mockedParseSourceCodeDefinitionsForFile).toHaveBeenCalledWith(
- absoluteFilePath,
- mockCline.rooIgnoreController,
- )
-
- // Verify XML structure
- expect(result).toContain(`${testFilePath}`)
- expect(result).toContain("Showing only 0 of 5 total lines")
- expect(result).toContain("")
- expect(result).toContain("")
- expect(result).toContain(sourceCodeDef.trim())
- expect(result).toContain("")
- expect(result).not.toContain(" {
- it("should read only maxReadFileLine lines and add source code definitions", async () => {
- // Setup
- const content = "Line 1\nLine 2\nLine 3"
- mockedReadLines.mockResolvedValue(content)
- mockedParseSourceCodeDefinitionsForFile.mockResolvedValue(sourceCodeDef)
-
- // Execute
- const result = await executeReadFileTool({}, { maxReadFileLine: 3 })
-
- // Verify - check behavior but not specific implementation details
- expect(mockedExtractTextFromFile).not.toHaveBeenCalled()
- expect(mockedReadLines).toHaveBeenCalled()
- expect(mockedParseSourceCodeDefinitionsForFile).toHaveBeenCalledWith(
- absoluteFilePath,
- mockCline.rooIgnoreController,
- )
-
- // Verify XML structure
- expect(result).toContain(`${testFilePath}`)
- expect(result).toContain('')
- expect(result).toContain("1 | Line 1")
- expect(result).toContain("2 | Line 2")
- expect(result).toContain("3 | Line 3")
- expect(result).toContain("")
- expect(result).toContain("Showing only 3 of 5 total lines")
- expect(result).toContain("")
- expect(result).toContain("")
- expect(result).toContain(sourceCodeDef.trim())
- expect(result).toContain("")
- expect(result).toContain("")
- expect(result).toContain(sourceCodeDef.trim())
- })
- })
-
- describe("when maxReadFileLine equals or exceeds file length", () => {
- it("should use extractTextFromFile when maxReadFileLine > totalLines", async () => {
- // Setup
- mockedCountFileLines.mockResolvedValue(5) // File shorter than maxReadFileLine
- mockInputContent = fileContent
-
- // Execute
- const result = await executeReadFileTool({}, { maxReadFileLine: 10, totalLines: 5 })
-
- // Verify
- expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
- expect(result).toBe(expectedFullFileXml)
- })
-
- it("should read with extractTextFromFile when file has few lines", async () => {
- // Setup
- mockedCountFileLines.mockResolvedValue(3) // File shorter than maxReadFileLine
- mockInputContent = fileContent
-
- // Execute
- const result = await executeReadFileTool({}, { maxReadFileLine: 5, totalLines: 3 })
-
- // Verify
- expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
- expect(mockedReadLines).not.toHaveBeenCalled()
- // Create a custom expected XML with lines="1-3" since totalLines is 3
- const expectedXml = `${testFilePath}\n\n${numberedFileContent}\n`
- expect(result).toBe(expectedXml)
- })
- })
-
- describe("when file is binary", () => {
- it("should always use extractTextFromFile regardless of maxReadFileLine", async () => {
- // Setup
- mockedIsBinaryFile.mockResolvedValue(true)
- // For binary files, we're using a maxReadFileLine of 3 and totalLines is assumed to be 3
- mockedCountFileLines.mockResolvedValue(3)
-
- // For binary files, we need a special mock implementation that doesn't use addLineNumbers
- // Save the original mock implementation
- const originalMockImplementation = mockedExtractTextFromFile.getMockImplementation()
- // Create a special mock implementation that doesn't call addLineNumbers
- mockedExtractTextFromFile.mockImplementation(() => {
- return Promise.resolve(numberedFileContent)
- })
-
- // Reset the spy to clear any previous calls
- addLineNumbersSpy.mockClear()
-
- // Execute - skip addLineNumbers check as we're directly providing the numbered content
- const result = await executeReadFileTool(
- {},
- {
- maxReadFileLine: 3,
- totalLines: 3,
- skipAddLineNumbersCheck: true,
- },
- )
-
- // Restore the original mock implementation after the test
- mockedExtractTextFromFile.mockImplementation(originalMockImplementation)
-
- // Verify
- expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
- expect(mockedReadLines).not.toHaveBeenCalled()
- // Create a custom expected XML with lines="1-3" for binary files
- const expectedXml = `${testFilePath}\n\n${numberedFileContent}\n`
- expect(result).toBe(expectedXml)
- })
- })
-
- describe("with range parameters", () => {
- it("should honor start_line and end_line when provided", async () => {
- // Setup
- mockedReadLines.mockResolvedValue("Line 2\nLine 3\nLine 4")
-
- // Execute using executeReadFileTool with range parameters
- const rangeResult = await executeReadFileTool({
- start_line: "2",
- end_line: "4",
- })
-
- // Verify
- expect(mockedReadLines).toHaveBeenCalledWith(absoluteFilePath, 3, 1) // end_line - 1, start_line - 1
- expect(addLineNumbersSpy).toHaveBeenCalledWith(expect.any(String), 2) // start with proper line numbers
-
- // Verify XML structure with lines attribute
- expect(rangeResult).toContain(`${testFilePath}`)
- expect(rangeResult).toContain(``)
- expect(rangeResult).toContain("2 | Line 2")
- expect(rangeResult).toContain("3 | Line 3")
- expect(rangeResult).toContain("4 | Line 4")
- expect(rangeResult).toContain("")
- })
- })
-})
diff --git a/src/core/assistant-message/__tests__/parseAssistantMessage.test.ts b/src/core/assistant-message/__tests__/parseAssistantMessage.test.ts
new file mode 100644
index 00000000000..19f88a91d7d
--- /dev/null
+++ b/src/core/assistant-message/__tests__/parseAssistantMessage.test.ts
@@ -0,0 +1,340 @@
+// npx jest src/core/assistant-message/__tests__/parseAssistantMessage.test.ts
+
+import { TextContent, ToolUse } from "../../../shared/tools"
+
+import { AssistantMessageContent, parseAssistantMessage as parseAssistantMessageV1 } from "../parseAssistantMessage"
+import { parseAssistantMessageV2 } from "../parseAssistantMessageV2"
+
+const isEmptyTextContent = (block: AssistantMessageContent) =>
+ block.type === "text" && (block as TextContent).content === ""
+
+;[parseAssistantMessageV1, parseAssistantMessageV2].forEach((parser, index) => {
+ describe(`parseAssistantMessageV${index + 1}`, () => {
+ describe("text content parsing", () => {
+ it("should parse a simple text message", () => {
+ const message = "This is a simple text message"
+ const result = parser(message)
+
+ expect(result).toHaveLength(1)
+ expect(result[0]).toEqual({
+ type: "text",
+ content: message,
+ partial: true, // Text is always partial when it's the last content
+ })
+ })
+
+ it("should parse a multi-line text message", () => {
+ const message = "This is a multi-line\ntext message\nwith several lines"
+ const result = parser(message)
+
+ expect(result).toHaveLength(1)
+ expect(result[0]).toEqual({
+ type: "text",
+ content: message,
+ partial: true, // Text is always partial when it's the last content
+ })
+ })
+
+ it("should mark text as partial when it's the last content in the message", () => {
+ const message = "This is a partial text"
+ const result = parser(message)
+
+ expect(result).toHaveLength(1)
+ expect(result[0]).toEqual({
+ type: "text",
+ content: message,
+ partial: true,
+ })
+ })
+ })
+
+ describe("tool use parsing", () => {
+ it("should parse a simple tool use", () => {
+ const message = "src/file.ts"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should parse a tool use with multiple parameters", () => {
+ const message =
+ "src/file.ts1020"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.params.start_line).toBe("10")
+ expect(toolUse.params.end_line).toBe("20")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should mark tool use as partial when it's not closed", () => {
+ const message = "src/file.ts"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(true)
+ })
+
+ it("should handle a partial parameter in a tool use", () => {
+ const message = "src/file.ts"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(true)
+ })
+ })
+
+ describe("mixed content parsing", () => {
+ it("should parse text followed by a tool use", () => {
+ const message = "Here's the file content: src/file.ts"
+ const result = parser(message)
+
+ expect(result).toHaveLength(2)
+
+ const textContent = result[0] as TextContent
+ expect(textContent.type).toBe("text")
+ expect(textContent.content).toBe("Here's the file content:")
+ expect(textContent.partial).toBe(false)
+
+ const toolUse = result[1] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should parse a tool use followed by text", () => {
+ const message = "src/file.tsHere's what I found in the file."
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(2)
+
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(false)
+
+ const textContent = result[1] as TextContent
+ expect(textContent.type).toBe("text")
+ expect(textContent.content).toBe("Here's what I found in the file.")
+ expect(textContent.partial).toBe(true)
+ })
+
+ it("should parse multiple tool uses separated by text", () => {
+ const message =
+ "First file: src/file1.tsSecond file: src/file2.ts"
+ const result = parser(message)
+
+ expect(result).toHaveLength(4)
+
+ expect(result[0].type).toBe("text")
+ expect((result[0] as TextContent).content).toBe("First file:")
+
+ expect(result[1].type).toBe("tool_use")
+ expect((result[1] as ToolUse).name).toBe("read_file")
+ expect((result[1] as ToolUse).params.path).toBe("src/file1.ts")
+
+ expect(result[2].type).toBe("text")
+ expect((result[2] as TextContent).content).toBe("Second file:")
+
+ expect(result[3].type).toBe("tool_use")
+ expect((result[3] as ToolUse).name).toBe("read_file")
+ expect((result[3] as ToolUse).params.path).toBe("src/file2.ts")
+ })
+ })
+
+ describe("special cases", () => {
+ it("should handle the write_to_file tool with content that contains closing tags", () => {
+ const message = `src/file.ts
+ function example() {
+ // This has XML-like content:
+ return true;
+ }
+ 5`
+
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("write_to_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.params.line_count).toBe("5")
+ expect(toolUse.params.content).toContain("function example()")
+ expect(toolUse.params.content).toContain("// This has XML-like content: ")
+ expect(toolUse.params.content).toContain("return true;")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle empty messages", () => {
+ const message = ""
+ const result = parser(message)
+
+ expect(result).toHaveLength(0)
+ })
+
+ it("should handle malformed tool use tags", () => {
+ const message = "This has a malformed tag"
+ const result = parser(message)
+
+ expect(result).toHaveLength(1)
+ expect(result[0].type).toBe("text")
+ expect((result[0] as TextContent).content).toBe(message)
+ })
+
+ it("should handle tool use with no parameters", () => {
+ const message = ""
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("browser_action")
+ expect(Object.keys(toolUse.params).length).toBe(0)
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle nested tool tags that aren't actually nested", () => {
+ const message =
+ "echo 'test.txt'"
+
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("execute_command")
+ expect(toolUse.params.command).toBe("echo 'test.txt'")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle a tool use with a parameter containing XML-like content", () => {
+ const message = ".*
src"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("search_files")
+ expect(toolUse.params.regex).toBe(".*
")
+ expect(toolUse.params.path).toBe("src")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle consecutive tool uses without text in between", () => {
+ const message =
+ "file1.tsfile2.ts"
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(2)
+
+ const toolUse1 = result[0] as ToolUse
+ expect(toolUse1.type).toBe("tool_use")
+ expect(toolUse1.name).toBe("read_file")
+ expect(toolUse1.params.path).toBe("file1.ts")
+ expect(toolUse1.partial).toBe(false)
+
+ const toolUse2 = result[1] as ToolUse
+ expect(toolUse2.type).toBe("tool_use")
+ expect(toolUse2.name).toBe("read_file")
+ expect(toolUse2.params.path).toBe("file2.ts")
+ expect(toolUse2.partial).toBe(false)
+ })
+
+ it("should handle whitespace in parameters", () => {
+ const message = " src/file.ts "
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("read_file")
+ expect(toolUse.params.path).toBe("src/file.ts")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle multi-line parameters", () => {
+ const message = `file.ts
+ line 1
+ line 2
+ line 3
+ 3`
+ const result = parser(message).filter((block) => !isEmptyTextContent(block))
+
+ expect(result).toHaveLength(1)
+ const toolUse = result[0] as ToolUse
+ expect(toolUse.type).toBe("tool_use")
+ expect(toolUse.name).toBe("write_to_file")
+ expect(toolUse.params.path).toBe("file.ts")
+ expect(toolUse.params.content).toContain("line 1")
+ expect(toolUse.params.content).toContain("line 2")
+ expect(toolUse.params.content).toContain("line 3")
+ expect(toolUse.params.line_count).toBe("3")
+ expect(toolUse.partial).toBe(false)
+ })
+
+ it("should handle a complex message with multiple content types", () => {
+ const message = `I'll help you with that task.
+
+ src/index.ts
+
+ Now let's modify the file:
+
+ src/index.ts
+ // Updated content
+ console.log("Hello world");
+ 2
+
+ Let's run the code:
+
+ node src/index.ts`
+
+ const result = parser(message)
+
+ expect(result).toHaveLength(6)
+
+ // First text block
+ expect(result[0].type).toBe("text")
+ expect((result[0] as TextContent).content).toBe("I'll help you with that task.")
+
+ // First tool use (read_file)
+ expect(result[1].type).toBe("tool_use")
+ expect((result[1] as ToolUse).name).toBe("read_file")
+
+ // Second text block
+ expect(result[2].type).toBe("text")
+ expect((result[2] as TextContent).content).toContain("Now let's modify the file:")
+
+ // Second tool use (write_to_file)
+ expect(result[3].type).toBe("tool_use")
+ expect((result[3] as ToolUse).name).toBe("write_to_file")
+
+ // Third text block
+ expect(result[4].type).toBe("text")
+ expect((result[4] as TextContent).content).toContain("Let's run the code:")
+
+ // Third tool use (execute_command)
+ expect(result[5].type).toBe("tool_use")
+ expect((result[5] as ToolUse).name).toBe("execute_command")
+ })
+ })
+ })
+})
diff --git a/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts b/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
new file mode 100644
index 00000000000..bea161330b9
--- /dev/null
+++ b/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
@@ -0,0 +1,109 @@
+// node --expose-gc --import tsx src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
+
+import { performance } from "perf_hooks"
+import { parseAssistantMessage as parseAssistantMessageV1 } from "../parseAssistantMessage"
+import { parseAssistantMessageV2 } from "../parseAssistantMessageV2"
+
+const formatNumber = (num: number): string => {
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
+}
+
+const measureExecutionTime = (fn: Function, input: string, iterations: number = 1000): number => {
+ for (let i = 0; i < 10; i++) {
+ fn(input)
+ }
+
+ const start = performance.now()
+
+ for (let i = 0; i < iterations; i++) {
+ fn(input)
+ }
+
+ const end = performance.now()
+ return (end - start) / iterations // Average time per iteration in ms.
+}
+
+const measureMemoryUsage = (
+ fn: Function,
+ input: string,
+ iterations: number = 100,
+): { heapUsed: number; heapTotal: number } => {
+ if (global.gc) {
+ // Force garbage collection if available.
+ global.gc()
+ } else {
+ console.warn("No garbage collection hook! Run with --expose-gc for more accurate memory measurements.")
+ }
+
+ const initialMemory = process.memoryUsage()
+
+ for (let i = 0; i < iterations; i++) {
+ fn(input)
+ }
+
+ const finalMemory = process.memoryUsage()
+
+ return {
+ heapUsed: (finalMemory.heapUsed - initialMemory.heapUsed) / iterations,
+ heapTotal: (finalMemory.heapTotal - initialMemory.heapTotal) / iterations,
+ }
+}
+
+const testCases = [
+ {
+ name: "Simple text message",
+ input: "This is a simple text message without any tool uses.",
+ },
+ {
+ name: "Message with a simple tool use",
+ input: "Let's read a file: src/file.ts",
+ },
+ {
+ name: "Message with a complex tool use (write_to_file)",
+ input: "src/file.ts\nfunction example() {\n // This has XML-like content: \n return true;\n}\n5",
+ },
+ {
+ name: "Message with multiple tool uses",
+ input: "First file: src/file1.ts\nSecond file: src/file2.ts\nLet's write a new file: src/file3.ts\nexport function newFunction() {\n return 'Hello world';\n}\n3",
+ },
+ {
+ name: "Large message with repeated tool uses",
+ input: Array(50)
+ .fill(
+ 'src/file.ts\noutput.tsconsole.log("hello");1',
+ )
+ .join("\n"),
+ },
+]
+
+const runBenchmark = () => {
+ const maxNameLength = testCases.reduce((max, testCase) => Math.max(max, testCase.name.length), 0)
+ const namePadding = maxNameLength + 2
+
+ console.log(
+ `| ${"Test Case".padEnd(namePadding)} | V1 Time (ms) | V2 Time (ms) | V1/V2 Ratio | V1 Heap (bytes) | V2 Heap (bytes) |`,
+ )
+ console.log(
+ `| ${"-".repeat(namePadding)} | ------------ | ------------ | ----------- | ---------------- | ---------------- |`,
+ )
+
+ for (const testCase of testCases) {
+ const v1Time = measureExecutionTime(parseAssistantMessageV1, testCase.input)
+ const v2Time = measureExecutionTime(parseAssistantMessageV2, testCase.input)
+ const timeRatio = v1Time / v2Time
+
+ const v1Memory = measureMemoryUsage(parseAssistantMessageV1, testCase.input)
+ const v2Memory = measureMemoryUsage(parseAssistantMessageV2, testCase.input)
+
+ console.log(
+ `| ${testCase.name.padEnd(namePadding)} | ` +
+ `${v1Time.toFixed(4).padStart(12)} | ` +
+ `${v2Time.toFixed(4).padStart(12)} | ` +
+ `${timeRatio.toFixed(2).padStart(11)} | ` +
+ `${formatNumber(Math.round(v1Memory.heapUsed)).padStart(16)} | ` +
+ `${formatNumber(Math.round(v2Memory.heapUsed)).padStart(16)} |`,
+ )
+ }
+}
+
+runBenchmark()
diff --git a/src/core/assistant-message/index.ts b/src/core/assistant-message/index.ts
index c53e88ed96b..72201b7722e 100644
--- a/src/core/assistant-message/index.ts
+++ b/src/core/assistant-message/index.ts
@@ -1 +1,2 @@
-export { type AssistantMessageContent, parseAssistantMessage } from "./parse-assistant-message"
+export { type AssistantMessageContent, parseAssistantMessage } from "./parseAssistantMessage"
+export { presentAssistantMessage } from "./presentAssistantMessage"
diff --git a/src/core/assistant-message/parse-assistant-message.ts b/src/core/assistant-message/parseAssistantMessage.ts
similarity index 73%
rename from src/core/assistant-message/parse-assistant-message.ts
rename to src/core/assistant-message/parseAssistantMessage.ts
index 0cac4dfb989..f641cabdaa9 100644
--- a/src/core/assistant-message/parse-assistant-message.ts
+++ b/src/core/assistant-message/parseAssistantMessage.ts
@@ -3,7 +3,7 @@ import { toolNames, ToolName } from "../../schemas"
export type AssistantMessageContent = TextContent | ToolUse
-export function parseAssistantMessage(assistantMessage: string) {
+export function parseAssistantMessage(assistantMessage: string): AssistantMessageContent[] {
let contentBlocks: AssistantMessageContent[] = []
let currentTextContent: TextContent | undefined = undefined
let currentTextContentStartIndex = 0
@@ -17,28 +17,28 @@ export function parseAssistantMessage(assistantMessage: string) {
const char = assistantMessage[i]
accumulator += char
- // there should not be a param without a tool use
+ // There should not be a param without a tool use.
if (currentToolUse && currentParamName) {
const currentParamValue = accumulator.slice(currentParamValueStartIndex)
const paramClosingTag = `${currentParamName}>`
if (currentParamValue.endsWith(paramClosingTag)) {
- // end of param value
+ // End of param value.
currentToolUse.params[currentParamName] = currentParamValue.slice(0, -paramClosingTag.length).trim()
currentParamName = undefined
continue
} else {
- // partial param value is accumulating
+ // Partial param value is accumulating.
continue
}
}
- // no currentParamName
+ // No currentParamName.
if (currentToolUse) {
const currentToolValue = accumulator.slice(currentToolUseStartIndex)
const toolUseClosingTag = `${currentToolUse.name}>`
if (currentToolValue.endsWith(toolUseClosingTag)) {
- // end of a tool use
+ // End of a tool use.
currentToolUse.partial = false
contentBlocks.push(currentToolUse)
currentToolUse = undefined
@@ -47,23 +47,29 @@ export function parseAssistantMessage(assistantMessage: string) {
const possibleParamOpeningTags = toolParamNames.map((name) => `<${name}>`)
for (const paramOpeningTag of possibleParamOpeningTags) {
if (accumulator.endsWith(paramOpeningTag)) {
- // start of a new parameter
+ // Start of a new parameter.
currentParamName = paramOpeningTag.slice(1, -1) as ToolParamName
currentParamValueStartIndex = accumulator.length
break
}
}
- // there's no current param, and not starting a new param
+ // There's no current param, and not starting a new param.
- // special case for write_to_file where file contents could contain the closing tag, in which case the param would have closed and we end up with the rest of the file contents here. To work around this, we get the string between the starting content tag and the LAST content tag.
+ // Special case for write_to_file where file contents could
+ // contain the closing tag, in which case the param would have
+ // closed and we end up with the rest of the file contents here.
+ // To work around this, we get the string between the starting
+ // ontent tag and the LAST content tag.
const contentParamName: ToolParamName = "content"
+
if (currentToolUse.name === "write_to_file" && accumulator.endsWith(`${contentParamName}>`)) {
const toolContent = accumulator.slice(currentToolUseStartIndex)
const contentStartTag = `<${contentParamName}>`
const contentEndTag = `${contentParamName}>`
const contentStartIndex = toolContent.indexOf(contentStartTag) + contentStartTag.length
const contentEndIndex = toolContent.lastIndexOf(contentEndTag)
+
if (contentStartIndex !== -1 && contentEndIndex !== -1 && contentEndIndex > contentStartIndex) {
currentToolUse.params[contentParamName] = toolContent
.slice(contentStartIndex, contentEndIndex)
@@ -71,32 +77,38 @@ export function parseAssistantMessage(assistantMessage: string) {
}
}
- // partial tool value is accumulating
+ // Partial tool value is accumulating.
continue
}
}
- // no currentToolUse
+ // No currentToolUse.
let didStartToolUse = false
const possibleToolUseOpeningTags = toolNames.map((name) => `<${name}>`)
+
for (const toolUseOpeningTag of possibleToolUseOpeningTags) {
if (accumulator.endsWith(toolUseOpeningTag)) {
- // start of a new tool use
+ // Start of a new tool use.
currentToolUse = {
type: "tool_use",
name: toolUseOpeningTag.slice(1, -1) as ToolName,
params: {},
partial: true,
}
+
currentToolUseStartIndex = accumulator.length
- // this also indicates the end of the current text content
+
+ // This also indicates the end of the current text content.
if (currentTextContent) {
currentTextContent.partial = false
- // remove the partially accumulated tool use tag from the end of text (()
+ const toolParamOpenTags = new Map()
+
+ for (const name of toolNames) {
+ toolUseOpenTags.set(`<${name}>`, name)
+ }
+
+ for (const name of toolParamNames) {
+ toolParamOpenTags.set(`<${name}>`, name)
+ }
+
+ const len = assistantMessage.length
+
+ for (let i = 0; i < len; i++) {
+ const currentCharIndex = i
+
+ // Parsing a tool parameter
+ if (currentToolUse && currentParamName) {
+ const closeTag = `${currentParamName}>`
+ // Check if the string *ending* at index `i` matches the closing tag
+ if (
+ currentCharIndex >= closeTag.length - 1 &&
+ assistantMessage.startsWith(
+ closeTag,
+ currentCharIndex - closeTag.length + 1, // Start checking from potential start of tag.
+ )
+ ) {
+ // Found the closing tag for the parameter.
+ const value = assistantMessage
+ .slice(
+ currentParamValueStart, // Start after the opening tag.
+ currentCharIndex - closeTag.length + 1, // End before the closing tag.
+ )
+ .trim()
+ currentToolUse.params[currentParamName] = value
+ currentParamName = undefined // Go back to parsing tool content.
+ // We don't continue loop here, need to check for tool close or other params at index i.
+ } else {
+ continue // Still inside param value, move to next char.
+ }
+ }
+
+ // Parsing a tool use (but not a specific parameter).
+ if (currentToolUse && !currentParamName) {
+ // Ensure we are not inside a parameter already.
+ // Check if starting a new parameter.
+ let startedNewParam = false
+
+ for (const [tag, paramName] of toolParamOpenTags.entries()) {
+ if (
+ currentCharIndex >= tag.length - 1 &&
+ assistantMessage.startsWith(tag, currentCharIndex - tag.length + 1)
+ ) {
+ currentParamName = paramName
+ currentParamValueStart = currentCharIndex + 1 // Value starts after the tag.
+ startedNewParam = true
+ break
+ }
+ }
+
+ if (startedNewParam) {
+ continue // Handled start of param, move to next char.
+ }
+
+ // Check if closing the current tool use.
+ const toolCloseTag = `${currentToolUse.name}>`
+
+ if (
+ currentCharIndex >= toolCloseTag.length - 1 &&
+ assistantMessage.startsWith(toolCloseTag, currentCharIndex - toolCloseTag.length + 1)
+ ) {
+ // End of the tool use found.
+ // Special handling for content params *before* finalizing the
+ // tool.
+ const toolContentSlice = assistantMessage.slice(
+ currentToolUseStart, // From after the tool opening tag.
+ currentCharIndex - toolCloseTag.length + 1, // To before the tool closing tag.
+ )
+
+ // Check if content parameter needs special handling
+ // (write_to_file/new_rule).
+ // This check is important if the closing tag was
+ // missed by the parameter parsing logic (e.g., if content is
+ // empty or parsing logic prioritizes tool close).
+ const contentParamName: ToolParamName = "content"
+ if (
+ currentToolUse.name === "write_to_file" /* || currentToolUse.name === "new_rule" */ &&
+ // !(contentParamName in currentToolUse.params) && // Only if not already parsed.
+ toolContentSlice.includes(`<${contentParamName}>`) // Check if tag exists.
+ ) {
+ const contentStartTag = `<${contentParamName}>`
+ const contentEndTag = `${contentParamName}>`
+ const contentStart = toolContentSlice.indexOf(contentStartTag)
+
+ // Use `lastIndexOf` for robustness against nested tags.
+ const contentEnd = toolContentSlice.lastIndexOf(contentEndTag)
+
+ if (contentStart !== -1 && contentEnd !== -1 && contentEnd > contentStart) {
+ const contentValue = toolContentSlice
+ .slice(contentStart + contentStartTag.length, contentEnd)
+ .trim()
+
+ currentToolUse.params[contentParamName] = contentValue
+ }
+ }
+
+ currentToolUse.partial = false // Mark as complete.
+ contentBlocks.push(currentToolUse)
+ currentToolUse = undefined // Reset state.
+ currentTextContentStart = currentCharIndex + 1 // Potential text starts after this tag.
+ continue // Move to next char.
+ }
+
+ // If not starting a param and not closing the tool, continue
+ // accumulating tool content implicitly.
+ continue
+ }
+
+ // Parsing text / looking for tool start.
+ if (!currentToolUse) {
+ // Check if starting a new tool use.
+ let startedNewTool = false
+
+ for (const [tag, toolName] of toolUseOpenTags.entries()) {
+ if (
+ currentCharIndex >= tag.length - 1 &&
+ assistantMessage.startsWith(tag, currentCharIndex - tag.length + 1)
+ ) {
+ // End current text block if one was active.
+ if (currentTextContent) {
+ currentTextContent.content = assistantMessage
+ .slice(
+ currentTextContentStart, // From where text started.
+ currentCharIndex - tag.length + 1, // To before the tool tag starts.
+ )
+ .trim()
+
+ currentTextContent.partial = false // Ended because tool started.
+
+ if (currentTextContent.content.length > 0) {
+ contentBlocks.push(currentTextContent)
+ }
+
+ currentTextContent = undefined
+ } else {
+ // Check for any text between the last block and this tag.
+ const potentialText = assistantMessage
+ .slice(
+ currentTextContentStart, // From where text *might* have started.
+ currentCharIndex - tag.length + 1, // To before the tool tag starts.
+ )
+ .trim()
+
+ if (potentialText.length > 0) {
+ contentBlocks.push({
+ type: "text",
+ content: potentialText,
+ partial: false,
+ })
+ }
+ }
+
+ // Start the new tool use.
+ currentToolUse = {
+ type: "tool_use",
+ name: toolName,
+ params: {},
+ partial: true, // Assume partial until closing tag is found.
+ }
+
+ currentToolUseStart = currentCharIndex + 1 // Tool content starts after the opening tag.
+ startedNewTool = true
+
+ break
+ }
+ }
+
+ if (startedNewTool) {
+ continue // Handled start of tool, move to next char.
+ }
+
+ // If not starting a tool, it must be text content.
+ if (!currentTextContent) {
+ // Start a new text block if we aren't already in one.
+ currentTextContentStart = currentCharIndex // Text starts at the current character.
+
+ // Check if the current char is the start of potential text *immediately* after a tag.
+ // This needs the previous state - simpler to let slicing handle it later.
+ // Resetting start index accurately is key.
+ // It should be the index *after* the last processed tag.
+ // The logic managing currentTextContentStart after closing tags handles this.
+ currentTextContent = {
+ type: "text",
+ content: "", // Will be determined by slicing at the end or when a tool starts
+ partial: true,
+ }
+ }
+ // Continue accumulating text implicitly; content is extracted later.
+ }
+ }
+
+ // Finalize any open parameter within an open tool use.
+ if (currentToolUse && currentParamName) {
+ currentToolUse.params[currentParamName] = assistantMessage
+ .slice(currentParamValueStart) // From param start to end of string.
+ .trim()
+ // Tool use remains partial.
+ }
+
+ // Finalize any open tool use (which might contain the finalized partial param).
+ if (currentToolUse) {
+ // Tool use is partial because the loop finished before its closing tag.
+ contentBlocks.push(currentToolUse)
+ }
+ // Finalize any trailing text content.
+ // Only possible if a tool use wasn't open at the very end.
+ else if (currentTextContent) {
+ currentTextContent.content = assistantMessage
+ .slice(currentTextContentStart) // From text start to end of string.
+ .trim()
+
+ // Text is partial because the loop finished.
+ if (currentTextContent.content.length > 0) {
+ contentBlocks.push(currentTextContent)
+ }
+ }
+
+ return contentBlocks
+}
diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts
new file mode 100644
index 00000000000..ef2bb049630
--- /dev/null
+++ b/src/core/assistant-message/presentAssistantMessage.ts
@@ -0,0 +1,525 @@
+import cloneDeep from "clone-deep"
+import { serializeError } from "serialize-error"
+
+import type { ToolName } from "../../schemas"
+
+import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
+import type { ToolParamName, ToolResponse } from "../../shared/tools"
+import type { ClineAsk, ToolProgressStatus } from "../../shared/ExtensionMessage"
+
+import { telemetryService } from "../../services/telemetry/TelemetryService"
+
+import { fetchInstructionsTool } from "../tools/fetchInstructionsTool"
+import { listFilesTool } from "../tools/listFilesTool"
+import { readFileTool } from "../tools/readFileTool"
+import { writeToFileTool } from "../tools/writeToFileTool"
+import { applyDiffTool } from "../tools/applyDiffTool"
+import { insertContentTool } from "../tools/insertContentTool"
+import { searchAndReplaceTool } from "../tools/searchAndReplaceTool"
+import { listCodeDefinitionNamesTool } from "../tools/listCodeDefinitionNamesTool"
+import { searchFilesTool } from "../tools/searchFilesTool"
+import { browserActionTool } from "../tools/browserActionTool"
+import { executeCommandTool } from "../tools/executeCommandTool"
+import { useMcpToolTool } from "../tools/useMcpToolTool"
+import { accessMcpResourceTool } from "../tools/accessMcpResourceTool"
+import { askFollowupQuestionTool } from "../tools/askFollowupQuestionTool"
+import { switchModeTool } from "../tools/switchModeTool"
+import { attemptCompletionTool } from "../tools/attemptCompletionTool"
+import { newTaskTool } from "../tools/newTaskTool"
+
+import { checkpointSave } from "../checkpoints"
+
+import { formatResponse } from "../prompts/responses"
+import { validateToolUse } from "../tools/validateToolUse"
+import { Task } from "../task/Task"
+
+/**
+ * Processes and presents assistant message content to the user interface.
+ *
+ * This function is the core message handling system that:
+ * - Sequentially processes content blocks from the assistant's response.
+ * - Displays text content to the user.
+ * - Executes tool use requests with appropriate user approval.
+ * - Manages the flow of conversation by determining when to proceed to the next content block.
+ * - Coordinates file system checkpointing for modified files.
+ * - Controls the conversation state to determine when to continue to the next request.
+ *
+ * The function uses a locking mechanism to prevent concurrent execution and handles
+ * partial content blocks during streaming. It's designed to work with the streaming
+ * API response pattern, where content arrives incrementally and needs to be processed
+ * as it becomes available.
+ */
+
+export async function presentAssistantMessage(cline: Task) {
+ if (cline.abort) {
+ throw new Error(`[Cline#presentAssistantMessage] task ${cline.taskId}.${cline.instanceId} aborted`)
+ }
+
+ if (cline.presentAssistantMessageLocked) {
+ cline.presentAssistantMessageHasPendingUpdates = true
+ return
+ }
+
+ cline.presentAssistantMessageLocked = true
+ cline.presentAssistantMessageHasPendingUpdates = false
+
+ if (cline.currentStreamingContentIndex >= cline.assistantMessageContent.length) {
+ // This may happen if the last content block was completed before
+ // streaming could finish. If streaming is finished, and we're out of
+ // bounds then this means we already presented/executed the last
+ // content block and are ready to continue to next request.
+ if (cline.didCompleteReadingStream) {
+ cline.userMessageContentReady = true
+ }
+
+ cline.presentAssistantMessageLocked = false
+ return
+ }
+
+ const block = cloneDeep(cline.assistantMessageContent[cline.currentStreamingContentIndex]) // need to create copy bc while stream is updating the array, it could be updating the reference block properties too
+
+ switch (block.type) {
+ case "text": {
+ if (cline.didRejectTool || cline.didAlreadyUseTool) {
+ break
+ }
+
+ let content = block.content
+
+ if (content) {
+ // Have to do this for partial and complete since sending
+ // content in thinking tags to markdown renderer will
+ // automatically be removed.
+ // Remove end substrings of (with optional line break
+ // after) and (with optional line break before).
+ // - Needs to be separate since we dont want to remove the line
+ // break before the first tag.
+ // - Needs to happen before the xml parsing below.
+ content = content.replace(/\s?/g, "")
+ content = content.replace(/\s?<\/thinking>/g, "")
+
+ // Remove partial XML tag at the very end of the content (for
+ // tool use and thinking tags), Prevents scrollview from
+ // jumping when tags are automatically removed.
+ const lastOpenBracketIndex = content.lastIndexOf("<")
+
+ if (lastOpenBracketIndex !== -1) {
+ const possibleTag = content.slice(lastOpenBracketIndex)
+
+ // Check if there's a '>' after the last '<' (i.e., if the
+ // tag is complete) (complete thinking and tool tags will
+ // have been removed by now.)
+ const hasCloseBracket = possibleTag.includes(">")
+
+ if (!hasCloseBracket) {
+ // Extract the potential tag name.
+ let tagContent: string
+
+ if (possibleTag.startsWith("")) {
+ tagContent = possibleTag.slice(2).trim()
+ } else {
+ tagContent = possibleTag.slice(1).trim()
+ }
+
+ // Check if tagContent is likely an incomplete tag name
+ // (letters and underscores only).
+ const isLikelyTagName = /^[a-zA-Z_]+$/.test(tagContent)
+
+ // Preemptively remove < or to keep from these
+ // artifacts showing up in chat (also handles closing
+ // thinking tags).
+ const isOpeningOrClosing = possibleTag === "<" || possibleTag === ""
+
+ // If the tag is incomplete and at the end, remove it
+ // from the content.
+ if (isOpeningOrClosing || isLikelyTagName) {
+ content = content.slice(0, lastOpenBracketIndex).trim()
+ }
+ }
+ }
+ }
+
+ await cline.say("text", content, undefined, block.partial)
+ break
+ }
+ case "tool_use":
+ const toolDescription = (): string => {
+ switch (block.name) {
+ case "execute_command":
+ return `[${block.name} for '${block.params.command}']`
+ case "read_file":
+ return `[${block.name} for '${block.params.path}']`
+ case "fetch_instructions":
+ return `[${block.name} for '${block.params.task}']`
+ case "write_to_file":
+ return `[${block.name} for '${block.params.path}']`
+ case "apply_diff":
+ return `[${block.name} for '${block.params.path}']`
+ case "search_files":
+ return `[${block.name} for '${block.params.regex}'${
+ block.params.file_pattern ? ` in '${block.params.file_pattern}'` : ""
+ }]`
+ case "insert_content":
+ return `[${block.name} for '${block.params.path}']`
+ case "search_and_replace":
+ return `[${block.name} for '${block.params.path}']`
+ case "list_files":
+ return `[${block.name} for '${block.params.path}']`
+ case "list_code_definition_names":
+ return `[${block.name} for '${block.params.path}']`
+ case "browser_action":
+ return `[${block.name} for '${block.params.action}']`
+ case "use_mcp_tool":
+ return `[${block.name} for '${block.params.server_name}']`
+ case "access_mcp_resource":
+ return `[${block.name} for '${block.params.server_name}']`
+ case "ask_followup_question":
+ return `[${block.name} for '${block.params.question}']`
+ case "attempt_completion":
+ return `[${block.name}]`
+ case "switch_mode":
+ return `[${block.name} to '${block.params.mode_slug}'${block.params.reason ? ` because: ${block.params.reason}` : ""}]`
+ case "new_task": {
+ const mode = block.params.mode ?? defaultModeSlug
+ const message = block.params.message ?? "(no message)"
+ const modeName = getModeBySlug(mode, customModes)?.name ?? mode
+ return `[${block.name} in ${modeName} mode: '${message}']`
+ }
+ }
+ }
+
+ if (cline.didRejectTool) {
+ // Ignore any tool content after user has rejected tool once.
+ if (!block.partial) {
+ cline.userMessageContent.push({
+ type: "text",
+ text: `Skipping tool ${toolDescription()} due to user rejecting a previous tool.`,
+ })
+ } else {
+ // Partial tool after user rejected a previous tool.
+ cline.userMessageContent.push({
+ type: "text",
+ text: `Tool ${toolDescription()} was interrupted and not executed due to user rejecting a previous tool.`,
+ })
+ }
+
+ break
+ }
+
+ if (cline.didAlreadyUseTool) {
+ // Ignore any content after a tool has already been used.
+ cline.userMessageContent.push({
+ type: "text",
+ text: `Tool [${block.name}] was not executed because a tool has already been used in this message. Only one tool may be used per message. You must assess the first tool's result before proceeding to use the next tool.`,
+ })
+
+ break
+ }
+
+ const pushToolResult = (content: ToolResponse) => {
+ cline.userMessageContent.push({ type: "text", text: `${toolDescription()} Result:` })
+
+ if (typeof content === "string") {
+ cline.userMessageContent.push({ type: "text", text: content || "(tool did not return anything)" })
+ } else {
+ cline.userMessageContent.push(...content)
+ }
+
+ // Once a tool result has been collected, ignore all other tool
+ // uses since we should only ever present one tool result per
+ // message.
+ cline.didAlreadyUseTool = true
+ }
+
+ const askApproval = async (
+ type: ClineAsk,
+ partialMessage?: string,
+ progressStatus?: ToolProgressStatus,
+ ) => {
+ const { response, text, images } = await cline.ask(type, partialMessage, false, progressStatus)
+
+ if (response !== "yesButtonClicked") {
+ // Handle both messageResponse and noButtonClicked with text.
+ if (text) {
+ await cline.say("user_feedback", text, images)
+ pushToolResult(formatResponse.toolResult(formatResponse.toolDeniedWithFeedback(text), images))
+ } else {
+ pushToolResult(formatResponse.toolDenied())
+ }
+ cline.didRejectTool = true
+ return false
+ }
+
+ // Handle yesButtonClicked with text.
+ if (text) {
+ await cline.say("user_feedback", text, images)
+ pushToolResult(formatResponse.toolResult(formatResponse.toolApprovedWithFeedback(text), images))
+ }
+
+ return true
+ }
+
+ const askFinishSubTaskApproval = async () => {
+ // Ask the user to approve this task has completed, and he has
+ // reviewed it, and we can declare task is finished and return
+ // control to the parent task to continue running the rest of
+ // the sub-tasks.
+ const toolMessage = JSON.stringify({ tool: "finishTask" })
+ return await askApproval("tool", toolMessage)
+ }
+
+ const handleError = async (action: string, error: Error) => {
+ const errorString = `Error ${action}: ${JSON.stringify(serializeError(error))}`
+
+ await cline.say(
+ "error",
+ `Error ${action}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}`,
+ )
+
+ pushToolResult(formatResponse.toolError(errorString))
+ }
+
+ // If block is partial, remove partial closing tag so its not
+ // presented to user.
+ const removeClosingTag = (tag: ToolParamName, text?: string): string => {
+ if (!block.partial) {
+ return text || ""
+ }
+
+ if (!text) {
+ return ""
+ }
+
+ // This regex dynamically constructs a pattern to match the
+ // closing tag:
+ // - Optionally matches whitespace before the tag.
+ // - Matches '<' or '' optionally followed by any subset of
+ // characters from the tag name.
+ const tagRegex = new RegExp(
+ `\\s?<\/?${tag
+ .split("")
+ .map((char) => `(?:${char})?`)
+ .join("")}$`,
+ "g",
+ )
+
+ return text.replace(tagRegex, "")
+ }
+
+ if (block.name !== "browser_action") {
+ await cline.browserSession.closeBrowser()
+ }
+
+ if (!block.partial) {
+ cline.recordToolUsage(block.name)
+ telemetryService.captureToolUsage(cline.taskId, block.name)
+ }
+
+ // Validate tool use before execution.
+ const { mode, customModes } = (await cline.providerRef.deref()?.getState()) ?? {}
+
+ try {
+ validateToolUse(
+ block.name as ToolName,
+ mode ?? defaultModeSlug,
+ customModes ?? [],
+ { apply_diff: cline.diffEnabled },
+ block.params,
+ )
+ } catch (error) {
+ cline.consecutiveMistakeCount++
+ pushToolResult(formatResponse.toolError(error.message))
+ break
+ }
+
+ // Check for identical consecutive tool calls.
+ if (!block.partial) {
+ // Use the detector to check for repetition, passing the ToolUse
+ // block directly.
+ const repetitionCheck = cline.toolRepetitionDetector.check(block)
+
+ // If execution is not allowed, notify user and break.
+ if (!repetitionCheck.allowExecution && repetitionCheck.askUser) {
+ // Handle repetition similar to mistake_limit_reached pattern.
+ const { response, text, images } = await cline.ask(
+ repetitionCheck.askUser.messageKey as ClineAsk,
+ repetitionCheck.askUser.messageDetail.replace("{toolName}", block.name),
+ )
+
+ if (response === "messageResponse") {
+ // Add user feedback to userContent.
+ cline.userMessageContent.push(
+ {
+ type: "text" as const,
+ text: `Tool repetition limit reached. User feedback: ${text}`,
+ },
+ ...formatResponse.imageBlocks(images),
+ )
+
+ // Add user feedback to chat.
+ await cline.say("user_feedback", text, images)
+
+ // Track tool repetition in telemetry.
+ telemetryService.captureConsecutiveMistakeError(cline.taskId)
+ }
+
+ // Return tool result message about the repetition
+ pushToolResult(
+ formatResponse.toolError(
+ `Tool call repetition limit reached for ${block.name}. Please try a different approach.`,
+ ),
+ )
+ break
+ }
+ }
+
+ switch (block.name) {
+ case "write_to_file":
+ await writeToFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "apply_diff":
+ await applyDiffTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "insert_content":
+ await insertContentTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "search_and_replace":
+ await searchAndReplaceTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "read_file":
+ await readFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+
+ break
+ case "fetch_instructions":
+ await fetchInstructionsTool(cline, block, askApproval, handleError, pushToolResult)
+ break
+ case "list_files":
+ await listFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "list_code_definition_names":
+ await listCodeDefinitionNamesTool(
+ cline,
+ block,
+ askApproval,
+ handleError,
+ pushToolResult,
+ removeClosingTag,
+ )
+ break
+ case "search_files":
+ await searchFilesTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "browser_action":
+ await browserActionTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "execute_command":
+ await executeCommandTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "use_mcp_tool":
+ await useMcpToolTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "access_mcp_resource":
+ await accessMcpResourceTool(
+ cline,
+ block,
+ askApproval,
+ handleError,
+ pushToolResult,
+ removeClosingTag,
+ )
+ break
+ case "ask_followup_question":
+ await askFollowupQuestionTool(
+ cline,
+ block,
+ askApproval,
+ handleError,
+ pushToolResult,
+ removeClosingTag,
+ )
+ break
+ case "switch_mode":
+ await switchModeTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "new_task":
+ await newTaskTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
+ break
+ case "attempt_completion":
+ await attemptCompletionTool(
+ cline,
+ block,
+ askApproval,
+ handleError,
+ pushToolResult,
+ removeClosingTag,
+ toolDescription,
+ askFinishSubTaskApproval,
+ )
+ break
+ }
+
+ break
+ }
+
+ const recentlyModifiedFiles = cline.fileContextTracker.getAndClearCheckpointPossibleFile()
+
+ if (recentlyModifiedFiles.length > 0) {
+ // TODO: We can track what file changes were made and only
+ // checkpoint those files, this will be save storage.
+ await checkpointSave(cline)
+ }
+
+ // Seeing out of bounds is fine, it means that the next too call is being
+ // built up and ready to add to assistantMessageContent to present.
+ // When you see the UI inactive during this, it means that a tool is
+ // breaking without presenting any UI. For example the write_to_file tool
+ // was breaking when relpath was undefined, and for invalid relpath it never
+ // presented UI.
+ // This needs to be placed here, if not then calling
+ // cline.presentAssistantMessage below would fail (sometimes) since it's
+ // locked.
+ cline.presentAssistantMessageLocked = false
+
+ // NOTE: When tool is rejected, iterator stream is interrupted and it waits
+ // for `userMessageContentReady` to be true. Future calls to present will
+ // skip execution since `didRejectTool` and iterate until `contentIndex` is
+ // set to message length and it sets userMessageContentReady to true itself
+ // (instead of preemptively doing it in iterator).
+ if (!block.partial || cline.didRejectTool || cline.didAlreadyUseTool) {
+ // Block is finished streaming and executing.
+ if (cline.currentStreamingContentIndex === cline.assistantMessageContent.length - 1) {
+ // It's okay that we increment if !didCompleteReadingStream, it'll
+ // just return because out of bounds and as streaming continues it
+ // will call `presentAssitantMessage` if a new block is ready. If
+ // streaming is finished then we set `userMessageContentReady` to
+ // true when out of bounds. This gracefully allows the stream to
+ // continue on and all potential content blocks be presented.
+ // Last block is complete and it is finished executing
+ cline.userMessageContentReady = true // Will allow `pWaitFor` to continue.
+ }
+
+ // Call next block if it exists (if not then read stream will call it
+ // when it's ready).
+ // Need to increment regardless, so when read stream calls this function
+ // again it will be streaming the next block.
+ cline.currentStreamingContentIndex++
+
+ if (cline.currentStreamingContentIndex < cline.assistantMessageContent.length) {
+ // There are already more content blocks to stream, so we'll call
+ // this function ourselves.
+ presentAssistantMessage(cline)
+ return
+ }
+ }
+
+ // Block is partial, but the read stream may have finished.
+ if (cline.presentAssistantMessageHasPendingUpdates) {
+ presentAssistantMessage(cline)
+ }
+}
diff --git a/src/core/checkpoints/index.ts b/src/core/checkpoints/index.ts
new file mode 100644
index 00000000000..3a5c2dde455
--- /dev/null
+++ b/src/core/checkpoints/index.ts
@@ -0,0 +1,296 @@
+import pWaitFor from "p-wait-for"
+import * as vscode from "vscode"
+
+import { Task } from "../task/Task"
+
+import { getWorkspacePath } from "../../utils/path"
+
+import { ClineApiReqInfo } from "../../shared/ExtensionMessage"
+import { getApiMetrics } from "../../shared/getApiMetrics"
+
+import { DIFF_VIEW_URI_SCHEME } from "../../integrations/editor/DiffViewProvider"
+
+import { telemetryService } from "../../services/telemetry/TelemetryService"
+import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../../services/checkpoints"
+
+export function getCheckpointService(cline: Task) {
+ if (!cline.enableCheckpoints) {
+ return undefined
+ }
+
+ if (cline.checkpointService) {
+ return cline.checkpointService
+ }
+
+ if (cline.checkpointServiceInitializing) {
+ console.log("[Cline#getCheckpointService] checkpoint service is still initializing")
+ return undefined
+ }
+
+ const provider = cline.providerRef.deref()
+
+ const log = (message: string) => {
+ console.log(message)
+
+ try {
+ provider?.log(message)
+ } catch (err) {
+ // NO-OP
+ }
+ }
+
+ console.log("[Cline#getCheckpointService] initializing checkpoints service")
+
+ try {
+ const workspaceDir = getWorkspacePath()
+
+ if (!workspaceDir) {
+ log("[Cline#getCheckpointService] workspace folder not found, disabling checkpoints")
+ cline.enableCheckpoints = false
+ return undefined
+ }
+
+ const globalStorageDir = provider?.context.globalStorageUri.fsPath
+
+ if (!globalStorageDir) {
+ log("[Cline#getCheckpointService] globalStorageDir not found, disabling checkpoints")
+ cline.enableCheckpoints = false
+ return undefined
+ }
+
+ const options: CheckpointServiceOptions = {
+ taskId: cline.taskId,
+ workspaceDir,
+ shadowDir: globalStorageDir,
+ log,
+ }
+
+ const service = RepoPerTaskCheckpointService.create(options)
+
+ cline.checkpointServiceInitializing = true
+
+ service.on("initialize", () => {
+ log("[Cline#getCheckpointService] service initialized")
+
+ try {
+ const isCheckpointNeeded =
+ typeof cline.clineMessages.find(({ say }) => say === "checkpoint_saved") === "undefined"
+
+ cline.checkpointService = service
+ cline.checkpointServiceInitializing = false
+
+ if (isCheckpointNeeded) {
+ log("[Cline#getCheckpointService] no checkpoints found, saving initial checkpoint")
+ checkpointSave(cline)
+ }
+ } catch (err) {
+ log("[Cline#getCheckpointService] caught error in on('initialize'), disabling checkpoints")
+ cline.enableCheckpoints = false
+ }
+ })
+
+ service.on("checkpoint", ({ isFirst, fromHash: from, toHash: to }) => {
+ try {
+ provider?.postMessageToWebview({ type: "currentCheckpointUpdated", text: to })
+
+ cline
+ .say("checkpoint_saved", to, undefined, undefined, { isFirst, from, to }, undefined, {
+ isNonInteractive: true,
+ })
+ .catch((err) => {
+ log("[Cline#getCheckpointService] caught unexpected error in say('checkpoint_saved')")
+ console.error(err)
+ })
+ } catch (err) {
+ log("[Cline#getCheckpointService] caught unexpected error in on('checkpoint'), disabling checkpoints")
+ console.error(err)
+ cline.enableCheckpoints = false
+ }
+ })
+
+ log("[Cline#getCheckpointService] initializing shadow git")
+
+ service.initShadowGit().catch((err) => {
+ log(
+ `[Cline#getCheckpointService] caught unexpected error in initShadowGit, disabling checkpoints (${err.message})`,
+ )
+
+ console.error(err)
+ cline.enableCheckpoints = false
+ })
+
+ return service
+ } catch (err) {
+ log("[Cline#getCheckpointService] caught unexpected error, disabling checkpoints")
+ cline.enableCheckpoints = false
+ return undefined
+ }
+}
+
+async function getInitializedCheckpointService(
+ cline: Task,
+ { interval = 250, timeout = 15_000 }: { interval?: number; timeout?: number } = {},
+) {
+ const service = getCheckpointService(cline)
+
+ if (!service || service.isInitialized) {
+ return service
+ }
+
+ try {
+ await pWaitFor(
+ () => {
+ console.log("[Cline#getCheckpointService] waiting for service to initialize")
+ return service.isInitialized
+ },
+ { interval, timeout },
+ )
+
+ return service
+ } catch (err) {
+ return undefined
+ }
+}
+
+export async function checkpointSave(cline: Task) {
+ const service = getCheckpointService(cline)
+
+ if (!service) {
+ return
+ }
+
+ if (!service.isInitialized) {
+ const provider = cline.providerRef.deref()
+ provider?.log("[checkpointSave] checkpoints didn't initialize in time, disabling checkpoints for this task")
+ cline.enableCheckpoints = false
+ return
+ }
+
+ telemetryService.captureCheckpointCreated(cline.taskId)
+
+ // Start the checkpoint process in the background.
+ return service.saveCheckpoint(`Task: ${cline.taskId}, Time: ${Date.now()}`).catch((err) => {
+ console.error("[Cline#checkpointSave] caught unexpected error, disabling checkpoints", err)
+ cline.enableCheckpoints = false
+ })
+}
+
+export type CheckpointRestoreOptions = {
+ ts: number
+ commitHash: string
+ mode: "preview" | "restore"
+}
+
+export async function checkpointRestore(cline: Task, { ts, commitHash, mode }: CheckpointRestoreOptions) {
+ const service = await getInitializedCheckpointService(cline)
+
+ if (!service) {
+ return
+ }
+
+ const index = cline.clineMessages.findIndex((m) => m.ts === ts)
+
+ if (index === -1) {
+ return
+ }
+
+ const provider = cline.providerRef.deref()
+
+ try {
+ await service.restoreCheckpoint(commitHash)
+ telemetryService.captureCheckpointRestored(cline.taskId)
+ await provider?.postMessageToWebview({ type: "currentCheckpointUpdated", text: commitHash })
+
+ if (mode === "restore") {
+ await cline.overwriteApiConversationHistory(cline.apiConversationHistory.filter((m) => !m.ts || m.ts < ts))
+
+ const deletedMessages = cline.clineMessages.slice(index + 1)
+
+ const { totalTokensIn, totalTokensOut, totalCacheWrites, totalCacheReads, totalCost } = getApiMetrics(
+ cline.combineMessages(deletedMessages),
+ )
+
+ await cline.overwriteClineMessages(cline.clineMessages.slice(0, index + 1))
+
+ // TODO: Verify that this is working as expected.
+ await cline.say(
+ "api_req_deleted",
+ JSON.stringify({
+ tokensIn: totalTokensIn,
+ tokensOut: totalTokensOut,
+ cacheWrites: totalCacheWrites,
+ cacheReads: totalCacheReads,
+ cost: totalCost,
+ } satisfies ClineApiReqInfo),
+ )
+ }
+
+ // The task is already cancelled by the provider beforehand, but we
+ // need to re-init to get the updated messages.
+ //
+ // This was take from Cline's implementation of the checkpoints
+ // feature. The cline instance will hang if we don't cancel twice,
+ // so this is currently necessary, but it seems like a complicated
+ // and hacky solution to a problem that I don't fully understand.
+ // I'd like to revisit this in the future and try to improve the
+ // task flow and the communication between the webview and the
+ // Cline instance.
+ provider?.cancelTask()
+ } catch (err) {
+ provider?.log("[checkpointRestore] disabling checkpoints for this task")
+ cline.enableCheckpoints = false
+ }
+}
+
+export type CheckpointDiffOptions = {
+ ts: number
+ previousCommitHash?: string
+ commitHash: string
+ mode: "full" | "checkpoint"
+}
+
+export async function checkpointDiff(cline: Task, { ts, previousCommitHash, commitHash, mode }: CheckpointDiffOptions) {
+ const service = await getInitializedCheckpointService(cline)
+
+ if (!service) {
+ return
+ }
+
+ telemetryService.captureCheckpointDiffed(cline.taskId)
+
+ if (!previousCommitHash && mode === "checkpoint") {
+ const previousCheckpoint = cline.clineMessages
+ .filter(({ say }) => say === "checkpoint_saved")
+ .sort((a, b) => b.ts - a.ts)
+ .find((message) => message.ts < ts)
+
+ previousCommitHash = previousCheckpoint?.text
+ }
+
+ try {
+ const changes = await service.getDiff({ from: previousCommitHash, to: commitHash })
+
+ if (!changes?.length) {
+ vscode.window.showInformationMessage("No changes found.")
+ return
+ }
+
+ await vscode.commands.executeCommand(
+ "vscode.changes",
+ mode === "full" ? "Changes since task started" : "Changes since previous checkpoint",
+ changes.map((change) => [
+ vscode.Uri.file(change.paths.absolute),
+ vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${change.paths.relative}`).with({
+ query: Buffer.from(change.content.before ?? "").toString("base64"),
+ }),
+ vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${change.paths.relative}`).with({
+ query: Buffer.from(change.content.after ?? "").toString("base64"),
+ }),
+ ]),
+ )
+ } catch (err) {
+ const provider = cline.providerRef.deref()
+ provider?.log("[checkpointDiff] disabling checkpoints for this task")
+ cline.enableCheckpoints = false
+ }
+}
diff --git a/src/core/condense/__tests__/index.test.ts b/src/core/condense/__tests__/index.test.ts
new file mode 100644
index 00000000000..10769589f86
--- /dev/null
+++ b/src/core/condense/__tests__/index.test.ts
@@ -0,0 +1,228 @@
+import { describe, expect, it, jest, beforeEach } from "@jest/globals"
+import { ApiHandler } from "../../../api"
+import { ApiMessage } from "../../task-persistence/apiMessages"
+import { maybeRemoveImageBlocks } from "../../../api/transform/image-cleaning"
+import { summarizeConversation, getMessagesSinceLastSummary, N_MESSAGES_TO_KEEP } from "../index"
+
+// Mock dependencies
+jest.mock("../../../api/transform/image-cleaning", () => ({
+ maybeRemoveImageBlocks: jest.fn((messages: ApiMessage[], _apiHandler: ApiHandler) => [...messages]),
+}))
+
+describe("getMessagesSinceLastSummary", () => {
+ it("should return all messages when there is no summary", () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "user", content: "How are you?", ts: 3 },
+ ]
+
+ const result = getMessagesSinceLastSummary(messages)
+ expect(result).toEqual(messages)
+ })
+
+ it("should return messages since the last summary", () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "assistant", content: "Summary of conversation", ts: 3, isSummary: true },
+ { role: "user", content: "How are you?", ts: 4 },
+ { role: "assistant", content: "I'm good", ts: 5 },
+ ]
+
+ const result = getMessagesSinceLastSummary(messages)
+ expect(result).toEqual([
+ { role: "assistant", content: "Summary of conversation", ts: 3, isSummary: true },
+ { role: "user", content: "How are you?", ts: 4 },
+ { role: "assistant", content: "I'm good", ts: 5 },
+ ])
+ })
+
+ it("should handle multiple summary messages and return since the last one", () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "First summary", ts: 2, isSummary: true },
+ { role: "user", content: "How are you?", ts: 3 },
+ { role: "assistant", content: "Second summary", ts: 4, isSummary: true },
+ { role: "user", content: "What's new?", ts: 5 },
+ ]
+
+ const result = getMessagesSinceLastSummary(messages)
+ expect(result).toEqual([
+ { role: "assistant", content: "Second summary", ts: 4, isSummary: true },
+ { role: "user", content: "What's new?", ts: 5 },
+ ])
+ })
+
+ it("should handle empty messages array", () => {
+ const result = getMessagesSinceLastSummary([])
+ expect(result).toEqual([])
+ })
+})
+
+describe("summarizeConversation", () => {
+ // Mock ApiHandler
+ let mockApiHandler: ApiHandler
+ let mockStream: AsyncGenerator
+
+ beforeEach(() => {
+ // Reset mocks
+ jest.clearAllMocks()
+
+ // Setup mock stream
+ mockStream = (async function* () {
+ yield { type: "text" as const, text: "This is " }
+ yield { type: "text" as const, text: "a summary" }
+ })()
+
+ // Setup mock API handler
+ mockApiHandler = {
+ createMessage: jest.fn().mockReturnValue(mockStream),
+ countTokens: jest.fn().mockImplementation(() => Promise.resolve(100)),
+ getModel: jest.fn().mockReturnValue({
+ id: "test-model",
+ info: {
+ contextWindow: 8000,
+ supportsImages: true,
+ supportsComputerUse: true,
+ supportsVision: true,
+ maxTokens: 4000,
+ supportsPromptCache: true,
+ maxCachePoints: 10,
+ minTokensPerCachePoint: 100,
+ cachableFields: ["system", "messages"],
+ },
+ }),
+ } as unknown as ApiHandler
+ })
+
+ it("should not summarize when there are not enough messages", async () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ ]
+
+ const result = await summarizeConversation(messages, mockApiHandler)
+ expect(result).toEqual(messages)
+ expect(mockApiHandler.createMessage).not.toHaveBeenCalled()
+ })
+
+ it("should not summarize when there was a recent summary", async () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "user", content: "How are you?", ts: 3 },
+ { role: "assistant", content: "I'm good", ts: 4 },
+ { role: "user", content: "What's new?", ts: 5 },
+ { role: "assistant", content: "Not much", ts: 6, isSummary: true }, // Recent summary
+ { role: "user", content: "Tell me more", ts: 7 },
+ ]
+
+ const result = await summarizeConversation(messages, mockApiHandler)
+ expect(result).toEqual(messages)
+ expect(mockApiHandler.createMessage).not.toHaveBeenCalled()
+ })
+
+ it("should summarize conversation and insert summary message", async () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "user", content: "How are you?", ts: 3 },
+ { role: "assistant", content: "I'm good", ts: 4 },
+ { role: "user", content: "What's new?", ts: 5 },
+ { role: "assistant", content: "Not much", ts: 6 },
+ { role: "user", content: "Tell me more", ts: 7 },
+ ]
+
+ const result = await summarizeConversation(messages, mockApiHandler)
+
+ // Check that the API was called correctly
+ expect(mockApiHandler.createMessage).toHaveBeenCalled()
+ expect(maybeRemoveImageBlocks).toHaveBeenCalled()
+
+ // Verify the structure of the result
+ // The result should be: original messages (except last N) + summary + last N messages
+ expect(result.length).toBe(messages.length + 1) // Original + summary
+
+ // Check that the summary message was inserted correctly
+ const summaryMessage = result[result.length - N_MESSAGES_TO_KEEP - 1]
+ expect(summaryMessage.role).toBe("assistant")
+ expect(summaryMessage.content).toBe("This is a summary")
+ expect(summaryMessage.isSummary).toBe(true)
+
+ // Check that the last N_MESSAGES_TO_KEEP messages are preserved
+ const lastMessages = messages.slice(-N_MESSAGES_TO_KEEP)
+ expect(result.slice(-N_MESSAGES_TO_KEEP)).toEqual(lastMessages)
+ })
+
+ it("should handle empty summary response", async () => {
+ // We need enough messages to trigger summarization
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "user", content: "How are you?", ts: 3 },
+ { role: "assistant", content: "I'm good", ts: 4 },
+ { role: "user", content: "What's new?", ts: 5 },
+ { role: "assistant", content: "Not much", ts: 6 },
+ { role: "user", content: "Tell me more", ts: 7 },
+ ]
+
+ // Mock console.warn before we call the function
+ const originalWarn = console.warn
+ const mockWarn = jest.fn()
+ console.warn = mockWarn
+
+ // Setup empty summary response
+ const emptyStream = (async function* () {
+ yield { type: "text" as const, text: "" }
+ })()
+
+ // Create a new mock for createMessage that returns empty stream
+ const createMessageMock = jest.fn().mockReturnValue(emptyStream)
+ mockApiHandler.createMessage = createMessageMock as any
+
+ // We need to mock maybeRemoveImageBlocks to return the expected messages
+ ;(maybeRemoveImageBlocks as jest.Mock).mockImplementationOnce((messages: any) => {
+ return messages.map(({ role, content }: { role: string; content: any }) => ({ role, content }))
+ })
+
+ const result = await summarizeConversation(messages, mockApiHandler)
+
+ // Should return original messages when summary is empty
+ expect(result).toEqual(messages)
+ expect(mockWarn).toHaveBeenCalledWith("Received empty summary from API")
+
+ // Restore console.warn
+ console.warn = originalWarn
+ })
+
+ it("should correctly format the request to the API", async () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Hello", ts: 1 },
+ { role: "assistant", content: "Hi there", ts: 2 },
+ { role: "user", content: "How are you?", ts: 3 },
+ { role: "assistant", content: "I'm good", ts: 4 },
+ { role: "user", content: "What's new?", ts: 5 },
+ { role: "assistant", content: "Not much", ts: 6 },
+ { role: "user", content: "Tell me more", ts: 7 },
+ ]
+
+ await summarizeConversation(messages, mockApiHandler)
+
+ // Verify the final request message
+ const expectedFinalMessage = {
+ role: "user",
+ content: "Summarize the conversation so far, as described in the prompt instructions.",
+ }
+
+ // Verify that createMessage was called with the correct prompt
+ expect(mockApiHandler.createMessage).toHaveBeenCalledWith(
+ expect.stringContaining("Your task is to create a detailed summary of the conversation"),
+ expect.any(Array),
+ )
+
+ // Check that maybeRemoveImageBlocks was called with the correct messages
+ const mockCallArgs = (maybeRemoveImageBlocks as jest.Mock).mock.calls[0][0] as any[]
+ expect(mockCallArgs[mockCallArgs.length - 1]).toEqual(expectedFinalMessage)
+ })
+})
diff --git a/src/core/condense/index.ts b/src/core/condense/index.ts
new file mode 100644
index 00000000000..2a88dbfccee
--- /dev/null
+++ b/src/core/condense/index.ts
@@ -0,0 +1,105 @@
+import Anthropic from "@anthropic-ai/sdk"
+import { ApiHandler } from "../../api"
+import { ApiMessage } from "../task-persistence/apiMessages"
+import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
+
+export const N_MESSAGES_TO_KEEP = 3
+
+const SUMMARY_PROMPT = `\
+Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions.
+This summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the conversation and supporting any continuing tasks.
+
+Your summary should be structured as follows:
+Context: The context to continue the conversation with. If applicable based on the current task, this should include:
+ 1. Previous Conversation: High level details about what was discussed throughout the entire conversation with the user. This should be written to allow someone to be able to follow the general overarching conversation flow.
+ 2. Current Work: Describe in detail what was being worked on prior to this request to summarize the conversation. Pay special attention to the more recent messages in the conversation.
+ 3. Key Technical Concepts: List all important technical concepts, technologies, coding conventions, and frameworks discussed, which might be relevant for continuing with this work.
+ 4. Relevant Files and Code: If applicable, enumerate specific files and code sections examined, modified, or created for the task continuation. Pay special attention to the most recent messages and changes.
+ 5. Problem Solving: Document problems solved thus far and any ongoing troubleshooting efforts.
+ 6. Pending Tasks and Next Steps: Outline all pending tasks that you have explicitly been asked to work on, as well as list the next steps you will take for all outstanding work, if applicable. Include code snippets where they add clarity. For any next steps, include direct quotes from the most recent conversation showing exactly what task you were working on and where you left off. This should be verbatim to ensure there's no information loss in context between tasks.
+
+Example summary structure:
+1. Previous Conversation:
+ [Detailed description]
+2. Current Work:
+ [Detailed description]
+3. Key Technical Concepts:
+ - [Concept 1]
+ - [Concept 2]
+ - [...]
+4. Relevant Files and Code:
+ - [File Name 1]
+ - [Summary of why this file is important]
+ - [Summary of the changes made to this file, if any]
+ - [Important Code Snippet]
+ - [File Name 2]
+ - [Important Code Snippet]
+ - [...]
+5. Problem Solving:
+ [Detailed description]
+6. Pending Tasks and Next Steps:
+ - [Task 1 details & next steps]
+ - [Task 2 details & next steps]
+ - [...]
+
+Output only the summary of the conversation so far, without any additional commentary or explanation.
+`
+
+/**
+ * Summarizes the conversation messages using an LLM call
+ *
+ * @param {ApiMessage[]} messages - The conversation messages
+ * @param {ApiHandler} apiHandler - The API handler to use for token counting.
+ * @returns {ApiMessage[]} - The input messages, potentially including a new summary message before the last message.
+ */
+export async function summarizeConversation(messages: ApiMessage[], apiHandler: ApiHandler): Promise {
+ const messagesToSummarize = getMessagesSinceLastSummary(messages.slice(0, -N_MESSAGES_TO_KEEP))
+ if (messagesToSummarize.length <= 1) {
+ return messages // Not enough messages to warrant a summary
+ }
+ const keepMessages = messages.slice(-N_MESSAGES_TO_KEEP)
+ for (const message of keepMessages) {
+ if (message.isSummary) {
+ return messages // We recently summarized these messages; it's too soon to summarize again.
+ }
+ }
+ const finalRequestMessage: Anthropic.MessageParam = {
+ role: "user",
+ content: "Summarize the conversation so far, as described in the prompt instructions.",
+ }
+ const requestMessages = maybeRemoveImageBlocks([...messagesToSummarize, finalRequestMessage], apiHandler).map(
+ ({ role, content }) => ({ role, content }),
+ )
+ // Note: this doesn't need to be a stream, consider using something like apiHandler.completePrompt
+ const stream = apiHandler.createMessage(SUMMARY_PROMPT, requestMessages)
+ let summary = ""
+ // TODO(canyon): compute usage and cost for this operation and update the global metrics.
+ for await (const chunk of stream) {
+ if (chunk.type === "text") {
+ summary += chunk.text
+ }
+ }
+ summary = summary.trim()
+ if (summary.length === 0) {
+ console.warn("Received empty summary from API")
+ return messages
+ }
+ const summaryMessage: ApiMessage = {
+ role: "assistant",
+ content: summary,
+ ts: keepMessages[0].ts,
+ isSummary: true,
+ }
+
+ return [...messages.slice(0, -N_MESSAGES_TO_KEEP), summaryMessage, ...keepMessages]
+}
+
+/* Returns the list of all messages since the last summary message, including the summary. Returns all messages if there is no summary. */
+export function getMessagesSinceLastSummary(messages: ApiMessage[]): ApiMessage[] {
+ let lastSummaryIndexReverse = [...messages].reverse().findIndex((message) => message.isSummary)
+ if (lastSummaryIndexReverse === -1) {
+ return messages
+ }
+ const lastSummaryIndex = messages.length - lastSummaryIndexReverse - 1
+ return messages.slice(lastSummaryIndex)
+}
diff --git a/src/core/config/ProviderSettingsManager.ts b/src/core/config/ProviderSettingsManager.ts
index ca53cba8892..d22a87e0974 100644
--- a/src/core/config/ProviderSettingsManager.ts
+++ b/src/core/config/ProviderSettingsManager.ts
@@ -1,11 +1,14 @@
import { ExtensionContext } from "vscode"
import { z, ZodError } from "zod"
-import { providerSettingsSchema, ApiConfigMeta } from "../../schemas"
+import { providerSettingsSchema, ProviderSettingsEntry, providerSettingsSchemaDiscriminated } from "../../schemas"
import { Mode, modes } from "../../shared/modes"
import { telemetryService } from "../../services/telemetry/TelemetryService"
const providerSettingsWithIdSchema = providerSettingsSchema.extend({ id: z.string().optional() })
+const discriminatedProviderSettingsWithIdSchema = providerSettingsSchemaDiscriminated.and(
+ z.object({ id: z.string().optional() }),
+)
type ProviderSettingsWithId = z.infer
@@ -79,6 +82,18 @@ export class ProviderSettingsManager {
let isDirty = false
+ // Migrate existing installs to have per-mode API config map
+ if (!providerProfiles.modeApiConfigs) {
+ // Use the currently selected config for all modes initially
+ const currentName = providerProfiles.currentApiConfigName
+ const seedId =
+ providerProfiles.apiConfigs[currentName]?.id ??
+ Object.values(providerProfiles.apiConfigs)[0]?.id ??
+ this.defaultConfigId
+ providerProfiles.modeApiConfigs = Object.fromEntries(modes.map((m) => [m.slug, seedId]))
+ isDirty = true
+ }
+
// Ensure all configs have IDs.
for (const [_name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
if (!apiConfig.id) {
@@ -211,7 +226,7 @@ export class ProviderSettingsManager {
/**
* List all available configs with metadata.
*/
- public async listConfig(): Promise {
+ public async listConfig(): Promise {
try {
return await this.lock(async () => {
const providerProfiles = await this.load()
@@ -232,66 +247,81 @@ export class ProviderSettingsManager {
* Preserves the ID from the input 'config' object if it exists,
* otherwise generates a new one (for creation scenarios).
*/
- public async saveConfig(name: string, config: ProviderSettingsWithId) {
+ public async saveConfig(name: string, config: ProviderSettingsWithId): Promise {
try {
return await this.lock(async () => {
const providerProfiles = await this.load()
// Preserve the existing ID if this is an update to an existing config.
const existingId = providerProfiles.apiConfigs[name]?.id
- providerProfiles.apiConfigs[name] = { ...config, id: config.id || existingId || this.generateId() }
+ const id = config.id || existingId || this.generateId()
+
+ // Filter out settings from other providers.
+ const filteredConfig = providerSettingsSchemaDiscriminated.parse(config)
+ providerProfiles.apiConfigs[name] = { ...filteredConfig, id }
await this.store(providerProfiles)
+ return id
})
} catch (error) {
throw new Error(`Failed to save config: ${error}`)
}
}
- /**
- * Load a config by name and set it as the current config.
- */
- public async loadConfig(name: string) {
+ public async getProfile(
+ params: { name: string } | { id: string },
+ ): Promise {
try {
return await this.lock(async () => {
const providerProfiles = await this.load()
- const providerSettings = providerProfiles.apiConfigs[name]
+ let name: string
+ let providerSettings: ProviderSettingsWithId
- if (!providerSettings) {
- throw new Error(`Config '${name}' not found`)
- }
+ if ("name" in params) {
+ name = params.name
- providerProfiles.currentApiConfigName = name
- await this.store(providerProfiles)
+ if (!providerProfiles.apiConfigs[name]) {
+ throw new Error(`Config with name '${name}' not found`)
+ }
+
+ providerSettings = providerProfiles.apiConfigs[name]
+ } else {
+ const id = params.id
+
+ const entry = Object.entries(providerProfiles.apiConfigs).find(
+ ([_, apiConfig]) => apiConfig.id === id,
+ )
- return providerSettings
+ if (!entry) {
+ throw new Error(`Config with ID '${id}' not found`)
+ }
+
+ name = entry[0]
+ providerSettings = entry[1]
+ }
+
+ return { name, ...providerSettings }
})
} catch (error) {
- throw new Error(`Failed to load config: ${error}`)
+ throw new Error(`Failed to get profile: ${error instanceof Error ? error.message : error}`)
}
}
/**
- * Load a config by ID and set it as the current config.
+ * Activate a profile by name or ID.
*/
- public async loadConfigById(id: string) {
+ public async activateProfile(
+ params: { name: string } | { id: string },
+ ): Promise {
+ const { name, ...providerSettings } = await this.getProfile(params)
+
try {
return await this.lock(async () => {
const providerProfiles = await this.load()
- const providerSettings = Object.entries(providerProfiles.apiConfigs).find(
- ([_, apiConfig]) => apiConfig.id === id,
- )
-
- if (!providerSettings) {
- throw new Error(`Config with ID '${id}' not found`)
- }
-
- const [name, apiConfig] = providerSettings
providerProfiles.currentApiConfigName = name
await this.store(providerProfiles)
-
- return { config: apiConfig, name }
+ return { name, ...providerSettings }
})
} catch (error) {
- throw new Error(`Failed to load config by ID: ${error}`)
+ throw new Error(`Failed to activate profile: ${error instanceof Error ? error.message : error}`)
}
}
@@ -340,8 +370,12 @@ export class ProviderSettingsManager {
try {
return await this.lock(async () => {
const providerProfiles = await this.load()
- const { modeApiConfigs = {} } = providerProfiles
- modeApiConfigs[mode] = configId
+ // Ensure the per-mode config map exists
+ if (!providerProfiles.modeApiConfigs) {
+ providerProfiles.modeApiConfigs = {}
+ }
+ // Assign the chosen config ID to this mode
+ providerProfiles.modeApiConfigs[mode] = configId
await this.store(providerProfiles)
})
} catch (error) {
@@ -365,7 +399,15 @@ export class ProviderSettingsManager {
public async export() {
try {
- return await this.lock(async () => providerProfilesSchema.parse(await this.load()))
+ return await this.lock(async () => {
+ const profiles = providerProfilesSchema.parse(await this.load())
+ const configs = profiles.apiConfigs
+ for (const name in configs) {
+ // Avoid leaking properties from other providers.
+ configs[name] = discriminatedProviderSettingsWithIdSchema.parse(configs[name])
+ }
+ return profiles
+ })
} catch (error) {
throw new Error(`Failed to export provider profiles: ${error}`)
}
diff --git a/src/core/config/__tests__/ProviderSettingsManager.test.ts b/src/core/config/__tests__/ProviderSettingsManager.test.ts
index 3cacc4c8b72..7e505440958 100644
--- a/src/core/config/__tests__/ProviderSettingsManager.test.ts
+++ b/src/core/config/__tests__/ProviderSettingsManager.test.ts
@@ -53,6 +53,7 @@ describe("ProviderSettingsManager", () => {
fuzzyMatchThreshold: 1.0,
},
},
+ modeApiConfigs: {},
migrations: {
rateLimitSecondsMigrated: true,
diffSettingsMigrated: true,
@@ -220,8 +221,9 @@ describe("ProviderSettingsManager", () => {
)
const newConfig: ProviderSettings = {
- apiProvider: "anthropic",
- apiKey: "test-key",
+ apiProvider: "vertex",
+ apiModelId: "gemini-2.5-flash-preview-04-17",
+ vertexKeyFile: "test-key-file",
}
await providerSettingsManager.saveConfig("test", newConfig)
@@ -246,10 +248,58 @@ describe("ProviderSettingsManager", () => {
},
}
- expect(mockSecrets.store).toHaveBeenCalledWith(
- "roo_cline_config_api_config",
- JSON.stringify(expectedConfig, null, 2),
+ expect(mockSecrets.store.mock.calls[0][0]).toEqual("roo_cline_config_api_config")
+ expect(storedConfig).toEqual(expectedConfig)
+ })
+
+ it("should only save provider relevant settings", async () => {
+ mockSecrets.get.mockResolvedValue(
+ JSON.stringify({
+ currentApiConfigName: "default",
+ apiConfigs: {
+ default: {},
+ },
+ modeApiConfigs: {
+ code: "default",
+ architect: "default",
+ ask: "default",
+ },
+ }),
)
+
+ const newConfig: ProviderSettings = {
+ apiProvider: "anthropic",
+ apiKey: "test-key",
+ }
+ const newConfigWithExtra: ProviderSettings = {
+ ...newConfig,
+ openRouterApiKey: "another-key",
+ }
+
+ await providerSettingsManager.saveConfig("test", newConfigWithExtra)
+
+ // Get the actual stored config to check the generated ID
+ const storedConfig = JSON.parse(mockSecrets.store.mock.lastCall[1])
+ const testConfigId = storedConfig.apiConfigs.test.id
+
+ const expectedConfig = {
+ currentApiConfigName: "default",
+ apiConfigs: {
+ default: {},
+ test: {
+ ...newConfig,
+ id: testConfigId,
+ },
+ },
+ modeApiConfigs: {
+ code: "default",
+ architect: "default",
+ ask: "default",
+ },
+ }
+
+ expect(mockSecrets.store.mock.calls[0][0]).toEqual("roo_cline_config_api_config")
+ expect(storedConfig).toEqual(expectedConfig)
})
it("should update existing config", async () => {
@@ -290,10 +340,9 @@ describe("ProviderSettingsManager", () => {
},
}
- expect(mockSecrets.store).toHaveBeenCalledWith(
- "roo_cline_config_api_config",
- JSON.stringify(expectedConfig, null, 2),
- )
+ const storedConfig = JSON.parse(mockSecrets.store.mock.lastCall[1])
+ expect(mockSecrets.store.mock.lastCall[0]).toEqual("roo_cline_config_api_config")
+ expect(storedConfig).toEqual(expectedConfig)
})
it("should throw error if secrets storage fails", async () => {
@@ -390,17 +439,15 @@ describe("ProviderSettingsManager", () => {
mockGlobalState.get.mockResolvedValue(42)
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
- const config = await providerSettingsManager.loadConfig("test")
+ const { name, ...providerSettings } = await providerSettingsManager.activateProfile({ name: "test" })
- expect(config).toEqual({
- apiProvider: "anthropic",
- apiKey: "test-key",
- id: "test-id",
- })
+ expect(name).toBe("test")
+ expect(providerSettings).toEqual({ apiProvider: "anthropic", apiKey: "test-key", id: "test-id" })
- // Get the stored config to check the structure
+ // Get the stored config to check the structure.
const storedConfig = JSON.parse(mockSecrets.store.mock.calls[1][1])
expect(storedConfig.currentApiConfigName).toBe("test")
+
expect(storedConfig.apiConfigs.test).toEqual({
apiProvider: "anthropic",
apiKey: "test-key",
@@ -412,17 +459,12 @@ describe("ProviderSettingsManager", () => {
mockSecrets.get.mockResolvedValue(
JSON.stringify({
currentApiConfigName: "default",
- apiConfigs: {
- default: {
- config: {},
- id: "default",
- },
- },
+ apiConfigs: { default: { config: {}, id: "default" } },
}),
)
- await expect(providerSettingsManager.loadConfig("nonexistent")).rejects.toThrow(
- "Config 'nonexistent' not found",
+ await expect(providerSettingsManager.activateProfile({ name: "nonexistent" })).rejects.toThrow(
+ "Config with name 'nonexistent' not found",
)
})
@@ -430,20 +472,13 @@ describe("ProviderSettingsManager", () => {
mockSecrets.get.mockResolvedValue(
JSON.stringify({
currentApiConfigName: "default",
- apiConfigs: {
- test: {
- config: {
- apiProvider: "anthropic",
- },
- id: "test-id",
- },
- },
+ apiConfigs: { test: { config: { apiProvider: "anthropic" }, id: "test-id" } },
}),
)
mockSecrets.store.mockRejectedValueOnce(new Error("Storage failed"))
- await expect(providerSettingsManager.loadConfig("test")).rejects.toThrow(
- "Failed to load config: Error: Failed to write provider profiles to secrets: Error: Storage failed",
+ await expect(providerSettingsManager.activateProfile({ name: "test" })).rejects.toThrow(
+ "Failed to activate profile: Failed to write provider profiles to secrets: Error: Storage failed",
)
})
@@ -493,12 +528,7 @@ describe("ProviderSettingsManager", () => {
mockSecrets.get.mockResolvedValue(
JSON.stringify({
currentApiConfigName: "test",
- apiConfigs: {
- test: {
- apiProvider: "anthropic",
- id: "test-id",
- },
- },
+ apiConfigs: { test: { apiProvider: "anthropic", id: "test-id" } },
}),
)
@@ -513,18 +543,8 @@ describe("ProviderSettingsManager", () => {
it("should return true for existing config", async () => {
const existingConfig: ProviderProfiles = {
currentApiConfigName: "default",
- apiConfigs: {
- default: {
- id: "default",
- },
- test: {
- apiProvider: "anthropic",
- id: "test-id",
- },
- },
- migrations: {
- rateLimitSecondsMigrated: false,
- },
+ apiConfigs: { default: { id: "default" }, test: { apiProvider: "anthropic", id: "test-id" } },
+ migrations: { rateLimitSecondsMigrated: false },
}
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
@@ -535,10 +555,7 @@ describe("ProviderSettingsManager", () => {
it("should return false for non-existent config", async () => {
mockSecrets.get.mockResolvedValue(
- JSON.stringify({
- currentApiConfigName: "default",
- apiConfigs: { default: {} },
- }),
+ JSON.stringify({ currentApiConfigName: "default", apiConfigs: { default: {} } }),
)
const hasConfig = await providerSettingsManager.hasConfig("nonexistent")
diff --git a/src/core/diff/strategies/__tests__/multi-search-replace.test.ts b/src/core/diff/strategies/__tests__/multi-search-replace.test.ts
index 37edcccb62f..dc971d3a10c 100644
--- a/src/core/diff/strategies/__tests__/multi-search-replace.test.ts
+++ b/src/core/diff/strategies/__tests__/multi-search-replace.test.ts
@@ -2332,6 +2332,54 @@ function two() {
function three() {
return "three";
+}`)
+ }
+ })
+
+ it("should deduce start_line when include line number in search and replace content", async () => {
+ const originalContent = `
+function one() {
+ return 1;
+}
+
+function process() {
+ return "target";
+}
+
+function process() {
+ return "target";
+}
+
+function two() {
+ return 2;
+}
+`.trim()
+ const diffContent = `test.ts
+<<<<<<< SEARCH
+9 | function process() {
+10 | return "target";
+=======
+9 | function process2() {
+10 | return "target222";
+>>>>>>> REPLACE`
+
+ const result = await strategy.applyDiff(originalContent, diffContent)
+ expect(result.success).toBe(true)
+ if (result.success) {
+ expect(result.content).toBe(`function one() {
+ return 1;
+}
+
+function process() {
+ return "target";
+}
+
+function process2() {
+ return "target222";
+}
+
+function two() {
+ return 2;
}`)
}
})
diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts
index 7c07f06ba0b..144b794f758 100644
--- a/src/core/diff/strategies/multi-search-replace.ts
+++ b/src/core/diff/strategies/multi-search-replace.ts
@@ -380,6 +380,10 @@ Only use a single line of '=======' between search and replacement content, beca
(everyLineHasLineNumbers(searchContent) && everyLineHasLineNumbers(replaceContent)) ||
(everyLineHasLineNumbers(searchContent) && replaceContent.trim() === "")
+ if (hasAllLineNumbers && startLine === 0) {
+ startLine = parseInt(searchContent.split("\n")[0].split("|")[0])
+ }
+
if (hasAllLineNumbers) {
searchContent = stripLineNumbers(searchContent)
replaceContent = stripLineNumbers(replaceContent)
diff --git a/src/core/environment/__tests__/getEnvironmentDetails.test.ts b/src/core/environment/__tests__/getEnvironmentDetails.test.ts
new file mode 100644
index 00000000000..008b0de14e2
--- /dev/null
+++ b/src/core/environment/__tests__/getEnvironmentDetails.test.ts
@@ -0,0 +1,316 @@
+// npx jest src/core/environment/__tests__/getEnvironmentDetails.test.ts
+
+import pWaitFor from "p-wait-for"
+import delay from "delay"
+
+import { getEnvironmentDetails } from "../getEnvironmentDetails"
+import { EXPERIMENT_IDS, experiments } from "../../../shared/experiments"
+import { defaultModeSlug, getFullModeDetails, getModeBySlug, isToolAllowedForMode } from "../../../shared/modes"
+import { getApiMetrics } from "../../../shared/getApiMetrics"
+import { listFiles } from "../../../services/glob/list-files"
+import { TerminalRegistry } from "../../../integrations/terminal/TerminalRegistry"
+import { Terminal } from "../../../integrations/terminal/Terminal"
+import { arePathsEqual } from "../../../utils/path"
+import { FileContextTracker } from "../../context-tracking/FileContextTracker"
+import { ApiHandler } from "../../../api/index"
+import { ClineProvider } from "../../webview/ClineProvider"
+import { RooIgnoreController } from "../../ignore/RooIgnoreController"
+import { formatResponse } from "../../prompts/responses"
+import { Task } from "../../task/Task"
+
+jest.mock("vscode", () => ({
+ window: {
+ tabGroups: { all: [], onDidChangeTabs: jest.fn() },
+ visibleTextEditors: [],
+ },
+ env: {
+ language: "en-US",
+ },
+}))
+
+jest.mock("p-wait-for")
+
+jest.mock("delay")
+
+jest.mock("execa", () => ({
+ execa: jest.fn(),
+}))
+
+jest.mock("../../../shared/experiments")
+jest.mock("../../../shared/modes")
+jest.mock("../../../shared/getApiMetrics")
+jest.mock("../../../services/glob/list-files")
+jest.mock("../../../integrations/terminal/TerminalRegistry")
+jest.mock("../../../integrations/terminal/Terminal")
+jest.mock("../../../utils/path")
+jest.mock("../../prompts/responses")
+
+describe("getEnvironmentDetails", () => {
+ const mockCwd = "/test/path"
+ const mockTaskId = "test-task-id"
+
+ type MockTerminal = {
+ id: string
+ getLastCommand: jest.Mock
+ getProcessesWithOutput: jest.Mock
+ cleanCompletedProcessQueue?: jest.Mock
+ }
+
+ let mockCline: Partial
+ let mockProvider: any
+ let mockState: any
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+
+ mockState = {
+ terminalOutputLineLimit: 100,
+ maxWorkspaceFiles: 50,
+ maxOpenTabsContext: 10,
+ mode: "code",
+ customModes: [],
+ experiments: {},
+ customInstructions: "test instructions",
+ language: "en",
+ showRooIgnoredFiles: true,
+ }
+
+ mockProvider = {
+ getState: jest.fn().mockResolvedValue(mockState),
+ }
+
+ mockCline = {
+ cwd: mockCwd,
+ taskId: mockTaskId,
+ didEditFile: false,
+ fileContextTracker: {
+ getAndClearRecentlyModifiedFiles: jest.fn().mockReturnValue([]),
+ } as unknown as FileContextTracker,
+ rooIgnoreController: {
+ filterPaths: jest.fn((paths: string[]) => paths.join("\n")),
+ cwd: mockCwd,
+ ignoreInstance: {},
+ disposables: [],
+ rooIgnoreContent: "",
+ isPathIgnored: jest.fn(),
+ getIgnoreContent: jest.fn(),
+ updateIgnoreContent: jest.fn(),
+ addToIgnore: jest.fn(),
+ removeFromIgnore: jest.fn(),
+ dispose: jest.fn(),
+ } as unknown as RooIgnoreController,
+ clineMessages: [],
+ api: {
+ getModel: jest.fn().mockReturnValue({ id: "test-model", info: { contextWindow: 100000 } }),
+ createMessage: jest.fn(),
+ countTokens: jest.fn(),
+ } as unknown as ApiHandler,
+ diffEnabled: true,
+ providerRef: {
+ deref: jest.fn().mockReturnValue(mockProvider),
+ [Symbol.toStringTag]: "WeakRef",
+ } as unknown as WeakRef,
+ }
+
+ // Mock other dependencies.
+ ;(getApiMetrics as jest.Mock).mockReturnValue({ contextTokens: 50000, totalCost: 0.25 })
+ ;(getFullModeDetails as jest.Mock).mockResolvedValue({
+ name: "💻 Code",
+ roleDefinition: "You are a code assistant",
+ customInstructions: "Custom instructions",
+ })
+ ;(isToolAllowedForMode as jest.Mock).mockReturnValue(true)
+ ;(listFiles as jest.Mock).mockResolvedValue([["file1.ts", "file2.ts"], false])
+ ;(formatResponse.formatFilesList as jest.Mock).mockReturnValue("file1.ts\nfile2.ts")
+ ;(arePathsEqual as jest.Mock).mockReturnValue(false)
+ ;(Terminal.compressTerminalOutput as jest.Mock).mockImplementation((output: string) => output)
+ ;(TerminalRegistry.getTerminals as jest.Mock).mockReturnValue([])
+ ;(TerminalRegistry.getBackgroundTerminals as jest.Mock).mockReturnValue([])
+ ;(TerminalRegistry.isProcessHot as jest.Mock).mockReturnValue(false)
+ ;(TerminalRegistry.getUnretrievedOutput as jest.Mock).mockReturnValue("")
+ ;(pWaitFor as unknown as jest.Mock).mockResolvedValue(undefined)
+ ;(delay as jest.Mock).mockResolvedValue(undefined)
+ })
+
+ it("should return basic environment details", async () => {
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("")
+ expect(result).toContain("")
+ expect(result).toContain("# VSCode Visible Files")
+ expect(result).toContain("# VSCode Open Tabs")
+ expect(result).toContain("# Current Time")
+ expect(result).toContain("# Current Context Size (Tokens)")
+ expect(result).toContain("# Current Cost")
+ expect(result).toContain("# Current Mode")
+ expect(result).toContain("test-model")
+
+ expect(mockProvider.getState).toHaveBeenCalled()
+
+ expect(getFullModeDetails).toHaveBeenCalledWith("code", [], undefined, {
+ cwd: mockCwd,
+ globalCustomInstructions: "test instructions",
+ language: "en",
+ })
+
+ expect(getApiMetrics).toHaveBeenCalledWith(mockCline.clineMessages)
+ })
+
+ it("should include file details when includeFileDetails is true", async () => {
+ const result = await getEnvironmentDetails(mockCline as Task, true)
+ expect(result).toContain("# Current Workspace Directory")
+ expect(result).toContain("Files")
+
+ expect(listFiles).toHaveBeenCalledWith(mockCwd, true, 50)
+
+ expect(formatResponse.formatFilesList).toHaveBeenCalledWith(
+ mockCwd,
+ ["file1.ts", "file2.ts"],
+ false,
+ mockCline.rooIgnoreController,
+ true,
+ )
+ })
+
+ it("should not include file details when includeFileDetails is false", async () => {
+ await getEnvironmentDetails(mockCline as Task, false)
+ expect(listFiles).not.toHaveBeenCalled()
+ expect(formatResponse.formatFilesList).not.toHaveBeenCalled()
+ })
+
+ it("should handle desktop directory specially", async () => {
+ ;(arePathsEqual as jest.Mock).mockReturnValue(true)
+ const result = await getEnvironmentDetails(mockCline as Task, true)
+ expect(result).toContain("Desktop files not shown automatically")
+ expect(listFiles).not.toHaveBeenCalled()
+ })
+
+ it("should include recently modified files if any", async () => {
+ ;(mockCline.fileContextTracker!.getAndClearRecentlyModifiedFiles as jest.Mock).mockReturnValue([
+ "modified1.ts",
+ "modified2.ts",
+ ])
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("# Recently Modified Files")
+ expect(result).toContain("modified1.ts")
+ expect(result).toContain("modified2.ts")
+ })
+
+ it("should include active terminal information", async () => {
+ const mockActiveTerminal = {
+ id: "terminal-1",
+ getLastCommand: jest.fn().mockReturnValue("npm test"),
+ getProcessesWithOutput: jest.fn().mockReturnValue([]),
+ } as MockTerminal
+
+ ;(TerminalRegistry.getTerminals as jest.Mock).mockReturnValue([mockActiveTerminal])
+ ;(TerminalRegistry.getUnretrievedOutput as jest.Mock).mockReturnValue("Test output")
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("# Actively Running Terminals")
+ expect(result).toContain("Original command: `npm test`")
+ expect(result).toContain("Test output")
+
+ mockCline.didEditFile = true
+ await getEnvironmentDetails(mockCline as Task)
+ expect(delay).toHaveBeenCalledWith(300)
+
+ expect(pWaitFor).toHaveBeenCalled()
+ })
+
+ it("should include inactive terminals with output", async () => {
+ const mockProcess = {
+ command: "npm build",
+ getUnretrievedOutput: jest.fn().mockReturnValue("Build output"),
+ }
+
+ const mockInactiveTerminal = {
+ id: "terminal-2",
+ getProcessesWithOutput: jest.fn().mockReturnValue([mockProcess]),
+ cleanCompletedProcessQueue: jest.fn(),
+ } as MockTerminal
+
+ ;(TerminalRegistry.getTerminals as jest.Mock).mockImplementation((active: boolean) =>
+ active ? [] : [mockInactiveTerminal],
+ )
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("# Inactive Terminals with Completed Process Output")
+ expect(result).toContain("Terminal terminal-2")
+ expect(result).toContain("Command: `npm build`")
+ expect(result).toContain("Build output")
+
+ expect(mockInactiveTerminal.cleanCompletedProcessQueue).toHaveBeenCalled()
+ })
+
+ it("should include warning when file writing is not allowed", async () => {
+ ;(isToolAllowedForMode as jest.Mock).mockReturnValue(false)
+ ;(getModeBySlug as jest.Mock).mockImplementation((slug: string) => {
+ if (slug === "code") {
+ return { name: "💻 Code" }
+ }
+
+ if (slug === defaultModeSlug) {
+ return { name: "Default Mode" }
+ }
+
+ return null
+ })
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("NOTE: You are currently in '💻 Code' mode, which does not allow write operations")
+ })
+
+ it("should include experiment-specific details when Power Steering is enabled", async () => {
+ mockState.experiments = { [EXPERIMENT_IDS.POWER_STEERING]: true }
+ ;(experiments.isEnabled as jest.Mock).mockReturnValue(true)
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ expect(result).toContain("You are a code assistant")
+ expect(result).toContain("Custom instructions")
+ })
+
+ it("should handle missing provider or state", async () => {
+ // Mock provider to return null.
+ mockCline.providerRef!.deref = jest.fn().mockReturnValue(null)
+
+ const result = await getEnvironmentDetails(mockCline as Task)
+
+ // Verify the function still returns a result.
+ expect(result).toContain("")
+ expect(result).toContain("")
+
+ // Mock provider to return null state.
+ mockCline.providerRef!.deref = jest.fn().mockReturnValue({
+ getState: jest.fn().mockResolvedValue(null),
+ })
+
+ const result2 = await getEnvironmentDetails(mockCline as Task)
+
+ // Verify the function still returns a result.
+ expect(result2).toContain("")
+ expect(result2).toContain("")
+ })
+
+ it("should handle errors gracefully", async () => {
+ ;(pWaitFor as unknown as jest.Mock).mockRejectedValue(new Error("Test error"))
+
+ const mockErrorTerminal = {
+ id: "terminal-1",
+ getLastCommand: jest.fn().mockReturnValue("npm test"),
+ getProcessesWithOutput: jest.fn().mockReturnValue([]),
+ } as MockTerminal
+
+ ;(TerminalRegistry.getTerminals as jest.Mock).mockReturnValue([mockErrorTerminal])
+ ;(TerminalRegistry.getBackgroundTerminals as jest.Mock).mockReturnValue([])
+ ;(mockCline.fileContextTracker!.getAndClearRecentlyModifiedFiles as jest.Mock).mockReturnValue([])
+
+ await expect(getEnvironmentDetails(mockCline as Task)).resolves.not.toThrow()
+ })
+})
diff --git a/src/core/environment/getEnvironmentDetails.ts b/src/core/environment/getEnvironmentDetails.ts
new file mode 100644
index 00000000000..3d8a9cdbc3a
--- /dev/null
+++ b/src/core/environment/getEnvironmentDetails.ts
@@ -0,0 +1,269 @@
+import path from "path"
+import os from "os"
+
+import * as vscode from "vscode"
+import pWaitFor from "p-wait-for"
+import delay from "delay"
+
+import { EXPERIMENT_IDS, experiments as Experiments, ExperimentId } from "../../shared/experiments"
+import { formatLanguage } from "../../shared/language"
+import { defaultModeSlug, getFullModeDetails, getModeBySlug, isToolAllowedForMode } from "../../shared/modes"
+import { getApiMetrics } from "../../shared/getApiMetrics"
+import { listFiles } from "../../services/glob/list-files"
+import { TerminalRegistry } from "../../integrations/terminal/TerminalRegistry"
+import { Terminal } from "../../integrations/terminal/Terminal"
+import { arePathsEqual } from "../../utils/path"
+import { formatResponse } from "../prompts/responses"
+
+import { Task } from "../task/Task"
+
+export async function getEnvironmentDetails(cline: Task, includeFileDetails: boolean = false) {
+ let details = ""
+
+ const clineProvider = cline.providerRef.deref()
+ const state = await clineProvider?.getState()
+ const { terminalOutputLineLimit = 500, maxWorkspaceFiles = 200 } = state ?? {}
+
+ // It could be useful for cline to know if the user went from one or no
+ // file to another between messages, so we always include this context.
+ details += "\n\n# VSCode Visible Files"
+
+ const visibleFilePaths = vscode.window.visibleTextEditors
+ ?.map((editor) => editor.document?.uri?.fsPath)
+ .filter(Boolean)
+ .map((absolutePath) => path.relative(cline.cwd, absolutePath))
+ .slice(0, maxWorkspaceFiles)
+
+ // Filter paths through rooIgnoreController
+ const allowedVisibleFiles = cline.rooIgnoreController
+ ? cline.rooIgnoreController.filterPaths(visibleFilePaths)
+ : visibleFilePaths.map((p) => p.toPosix()).join("\n")
+
+ if (allowedVisibleFiles) {
+ details += `\n${allowedVisibleFiles}`
+ } else {
+ details += "\n(No visible files)"
+ }
+
+ details += "\n\n# VSCode Open Tabs"
+ const { maxOpenTabsContext } = state ?? {}
+ const maxTabs = maxOpenTabsContext ?? 20
+ const openTabPaths = vscode.window.tabGroups.all
+ .flatMap((group) => group.tabs)
+ .map((tab) => (tab.input as vscode.TabInputText)?.uri?.fsPath)
+ .filter(Boolean)
+ .map((absolutePath) => path.relative(cline.cwd, absolutePath).toPosix())
+ .slice(0, maxTabs)
+
+ // Filter paths through rooIgnoreController
+ const allowedOpenTabs = cline.rooIgnoreController
+ ? cline.rooIgnoreController.filterPaths(openTabPaths)
+ : openTabPaths.map((p) => p.toPosix()).join("\n")
+
+ if (allowedOpenTabs) {
+ details += `\n${allowedOpenTabs}`
+ } else {
+ details += "\n(No open tabs)"
+ }
+
+ // Get task-specific and background terminals.
+ const busyTerminals = [
+ ...TerminalRegistry.getTerminals(true, cline.taskId),
+ ...TerminalRegistry.getBackgroundTerminals(true),
+ ]
+
+ const inactiveTerminals = [
+ ...TerminalRegistry.getTerminals(false, cline.taskId),
+ ...TerminalRegistry.getBackgroundTerminals(false),
+ ]
+
+ if (busyTerminals.length > 0) {
+ if (cline.didEditFile) {
+ await delay(300) // Delay after saving file to let terminals catch up.
+ }
+
+ // Wait for terminals to cool down.
+ await pWaitFor(() => busyTerminals.every((t) => !TerminalRegistry.isProcessHot(t.id)), {
+ interval: 100,
+ timeout: 5_000,
+ }).catch(() => {})
+ }
+
+ // Reset, this lets us know when to wait for saved files to update terminals.
+ cline.didEditFile = false
+
+ // Waiting for updated diagnostics lets terminal output be the most
+ // up-to-date possible.
+ let terminalDetails = ""
+
+ if (busyTerminals.length > 0) {
+ // Terminals are cool, let's retrieve their output.
+ terminalDetails += "\n\n# Actively Running Terminals"
+
+ for (const busyTerminal of busyTerminals) {
+ terminalDetails += `\n## Original command: \`${busyTerminal.getLastCommand()}\``
+ let newOutput = TerminalRegistry.getUnretrievedOutput(busyTerminal.id)
+
+ if (newOutput) {
+ newOutput = Terminal.compressTerminalOutput(newOutput, terminalOutputLineLimit)
+ terminalDetails += `\n### New Output\n${newOutput}`
+ }
+ }
+ }
+
+ // First check if any inactive terminals in this task have completed
+ // processes with output.
+ const terminalsWithOutput = inactiveTerminals.filter((terminal) => {
+ const completedProcesses = terminal.getProcessesWithOutput()
+ return completedProcesses.length > 0
+ })
+
+ // Only add the header if there are terminals with output.
+ if (terminalsWithOutput.length > 0) {
+ terminalDetails += "\n\n# Inactive Terminals with Completed Process Output"
+
+ // Process each terminal with output.
+ for (const inactiveTerminal of terminalsWithOutput) {
+ let terminalOutputs: string[] = []
+
+ // Get output from completed processes queue.
+ const completedProcesses = inactiveTerminal.getProcessesWithOutput()
+
+ for (const process of completedProcesses) {
+ let output = process.getUnretrievedOutput()
+
+ if (output) {
+ output = Terminal.compressTerminalOutput(output, terminalOutputLineLimit)
+ terminalOutputs.push(`Command: \`${process.command}\`\n${output}`)
+ }
+ }
+
+ // Clean the queue after retrieving output.
+ inactiveTerminal.cleanCompletedProcessQueue()
+
+ // Add this terminal's outputs to the details.
+ if (terminalOutputs.length > 0) {
+ terminalDetails += `\n## Terminal ${inactiveTerminal.id}`
+ terminalOutputs.forEach((output) => {
+ terminalDetails += `\n### New Output\n${output}`
+ })
+ }
+ }
+ }
+
+ // console.log(`[Cline#getEnvironmentDetails] terminalDetails: ${terminalDetails}`)
+
+ // Add recently modified files section.
+ const recentlyModifiedFiles = cline.fileContextTracker.getAndClearRecentlyModifiedFiles()
+
+ if (recentlyModifiedFiles.length > 0) {
+ details +=
+ "\n\n# Recently Modified Files\nThese files have been modified since you last accessed them (file was just edited so you may need to re-read it before editing):"
+ for (const filePath of recentlyModifiedFiles) {
+ details += `\n${filePath}`
+ }
+ }
+
+ if (terminalDetails) {
+ details += terminalDetails
+ }
+
+ // Add current time information with timezone.
+ const now = new Date()
+
+ const formatter = new Intl.DateTimeFormat(undefined, {
+ year: "numeric",
+ month: "numeric",
+ day: "numeric",
+ hour: "numeric",
+ minute: "numeric",
+ second: "numeric",
+ hour12: true,
+ })
+
+ const timeZone = formatter.resolvedOptions().timeZone
+ const timeZoneOffset = -now.getTimezoneOffset() / 60 // Convert to hours and invert sign to match conventional notation
+ const timeZoneOffsetHours = Math.floor(Math.abs(timeZoneOffset))
+ const timeZoneOffsetMinutes = Math.abs(Math.round((Math.abs(timeZoneOffset) - timeZoneOffsetHours) * 60))
+ const timeZoneOffsetStr = `${timeZoneOffset >= 0 ? "+" : "-"}${timeZoneOffsetHours}:${timeZoneOffsetMinutes.toString().padStart(2, "0")}`
+ details += `\n\n# Current Time\n${formatter.format(now)} (${timeZone}, UTC${timeZoneOffsetStr})`
+
+ // Add context tokens information.
+ const { contextTokens, totalCost } = getApiMetrics(cline.clineMessages)
+ const { id: modelId, info: modelInfo } = cline.api.getModel()
+ const contextWindow = modelInfo.contextWindow
+
+ const contextPercentage =
+ contextTokens && contextWindow ? Math.round((contextTokens / contextWindow) * 100) : undefined
+
+ details += `\n\n# Current Context Size (Tokens)\n${contextTokens ? `${contextTokens.toLocaleString()} (${contextPercentage}%)` : "(Not available)"}`
+ details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
+
+ // Add current mode and any mode-specific warnings.
+ const {
+ mode,
+ customModes,
+ customModePrompts,
+ experiments = {} as Record,
+ customInstructions: globalCustomInstructions,
+ language,
+ } = state ?? {}
+
+ const currentMode = mode ?? defaultModeSlug
+
+ const modeDetails = await getFullModeDetails(currentMode, customModes, customModePrompts, {
+ cwd: cline.cwd,
+ globalCustomInstructions,
+ language: language ?? formatLanguage(vscode.env.language),
+ })
+
+ details += `\n\n# Current Mode\n`
+ details += `${currentMode}\n`
+ details += `${modeDetails.name}\n`
+ details += `${modelId}\n`
+
+ if (Experiments.isEnabled(experiments ?? {}, EXPERIMENT_IDS.POWER_STEERING)) {
+ details += `${modeDetails.roleDefinition}\n`
+
+ if (modeDetails.customInstructions) {
+ details += `${modeDetails.customInstructions}\n`
+ }
+ }
+
+ // Add warning if not in code mode.
+ if (
+ !isToolAllowedForMode("write_to_file", currentMode, customModes ?? [], { apply_diff: cline.diffEnabled }) &&
+ !isToolAllowedForMode("apply_diff", currentMode, customModes ?? [], { apply_diff: cline.diffEnabled })
+ ) {
+ const currentModeName = getModeBySlug(currentMode, customModes)?.name ?? currentMode
+ const defaultModeName = getModeBySlug(defaultModeSlug, customModes)?.name ?? defaultModeSlug
+ details += `\n\nNOTE: You are currently in '${currentModeName}' mode, which does not allow write operations. To write files, the user will need to switch to a mode that supports file writing, such as '${defaultModeName}' mode.`
+ }
+
+ if (includeFileDetails) {
+ details += `\n\n# Current Workspace Directory (${cline.cwd.toPosix()}) Files\n`
+ const isDesktop = arePathsEqual(cline.cwd, path.join(os.homedir(), "Desktop"))
+
+ if (isDesktop) {
+ // Don't want to immediately access desktop since it would show
+ // permission popup.
+ details += "(Desktop files not shown automatically. Use list_files to explore if needed.)"
+ } else {
+ const maxFiles = maxWorkspaceFiles ?? 200
+ const [files, didHitLimit] = await listFiles(cline.cwd, true, maxFiles)
+ const { showRooIgnoredFiles = true } = state ?? {}
+
+ const result = formatResponse.formatFilesList(
+ cline.cwd,
+ files,
+ didHitLimit,
+ cline.rooIgnoreController,
+ showRooIgnoredFiles,
+ )
+
+ details += result
+ }
+ }
+
+ return `\n${details.trim()}\n`
+}
diff --git a/src/core/mentions/index.ts b/src/core/mentions/index.ts
index 2e75a10ce3d..d53a3ff3ed7 100644
--- a/src/core/mentions/index.ts
+++ b/src/core/mentions/index.ts
@@ -4,14 +4,17 @@ import * as path from "path"
import * as vscode from "vscode"
import { isBinaryFile } from "isbinaryfile"
-import { openFile } from "../../integrations/misc/open-file"
-import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
import { mentionRegexGlobal, unescapeSpaces } from "../../shared/context-mentions"
-import { extractTextFromFile } from "../../integrations/misc/extract-text"
-import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
import { getCommitInfo, getWorkingState } from "../../utils/git"
import { getWorkspacePath } from "../../utils/path"
+
+import { openFile } from "../../integrations/misc/open-file"
+import { extractTextFromFile } from "../../integrations/misc/extract-text"
+import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
+
+import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
+
import { FileContextTracker } from "../context-tracking/FileContextTracker"
export async function openMention(mention?: string): Promise {
@@ -273,3 +276,6 @@ export async function getLatestTerminalOutput(): Promise {
await vscode.env.clipboard.writeText(originalClipboard)
}
}
+
+// Export processUserContentMentions from its own file
+export { processUserContentMentions } from "./processUserContentMentions"
diff --git a/src/core/mentions/processUserContentMentions.ts b/src/core/mentions/processUserContentMentions.ts
new file mode 100644
index 00000000000..2b69486a867
--- /dev/null
+++ b/src/core/mentions/processUserContentMentions.ts
@@ -0,0 +1,81 @@
+import { Anthropic } from "@anthropic-ai/sdk"
+import { parseMentions } from "./index"
+import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
+import { FileContextTracker } from "../context-tracking/FileContextTracker"
+
+/**
+ * Process mentions in user content, specifically within task and feedback tags
+ */
+export async function processUserContentMentions({
+ userContent,
+ cwd,
+ urlContentFetcher,
+ fileContextTracker,
+}: {
+ userContent: Anthropic.Messages.ContentBlockParam[]
+ cwd: string
+ urlContentFetcher: UrlContentFetcher
+ fileContextTracker: FileContextTracker
+}) {
+ // Process userContent array, which contains various block types:
+ // TextBlockParam, ImageBlockParam, ToolUseBlockParam, and ToolResultBlockParam.
+ // We need to apply parseMentions() to:
+ // 1. All TextBlockParam's text (first user message with task)
+ // 2. ToolResultBlockParam's content/context text arrays if it contains
+ // "" (see formatToolDeniedFeedback, attemptCompletion,
+ // executeCommand, and consecutiveMistakeCount >= 3) or ""
+ // (see askFollowupQuestion), we place all user generated content in
+ // these tags so they can effectively be used as markers for when we
+ // should parse mentions).
+ return Promise.all(
+ userContent.map(async (block) => {
+ const shouldProcessMentions = (text: string) => text.includes("") || text.includes("")
+
+ if (block.type === "text") {
+ if (shouldProcessMentions(block.text)) {
+ return {
+ ...block,
+ text: await parseMentions(block.text, cwd, urlContentFetcher, fileContextTracker),
+ }
+ }
+
+ return block
+ } else if (block.type === "tool_result") {
+ if (typeof block.content === "string") {
+ if (shouldProcessMentions(block.content)) {
+ return {
+ ...block,
+ content: await parseMentions(block.content, cwd, urlContentFetcher, fileContextTracker),
+ }
+ }
+
+ return block
+ } else if (Array.isArray(block.content)) {
+ const parsedContent = await Promise.all(
+ block.content.map(async (contentBlock) => {
+ if (contentBlock.type === "text" && shouldProcessMentions(contentBlock.text)) {
+ return {
+ ...contentBlock,
+ text: await parseMentions(
+ contentBlock.text,
+ cwd,
+ urlContentFetcher,
+ fileContextTracker,
+ ),
+ }
+ }
+
+ return contentBlock
+ }),
+ )
+
+ return { ...block, content: parsedContent }
+ }
+
+ return block
+ }
+
+ return block
+ }),
+ )
+}
diff --git a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap
index 34f9fa45b77..f8f115c4ca3 100644
--- a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap
@@ -5,27 +5,33 @@ exports[`SYSTEM_PROMPT should exclude diff strategy tool description when diffEn
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -348,10 +354,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -485,27 +491,33 @@ exports[`SYSTEM_PROMPT should exclude diff strategy tool description when diffEn
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -828,10 +840,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -965,27 +977,33 @@ exports[`SYSTEM_PROMPT should explicitly handle undefined mcpHub 1`] = `
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -1308,10 +1326,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -1445,27 +1463,33 @@ exports[`SYSTEM_PROMPT should handle different browser viewport sizes 1`] = `
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -1841,10 +1865,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -1981,27 +2005,33 @@ exports[`SYSTEM_PROMPT should include MCP server info when mcpHub is provided 1`
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -2373,10 +2403,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -2529,27 +2559,33 @@ exports[`SYSTEM_PROMPT should include browser actions when supportsComputerUse i
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -2925,10 +2961,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -3065,27 +3101,33 @@ exports[`SYSTEM_PROMPT should include diff strategy tool description when diffEn
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -3508,10 +3550,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -3645,27 +3687,33 @@ exports[`SYSTEM_PROMPT should maintain consistent system prompt 1`] = `
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -3988,10 +4036,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -4167,27 +4215,33 @@ exports[`addCustomInstructions should exclude MCP server creation info when disa
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -4559,10 +4613,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -4724,27 +4778,33 @@ exports[`addCustomInstructions should generate correct prompt for architect mode
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -5045,10 +5105,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -5195,27 +5255,33 @@ exports[`addCustomInstructions should generate correct prompt for ask mode 1`] =
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -5413,10 +5479,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
@@ -5539,7 +5605,7 @@ Language Preference:
You should always speak and think in the "en" language.
Mode-specific Instructions:
-You can analyze code, explain concepts, and access external resources. Make sure to answer the user's questions and don't rush to switch to implementing code. Include Mermaid diagrams if they help make your response clearer.
+You can analyze code, explain concepts, and access external resources. Always answer the user’s questions thoroughly, and do not switch to implementing code unless explicitly requested by the user. Include Mermaid diagrams when they clarify your response.
Rules:
# Rules from .clinerules-ask:
@@ -5583,27 +5649,33 @@ exports[`addCustomInstructions should include MCP server creation info when enab
====
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in
+
+====
+
TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.
+Always use the actual tool name as the XML tag name for proper parsing and execution.
# Tools
@@ -5975,10 +6047,10 @@ Example: Requesting to switch to code mode
## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
diff --git a/src/core/prompts/instructions/create-mode.ts b/src/core/prompts/instructions/create-mode.ts
index ad02f6b6ab5..fe7509c1de0 100644
--- a/src/core/prompts/instructions/create-mode.ts
+++ b/src/core/prompts/instructions/create-mode.ts
@@ -26,7 +26,9 @@ If asked to create a project mode, create it in ${AGENT_MODES_FILE_NAME} in the
* roleDefinition: A detailed description of the mode's role and capabilities
* groups: Array of allowed tool groups (can be empty). Each group can be specified either as a string (e.g., "edit" to allow editing any file) or with file restrictions (e.g., ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }] to only allow editing markdown files)
-- The customInstructions field is optional.
+- The following fields are optional but highly recommended:
+ * whenToUse: A clear description of when this mode should be selected and what types of tasks it's best suited for. This helps the Orchestrator mode make better decisions.
+ * customInstructions: Additional instructions for how the mode should operate
- For multi-line text, include newline characters in the string like "This is the first line.\\nThis is the next line.\\n\\nThis is a double line break."
@@ -37,6 +39,7 @@ Both files should follow this structure:
"slug": "designer", // Required: unique slug with lowercase letters, numbers, and hyphens
"name": "Designer", // Required: mode display name
"roleDefinition": "You are PearAI (Powered by Roo Code / Cline), a UI/UX expert specializing in design systems and frontend development. Your expertise includes:\\n- Creating and maintaining design systems\\n- Implementing responsive and accessible web interfaces\\n- Working with CSS, HTML, and modern frontend frameworks\\n- Ensuring consistent user experiences across platforms", // Required: non-empty
+ "whenToUse": "Use this mode when creating or modifying UI components, implementing design systems, or ensuring responsive web interfaces. This mode is especially effective with CSS, HTML, and modern frontend frameworks.", // Optional but recommended
"groups": [ // Required: array of tool groups (can be empty)
"read", // Read files group (read_file, fetch_instructions, search_files, list_files, list_code_definition_names)
"edit", // Edit files group (apply_diff, write_to_file) - allows editing any file
diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts
index 9c82a848804..8238b969e2b 100644
--- a/src/core/prompts/responses.ts
+++ b/src/core/prompts/responses.ts
@@ -185,15 +185,15 @@ const formatImagesIntoBlocks = (images?: string[]): Anthropic.ImageBlockParam[]
const toolUseInstructionsReminder = `# Reminder: Instructions for Tool Use
-Tool uses are formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the attempt_completion tool:
@@ -201,4 +201,4 @@ I have completed the task...
-Always adhere to this format for all tool uses to ensure proper parsing and execution.`
+Always use the actual tool name as the XML tag name for proper parsing and execution.`
diff --git a/src/core/prompts/sections/index.ts b/src/core/prompts/sections/index.ts
index a9f8c9e4c6d..d06dbbfde1d 100644
--- a/src/core/prompts/sections/index.ts
+++ b/src/core/prompts/sections/index.ts
@@ -7,3 +7,4 @@ export { getMcpServersSection } from "./mcp-servers"
export { getToolUseGuidelinesSection } from "./tool-use-guidelines"
export { getCapabilitiesSection } from "./capabilities"
export { getModesSection } from "./modes"
+export { markdownFormattingSection } from "./markdown-formatting"
diff --git a/src/core/prompts/sections/markdown-formatting.ts b/src/core/prompts/sections/markdown-formatting.ts
new file mode 100644
index 00000000000..fe152a1a41d
--- /dev/null
+++ b/src/core/prompts/sections/markdown-formatting.ts
@@ -0,0 +1,7 @@
+export function markdownFormattingSection(): string {
+ return `====
+
+MARKDOWN RULES
+
+ALL responses MUST show ANY \`language construct\` OR filename reterence as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in `
+}
diff --git a/src/core/prompts/sections/modes.ts b/src/core/prompts/sections/modes.ts
index 0fa5e065760..ff12098d5e9 100644
--- a/src/core/prompts/sections/modes.ts
+++ b/src/core/prompts/sections/modes.ts
@@ -16,7 +16,19 @@ export async function getModesSection(context: vscode.ExtensionContext): Promise
MODES
- These are the currently available modes:
-${allModes.map((mode: ModeConfig) => ` * "${mode.name}" mode (${mode.slug}) - ${mode.roleDefinition.split(".")[0]}`).join("\n")}`
+${allModes
+ .map((mode: ModeConfig) => {
+ let description: string
+ if (mode.whenToUse && mode.whenToUse.trim() !== "") {
+ // Use whenToUse as the primary description, indenting subsequent lines for readability
+ description = mode.whenToUse.replace(/\n/g, "\n ")
+ } else {
+ // Fallback to the first sentence of roleDefinition if whenToUse is not available
+ description = mode.roleDefinition.split(".")[0]
+ }
+ return ` * "${mode.name}" mode (${mode.slug}) - ${description}`
+ })
+ .join("\n")}`
modesContent += `
If the user asks you to create or edit a new mode for this project, you should read the instructions by using the fetch_instructions tool, like this:
diff --git a/src/core/prompts/sections/tool-use.ts b/src/core/prompts/sections/tool-use.ts
index e5671871ce7..b75e4dad921 100644
--- a/src/core/prompts/sections/tool-use.ts
+++ b/src/core/prompts/sections/tool-use.ts
@@ -7,19 +7,19 @@ You have access to a set of tools that are executed upon the user's approval. Yo
# Tool Use Formatting
-Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
+Tool uses are formatted using XML-style tags. The tool name itself becomes the XML tag name. Each parameter is enclosed within its own set of tags. Here's the structure:
-
+
value1
value2
...
-
+
-For example:
+For example, to use the read_file tool:
src/main.js
-Always adhere to this format for the tool use to ensure proper parsing and execution.`
+Always use the actual tool name as the XML tag name for proper parsing and execution.`
}
diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts
index f56a9476637..92eba6bdc7c 100644
--- a/src/core/prompts/system.ts
+++ b/src/core/prompts/system.ts
@@ -24,6 +24,7 @@ import {
getCapabilitiesSection,
getModesSection,
addCustomInstructions,
+ markdownFormattingSection,
} from "./sections"
import { loadSystemPromptFile } from "./sections/custom-system-prompt"
import { formatLanguage } from "../../shared/language"
@@ -65,6 +66,8 @@ async function generatePrompt(
const basePrompt = `${roleDefinition}
+${markdownFormattingSection()}
+
${getSharedToolUseSection()}
${getToolDescriptionsForMode(
diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts
index 1bf8848aef4..7301b7b422d 100644
--- a/src/core/prompts/tools/new-task.ts
+++ b/src/core/prompts/tools/new-task.ts
@@ -2,10 +2,10 @@ import { ToolArgs } from "./types"
export function getNewTaskDescription(_args: ToolArgs): string {
return `## new_task
-Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.
+Description: This will let you create a new task instance in the chosen mode using your provided message.
Parameters:
-- mode: (required) The slug of the mode to start the new task in (e.g., "code", "ask", "architect").
+- mode: (required) The slug of the mode to start the new task in (e.g., "code", "debug", "architect").
- message: (required) The initial user message or instructions for this new task.
Usage:
diff --git a/src/core/sliding-window/__tests__/sliding-window.test.ts b/src/core/sliding-window/__tests__/sliding-window.test.ts
index 16af2d46301..7890b55ec88 100644
--- a/src/core/sliding-window/__tests__/sliding-window.test.ts
+++ b/src/core/sliding-window/__tests__/sliding-window.test.ts
@@ -10,6 +10,7 @@ import {
truncateConversation,
truncateConversationIfNeeded,
} from "../index"
+import { ApiMessage } from "../../task-persistence/apiMessages"
// Create a mock ApiHandler for testing
class MockApiHandler extends BaseProvider {
@@ -41,7 +42,7 @@ const mockApiHandler = new MockApiHandler()
*/
describe("truncateConversation", () => {
it("should retain the first message", () => {
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -58,7 +59,7 @@ describe("truncateConversation", () => {
})
it("should remove the specified fraction of messages (rounded to even number)", () => {
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -77,7 +78,7 @@ describe("truncateConversation", () => {
})
it("should round to an even number of messages to remove", () => {
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -96,7 +97,7 @@ describe("truncateConversation", () => {
})
it("should handle edge case with fracToRemove = 0", () => {
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -108,7 +109,7 @@ describe("truncateConversation", () => {
})
it("should handle edge case with fracToRemove = 1", () => {
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -224,7 +225,7 @@ describe("truncateConversationIfNeeded", () => {
maxTokens,
})
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
@@ -328,7 +329,7 @@ describe("truncateConversationIfNeeded", () => {
// Test case 1: Small content that won't push us over the threshold
const smallContent = [{ type: "text" as const, text: "Small content" }]
const smallContentTokens = await estimateTokenCount(smallContent, mockApiHandler)
- const messagesWithSmallContent: Anthropic.Messages.MessageParam[] = [
+ const messagesWithSmallContent: ApiMessage[] = [
...messages.slice(0, -1),
{ role: messages[messages.length - 1].role, content: smallContent },
]
@@ -353,7 +354,7 @@ describe("truncateConversationIfNeeded", () => {
},
]
const largeContentTokens = await estimateTokenCount(largeContent, mockApiHandler)
- const messagesWithLargeContent: Anthropic.Messages.MessageParam[] = [
+ const messagesWithLargeContent: ApiMessage[] = [
...messages.slice(0, -1),
{ role: messages[messages.length - 1].role, content: largeContent },
]
@@ -372,7 +373,7 @@ describe("truncateConversationIfNeeded", () => {
// Test case 3: Very large content that will definitely exceed threshold
const veryLargeContent = [{ type: "text" as const, text: "X".repeat(1000) }]
const veryLargeContentTokens = await estimateTokenCount(veryLargeContent, mockApiHandler)
- const messagesWithVeryLargeContent: Anthropic.Messages.MessageParam[] = [
+ const messagesWithVeryLargeContent: ApiMessage[] = [
...messages.slice(0, -1),
{ role: messages[messages.length - 1].role, content: veryLargeContent },
]
@@ -424,7 +425,7 @@ describe("getMaxTokens", () => {
})
// Reuse across tests for consistency
- const messages: Anthropic.Messages.MessageParam[] = [
+ const messages: ApiMessage[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "Second message" },
{ role: "user", content: "Third message" },
diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts
index 75395ecd758..d17bf7fc57d 100644
--- a/src/core/sliding-window/index.ts
+++ b/src/core/sliding-window/index.ts
@@ -1,5 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ApiHandler } from "../../api"
+import { summarizeConversation } from "../condense"
+import { ApiMessage } from "../task-persistence/apiMessages"
/**
* Default percentage of the context window to use as a buffer when deciding when to truncate
@@ -27,14 +29,11 @@ export async function estimateTokenCount(
* The first message is always retained, and a specified fraction (rounded to an even number)
* of messages from the beginning (excluding the first) is removed.
*
- * @param {Anthropic.Messages.MessageParam[]} messages - The conversation messages.
+ * @param {ApiMessage[]} messages - The conversation messages.
* @param {number} fracToRemove - The fraction (between 0 and 1) of messages (excluding the first) to remove.
- * @returns {Anthropic.Messages.MessageParam[]} The truncated conversation messages.
+ * @returns {ApiMessage[]} The truncated conversation messages.
*/
-export function truncateConversation(
- messages: Anthropic.Messages.MessageParam[],
- fracToRemove: number,
-): Anthropic.Messages.MessageParam[] {
+export function truncateConversation(messages: ApiMessage[], fracToRemove: number): ApiMessage[] {
const truncatedMessages = [messages[0]]
const rawMessagesToRemove = Math.floor((messages.length - 1) * fracToRemove)
const messagesToRemove = rawMessagesToRemove - (rawMessagesToRemove % 2)
@@ -48,20 +47,22 @@ export function truncateConversation(
* Conditionally truncates the conversation messages if the total token count
* exceeds the model's limit, considering the size of incoming content.
*
- * @param {Anthropic.Messages.MessageParam[]} messages - The conversation messages.
+ * @param {ApiMessage[]} messages - The conversation messages.
* @param {number} totalTokens - The total number of tokens in the conversation (excluding the last user message).
* @param {number} contextWindow - The context window size.
* @param {number} maxTokens - The maximum number of tokens allowed.
* @param {ApiHandler} apiHandler - The API handler to use for token counting.
- * @returns {Anthropic.Messages.MessageParam[]} The original or truncated conversation messages.
+ * @param {boolean} autoCondenseContext - Whether to use LLM summarization or sliding window implementation
+ * @returns {ApiMessage[]} The original or truncated conversation messages.
*/
type TruncateOptions = {
- messages: Anthropic.Messages.MessageParam[]
+ messages: ApiMessage[]
totalTokens: number
contextWindow: number
maxTokens?: number | null
apiHandler: ApiHandler
+ autoCondenseContext?: boolean
}
/**
@@ -69,7 +70,7 @@ type TruncateOptions = {
* exceeds the model's limit, considering the size of incoming content.
*
* @param {TruncateOptions} options - The options for truncation
- * @returns {Promise} The original or truncated conversation messages.
+ * @returns {Promise} The original or truncated conversation messages.
*/
export async function truncateConversationIfNeeded({
messages,
@@ -77,7 +78,8 @@ export async function truncateConversationIfNeeded({
contextWindow,
maxTokens,
apiHandler,
-}: TruncateOptions): Promise {
+ autoCondenseContext,
+}: TruncateOptions): Promise {
// Calculate the maximum tokens reserved for response
const reservedTokens = maxTokens || contextWindow * 0.2
@@ -96,5 +98,13 @@ export async function truncateConversationIfNeeded({
const allowedTokens = contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens
// Determine if truncation is needed and apply if necessary
- return effectiveTokens > allowedTokens ? truncateConversation(messages, 0.5) : messages
+ if (effectiveTokens <= allowedTokens) {
+ return messages
+ } else if (autoCondenseContext) {
+ const summarizedMessages = await summarizeConversation(messages, apiHandler)
+ if (messages !== summarizedMessages) {
+ return summarizedMessages
+ }
+ }
+ return truncateConversation(messages, 0.5)
}
diff --git a/src/core/task-persistence/apiMessages.ts b/src/core/task-persistence/apiMessages.ts
index b361016345b..6ac36ed08fa 100644
--- a/src/core/task-persistence/apiMessages.ts
+++ b/src/core/task-persistence/apiMessages.ts
@@ -8,7 +8,7 @@ import { fileExistsAtPath } from "../../utils/fs"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { getTaskDirectoryPath } from "../../shared/storagePathManager"
-export type ApiMessage = Anthropic.MessageParam & { ts?: number }
+export type ApiMessage = Anthropic.MessageParam & { ts?: number; isSummary?: boolean }
export async function readApiMessages({
taskId,
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
new file mode 100644
index 00000000000..9b427c26c93
--- /dev/null
+++ b/src/core/task/Task.ts
@@ -0,0 +1,1666 @@
+import * as path from "path"
+import os from "os"
+import crypto from "crypto"
+import EventEmitter from "events"
+
+import { Anthropic } from "@anthropic-ai/sdk"
+import delay from "delay"
+import pWaitFor from "p-wait-for"
+import { serializeError } from "serialize-error"
+
+// schemas
+import { TokenUsage, ToolUsage, ToolName, ModelInfo, CreatorModeConfig } from ../../schemas"
+
+// api
+import { ApiHandler, buildApiHandler } from "../../api"
+import { ApiStream } from "../../api/transform/stream"
+
+// shared
+import { ProviderSettings } from "../../shared/api"
+import { findLastIndex } from "../../shared/array"
+import { combineApiRequests } from "../../shared/combineApiRequests"
+import { combineCommandSequences } from "../../shared/combineCommandSequences"
+import {
+ ClineApiReqCancelReason,
+ ClineApiReqInfo,
+ ClineAsk,
+ ClineMessage,
+ ClineSay,
+ ToolProgressStatus,
+} from "../../shared/ExtensionMessage"
+import { getApiMetrics } from "../../shared/getApiMetrics"
+import { HistoryItem } from "../../shared/HistoryItem"
+import { ClineAskResponse } from "../../shared/WebviewMessage"
+import { defaultModeSlug } from "../../shared/modes"
+import { DiffStrategy } from "../../shared/tools"
+
+// services
+import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
+import { BrowserSession } from "../../services/browser/BrowserSession"
+import { McpHub } from "../../services/mcp/McpHub"
+import { McpServerManager } from "../../services/mcp/McpServerManager"
+import { telemetryService } from "../../services/telemetry/TelemetryService"
+import { RepoPerTaskCheckpointService } from "../../services/checkpoints"
+
+// integrations
+import { DiffViewProvider } from "../../integrations/editor/DiffViewProvider"
+import { findToolName, formatContentBlockToMarkdown } from "../../integrations/misc/export-markdown"
+import { RooTerminalProcess } from "../../integrations/terminal/types"
+import { TerminalRegistry } from "../../integrations/terminal/TerminalRegistry"
+
+// utils
+import { calculateApiCostAnthropic } from "../../utils/cost"
+import { getWorkspacePath } from "../../utils/path"
+
+// prompts
+import { formatResponse } from "../prompts/responses"
+import { SYSTEM_PROMPT } from "../prompts/system"
+
+// core modules
+import { ToolRepetitionDetector } from "../tools/ToolRepetitionDetector"
+import { FileContextTracker } from "../context-tracking/FileContextTracker"
+import { RooIgnoreController } from "../ignore/RooIgnoreController"
+import { type AssistantMessageContent, parseAssistantMessage, presentAssistantMessage } from "../assistant-message"
+import { truncateConversationIfNeeded } from "../sliding-window"
+import { ClineProvider } from "../webview/ClineProvider"
+import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
+import { readApiMessages, saveApiMessages, readTaskMessages, saveTaskMessages, taskMetadata } from "../task-persistence"
+import { getEnvironmentDetails } from "../environment/getEnvironmentDetails"
+import {
+ type CheckpointDiffOptions,
+ type CheckpointRestoreOptions,
+ getCheckpointService,
+ checkpointSave,
+ checkpointRestore,
+ checkpointDiff,
+} from "../checkpoints"
+import { processUserContentMentions } from "../mentions/processUserContentMentions"
+import { ApiMessage } from "../task-persistence/apiMessages"
+import { getMessagesSinceLastSummary } from "../condense"
+import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
+import { readMemories } from "../../utils/memory"
+
+export type ClineEvents = {
+ message: [{ action: "created" | "updated"; message: ClineMessage }]
+ taskStarted: []
+ taskModeSwitched: [taskId: string, mode: string]
+ taskPaused: []
+ taskUnpaused: []
+ taskAskResponded: []
+ taskAborted: []
+ taskSpawned: [taskId: string]
+ taskCompleted: [taskId: string, tokenUsage: TokenUsage, toolUsage: ToolUsage]
+ taskTokenUsageUpdated: [taskId: string, tokenUsage: TokenUsage]
+ taskToolFailed: [taskId: string, tool: ToolName, error: string]
+}
+
+export type TaskOptions = {
+ provider: ClineProvider
+ apiConfiguration: ProviderSettings
+ enableDiff?: boolean
+ enableCheckpoints?: boolean
+ fuzzyMatchThreshold?: number
+ consecutiveMistakeLimit?: number
+ task?: string
+ images?: string[]
+ historyItem?: HistoryItem
+ experiments?: Record
+ startTask?: boolean
+ rootTask?: Task
+ parentTask?: Task
+ taskNumber?: number
+ onCreated?: (cline: Task) => void
+ pearaiModels?: Record
+ creatorModeConfig?: CreatorModeConfig
+}
+
+export class Task extends EventEmitter {
+ readonly taskId: string
+ readonly instanceId: string
+
+ readonly rootTask: Task | undefined = undefined
+ readonly parentTask: Task | undefined = undefined
+ readonly taskNumber: number
+ readonly workspacePath: string
+
+ providerRef: WeakRef
+ private readonly globalStoragePath: string
+ abort: boolean = false
+ didFinishAbortingStream = false
+ abandoned = false
+ isInitialized = false
+ isPaused: boolean = false
+ pausedModeSlug: string = defaultModeSlug
+ private pauseInterval: NodeJS.Timeout | undefined
+
+ // PearAI
+ public creatorModeConfig: CreatorModeConfig
+
+ // API
+ readonly apiConfiguration: ProviderSettings
+ api: ApiHandler
+ private lastApiRequestTime?: number
+
+ toolRepetitionDetector: ToolRepetitionDetector
+ rooIgnoreController?: RooIgnoreController
+ fileContextTracker: FileContextTracker
+ urlContentFetcher: UrlContentFetcher
+ terminalProcess?: RooTerminalProcess
+
+ // Computer User
+ browserSession: BrowserSession
+
+ // Editing
+ diffViewProvider: DiffViewProvider
+ diffStrategy?: DiffStrategy
+ diffEnabled: boolean = false
+ fuzzyMatchThreshold: number
+ didEditFile: boolean = false
+
+ // LLM Messages & Chat Messages
+ apiConversationHistory: ApiMessage[] = []
+ clineMessages: ClineMessage[] = []
+
+ // Ask
+ private askResponse?: ClineAskResponse
+ private askResponseText?: string
+ private askResponseImages?: string[]
+ public lastMessageTs?: number
+
+ // Tool Use
+ consecutiveMistakeCount: number = 0
+ consecutiveMistakeLimit: number
+ consecutiveMistakeCountForApplyDiff: Map = new Map()
+ toolUsage: ToolUsage = {}
+
+ // Checkpoints
+ enableCheckpoints: boolean
+ checkpointService?: RepoPerTaskCheckpointService
+ checkpointServiceInitializing = false
+
+ // Streaming
+ isWaitingForFirstChunk = false
+ isStreaming = false
+ currentStreamingContentIndex = 0
+ assistantMessageContent: AssistantMessageContent[] = []
+ presentAssistantMessageLocked = false
+ presentAssistantMessageHasPendingUpdates = false
+ userMessageContent: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = []
+ userMessageContentReady = false
+ didRejectTool = false
+ didAlreadyUseTool = false
+ didCompleteReadingStream = false
+
+ constructor({
+ provider,
+ apiConfiguration,
+ enableDiff = false,
+ enableCheckpoints = true,
+ fuzzyMatchThreshold = 1.0,
+ consecutiveMistakeLimit = 3,
+ task,
+ images,
+ historyItem,
+ startTask = true,
+ rootTask,
+ parentTask,
+ taskNumber = -1,
+ onCreated,
+ creatorModeConfig,
+ }: TaskOptions) {
+ super()
+
+ if (startTask && !task && !images && !historyItem) {
+ throw new Error("Either historyItem or task/images must be provided")
+ }
+
+ this.taskId = historyItem ? historyItem.id : crypto.randomUUID()
+ // normal use-case is usually retry similar history task with new workspace
+ this.workspacePath = parentTask
+ ? parentTask.workspacePath
+ : getWorkspacePath(path.join(os.homedir(), "Desktop"))
+ this.instanceId = crypto.randomUUID().slice(0, 8)
+ this.taskNumber = -1
+
+ this.rooIgnoreController = new RooIgnoreController(this.cwd)
+ this.fileContextTracker = new FileContextTracker(provider, this.taskId)
+
+ this.rooIgnoreController.initialize().catch((error) => {
+ console.error("Failed to initialize RooIgnoreController:", error)
+ })
+
+ this.creatorModeConfig = creatorModeConfig ?? historyItem?.creatorModeConfig ?? { creatorMode: false }
+
+ this.apiConfiguration = {
+ ...apiConfiguration,
+ creatorModeConfig: this.creatorModeConfig
+ }
+ this.api = buildApiHandler(this.apiConfiguration)
+
+ this.urlContentFetcher = new UrlContentFetcher(provider.context)
+ this.browserSession = new BrowserSession(provider.context)
+ this.diffEnabled = enableDiff
+ this.fuzzyMatchThreshold = fuzzyMatchThreshold
+ this.consecutiveMistakeLimit = consecutiveMistakeLimit
+ this.providerRef = new WeakRef(provider)
+ this.globalStoragePath = provider.context.globalStorageUri.fsPath
+ this.diffViewProvider = new DiffViewProvider(this.cwd)
+ this.enableCheckpoints = enableCheckpoints
+ this.creatorModeConfig = creatorModeConfig ?? historyItem?.creatorModeConfig ?? { creatorMode: false }
+
+
+ this.rootTask = rootTask
+ this.parentTask = parentTask
+ this.taskNumber = taskNumber
+
+ if (historyItem) {
+ telemetryService.captureTaskRestarted(this.taskId)
+ } else {
+ telemetryService.captureTaskCreated(this.taskId)
+ }
+
+ this.diffStrategy = new MultiSearchReplaceDiffStrategy(this.fuzzyMatchThreshold)
+ this.toolRepetitionDetector = new ToolRepetitionDetector(this.consecutiveMistakeLimit)
+
+ onCreated?.(this)
+
+ if (startTask) {
+ if (task || images) {
+ this.startTask(task, images)
+ } else if (historyItem) {
+ this.resumeTaskFromHistory()
+ } else {
+ throw new Error("Either historyItem or task/images must be provided")
+ }
+ }
+ }
+
+ static create(options: TaskOptions): [Task, Promise] {
+ const instance = new Task({ ...options, startTask: false })
+ const { images, task, historyItem } = options
+ let promise
+
+ if (images || task) {
+ promise = instance.startTask(task, images)
+ } else if (historyItem) {
+ promise = instance.resumeTaskFromHistory()
+ } else {
+ throw new Error("Either historyItem or task/images must be provided")
+ }
+
+ return [instance, promise]
+ }
+
+ // API Messages
+
+ private async getSavedApiConversationHistory(): Promise {
+ return readApiMessages({ taskId: this.taskId, globalStoragePath: this.globalStoragePath })
+ }
+
+ private async addToApiConversationHistory(message: Anthropic.MessageParam) {
+ const messageWithTs = { ...message, ts: Date.now() }
+ this.apiConversationHistory.push(messageWithTs)
+ await this.saveApiConversationHistory()
+ }
+
+ async overwriteApiConversationHistory(newHistory: ApiMessage[]) {
+ this.apiConversationHistory = newHistory
+ await this.saveApiConversationHistory()
+ }
+
+ private async saveApiConversationHistory() {
+ try {
+ await saveApiMessages({
+ messages: this.apiConversationHistory,
+ taskId: this.taskId,
+ globalStoragePath: this.globalStoragePath,
+ })
+ } catch (error) {
+ // In the off chance this fails, we don't want to stop the task.
+ console.error("Failed to save API conversation history:", error)
+ }
+ }
+
+ // Cline Messages
+
+ private async getSavedClineMessages(): Promise {
+ return readTaskMessages({ taskId: this.taskId, globalStoragePath: this.globalStoragePath })
+ }
+
+ private async addToClineMessages(message: ClineMessage) {
+ this.clineMessages.push(message)
+ await this.providerRef.deref()?.postStateToWebview()
+ this.emit("message", { action: "created", message })
+ await this.saveClineMessages()
+ }
+
+ public async overwriteClineMessages(newMessages: ClineMessage[]) {
+ this.clineMessages = newMessages
+ await this.saveClineMessages()
+ }
+
+ private async updateClineMessage(partialMessage: ClineMessage) {
+ await this.providerRef.deref()?.postMessageToWebview({ type: "partialMessage", partialMessage })
+ this.emit("message", { action: "updated", message: partialMessage })
+ }
+
+ private async saveClineMessages() {
+ try {
+ await saveTaskMessages({
+ messages: this.clineMessages,
+ taskId: this.taskId,
+ globalStoragePath: this.globalStoragePath,
+ })
+
+ const { historyItem, tokenUsage } = await taskMetadata({
+ messages: this.clineMessages,
+ taskId: this.taskId,
+ taskNumber: this.taskNumber,
+ globalStoragePath: this.globalStoragePath,
+ workspace: this.cwd,
+ creatorModeConfig: this.creatorModeConfig,
+ })
+
+ this.emit("taskTokenUsageUpdated", this.taskId, tokenUsage)
+
+ await this.providerRef.deref()?.updateTaskHistory(historyItem)
+ } catch (error) {
+ console.error("Failed to save cline messages:", error)
+ }
+ }
+
+ // Note that `partial` has three valid states true (partial message),
+ // false (completion of partial message), undefined (individual complete
+ // message).
+ async ask(
+ type: ClineAsk,
+ text?: string,
+ partial?: boolean,
+ progressStatus?: ToolProgressStatus,
+ ): Promise<{ response: ClineAskResponse; text?: string; images?: string[] }> {
+ // If this Cline instance was aborted by the provider, then the only
+ // thing keeping us alive is a promise still running in the background,
+ // in which case we don't want to send its result to the webview as it
+ // is attached to a new instance of Cline now. So we can safely ignore
+ // the result of any active promises, and this class will be
+ // deallocated. (Although we set Cline = undefined in provider, that
+ // simply removes the reference to this instance, but the instance is
+ // still alive until this promise resolves or rejects.)
+ if (this.abort) {
+ throw new Error(`[Cline#ask] task ${this.taskId}.${this.instanceId} aborted`)
+ }
+
+ let askTs: number
+
+ if (partial !== undefined) {
+ const lastMessage = this.clineMessages.at(-1)
+
+ const isUpdatingPreviousPartial =
+ lastMessage && lastMessage.partial && lastMessage.type === "ask" && lastMessage.ask === type
+
+ if (partial) {
+ if (isUpdatingPreviousPartial) {
+ // Existing partial message, so update it.
+ lastMessage.text = text
+ lastMessage.partial = partial
+ lastMessage.progressStatus = progressStatus
+ // TODO: Be more efficient about saving and posting only new
+ // data or one whole message at a time so ignore partial for
+ // saves, and only post parts of partial message instead of
+ // whole array in new listener.
+ this.updateClineMessage(lastMessage)
+ throw new Error("Current ask promise was ignored (#1)")
+ } else {
+ // This is a new partial message, so add it with partial
+ // state.
+ askTs = Date.now()
+ this.lastMessageTs = askTs
+ await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text, partial })
+ throw new Error("Current ask promise was ignored (#2)")
+ }
+ } else {
+ if (isUpdatingPreviousPartial) {
+ // This is the complete version of a previously partial
+ // message, so replace the partial with the complete version.
+ this.askResponse = undefined
+ this.askResponseText = undefined
+ this.askResponseImages = undefined
+
+ // Bug for the history books:
+ // In the webview we use the ts as the chatrow key for the
+ // virtuoso list. Since we would update this ts right at the
+ // end of streaming, it would cause the view to flicker. The
+ // key prop has to be stable otherwise react has trouble
+ // reconciling items between renders, causing unmounting and
+ // remounting of components (flickering).
+ // The lesson here is if you see flickering when rendering
+ // lists, it's likely because the key prop is not stable.
+ // So in this case we must make sure that the message ts is
+ // never altered after first setting it.
+ askTs = lastMessage.ts
+ this.lastMessageTs = askTs
+ lastMessage.text = text
+ lastMessage.partial = false
+ lastMessage.progressStatus = progressStatus
+ await this.saveClineMessages()
+ this.updateClineMessage(lastMessage)
+ } else {
+ // This is a new and complete message, so add it like normal.
+ this.askResponse = undefined
+ this.askResponseText = undefined
+ this.askResponseImages = undefined
+ askTs = Date.now()
+ this.lastMessageTs = askTs
+ await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text })
+ }
+ }
+ } else {
+ // This is a new non-partial message, so add it like normal.
+ this.askResponse = undefined
+ this.askResponseText = undefined
+ this.askResponseImages = undefined
+ askTs = Date.now()
+ this.lastMessageTs = askTs
+ await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text })
+ }
+
+ await pWaitFor(() => this.askResponse !== undefined || this.lastMessageTs !== askTs, { interval: 100 })
+
+ if (this.lastMessageTs !== askTs) {
+ // Could happen if we send multiple asks in a row i.e. with
+ // command_output. It's important that when we know an ask could
+ // fail, it is handled gracefully.
+ throw new Error("Current ask promise was ignored")
+ }
+
+ const result = { response: this.askResponse!, text: this.askResponseText, images: this.askResponseImages }
+ this.askResponse = undefined
+ this.askResponseText = undefined
+ this.askResponseImages = undefined
+ this.emit("taskAskResponded")
+ return result
+ }
+
+ async handleWebviewAskResponse(askResponse: ClineAskResponse, text?: string, images?: string[]) {
+ this.askResponse = askResponse
+ this.askResponseText = text
+ this.askResponseImages = images
+ }
+
+ async handleTerminalOperation(terminalOperation: "continue" | "abort") {
+ if (terminalOperation === "continue") {
+ this.terminalProcess?.continue()
+ } else if (terminalOperation === "abort") {
+ this.terminalProcess?.abort()
+ }
+ }
+
+ async say(
+ type: ClineSay,
+ text?: string,
+ images?: string[],
+ partial?: boolean,
+ checkpoint?: Record,
+ progressStatus?: ToolProgressStatus,
+ options: {
+ isNonInteractive?: boolean
+ } = {},
+ ): Promise {
+ if (this.abort) {
+ throw new Error(`[Cline#say] task ${this.taskId}.${this.instanceId} aborted`)
+ }
+
+ if (partial !== undefined) {
+ const lastMessage = this.clineMessages.at(-1)
+
+ const isUpdatingPreviousPartial =
+ lastMessage && lastMessage.partial && lastMessage.type === "say" && lastMessage.say === type
+
+ if (partial) {
+ if (isUpdatingPreviousPartial) {
+ // Existing partial message, so update it.
+ lastMessage.text = text
+ lastMessage.images = images
+ lastMessage.partial = partial
+ lastMessage.progressStatus = progressStatus
+ this.updateClineMessage(lastMessage)
+ } else {
+ // This is a new partial message, so add it with partial state.
+ const sayTs = Date.now()
+
+ if (!options.isNonInteractive) {
+ this.lastMessageTs = sayTs
+ }
+
+ await this.addToClineMessages({ ts: sayTs, type: "say", say: type, text, images, partial })
+ }
+ } else {
+ // New now have a complete version of a previously partial message.
+ // This is the complete version of a previously partial
+ // message, so replace the partial with the complete version.
+ if (isUpdatingPreviousPartial) {
+ if (!options.isNonInteractive) {
+ this.lastMessageTs = lastMessage.ts
+ }
+
+ lastMessage.text = text
+ lastMessage.images = images
+ lastMessage.partial = false
+ lastMessage.progressStatus = progressStatus
+
+ // Instead of streaming partialMessage events, we do a save
+ // and post like normal to persist to disk.
+ await this.saveClineMessages()
+
+ // More performant than an entire `postStateToWebview`.
+ this.updateClineMessage(lastMessage)
+ } else {
+ // This is a new and complete message, so add it like normal.
+ const sayTs = Date.now()
+
+ if (!options.isNonInteractive) {
+ this.lastMessageTs = sayTs
+ }
+
+ await this.addToClineMessages({ ts: sayTs, type: "say", say: type, text, images })
+ }
+ }
+ } else {
+ // This is a new non-partial message, so add it like normal.
+ const sayTs = Date.now()
+
+ // A "non-interactive" message is a message is one that the user
+ // does not need to respond to. We don't want these message types
+ // to trigger an update to `lastMessageTs` since they can be created
+ // asynchronously and could interrupt a pending ask.
+ if (!options.isNonInteractive) {
+ this.lastMessageTs = sayTs
+ }
+
+ await this.addToClineMessages({ ts: sayTs, type: "say", say: type, text, images, checkpoint })
+ }
+ }
+
+ async sayAndCreateMissingParamError(toolName: ToolName, paramName: string, relPath?: string) {
+ await this.say(
+ "error",
+ `Roo tried to use ${toolName}${
+ relPath ? ` for '${relPath.toPosix()}'` : ""
+ } without value for required parameter '${paramName}'. Retrying...`,
+ )
+ return formatResponse.toolError(formatResponse.missingToolParameterError(paramName))
+ }
+
+ // Start / Abort / Resume
+
+ private async startTask(task?: string, images?: string[]): Promise {
+ // `conversationHistory` (for API) and `clineMessages` (for webview)
+ // need to be in sync.
+ // If the extension process were killed, then on restart the
+ // `clineMessages` might not be empty, so we need to set it to [] when
+ // we create a new Cline client (otherwise webview would show stale
+ // messages from previous session).
+ this.clineMessages = []
+ this.apiConversationHistory = []
+ await this.providerRef.deref()?.postStateToWebview()
+
+ await this.say("text", task, images)
+ this.isInitialized = true
+
+ let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images)
+
+ console.log(`[subtasks] task ${this.taskId}.${this.instanceId} starting`)
+ // PearAI memories
+ const memories = readMemories()
+ let memoryBlocks: Anthropic.TextBlockParam[] = []
+ if (memories.length > 0) {
+ const memoryContext = memories.map((m) => m.memory).join("\n\n")
+ memoryBlocks.push({
+ type: "text",
+ text: `\n\n${memoryContext}\n`,
+ })
+ }
+ await this.initiateTaskLoop([
+ {
+ type: "text",
+ text: `\n${task}\n`,
+ },
+ ...imageBlocks,
+ ])
+ }
+
+ public async resumePausedTask(lastMessage: string) {
+ // Release this Cline instance from paused state.
+ this.isPaused = false
+ this.emit("taskUnpaused")
+
+ // Fake an answer from the subtask that it has completed running and
+ // this is the result of what it has done add the message to the chat
+ // history and to the webview ui.
+ try {
+ await this.say("subtask_result", lastMessage)
+
+ await this.addToApiConversationHistory({
+ role: "user",
+ content: [{ type: "text", text: `[new_task completed] Result: ${lastMessage}` }],
+ })
+ } catch (error) {
+ this.providerRef
+ .deref()
+ ?.log(`Error failed to add reply from subtast into conversation of parent task, error: ${error}`)
+
+ throw error
+ }
+ }
+
+ private async resumeTaskFromHistory() {
+ const modifiedClineMessages = await this.getSavedClineMessages()
+
+ // Remove any resume messages that may have been added before
+ const lastRelevantMessageIndex = findLastIndex(
+ modifiedClineMessages,
+ (m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"),
+ )
+
+ if (lastRelevantMessageIndex !== -1) {
+ modifiedClineMessages.splice(lastRelevantMessageIndex + 1)
+ }
+
+ // since we don't use api_req_finished anymore, we need to check if the last api_req_started has a cost value, if it doesn't and no cancellation reason to present, then we remove it since it indicates an api request without any partial content streamed
+ const lastApiReqStartedIndex = findLastIndex(
+ modifiedClineMessages,
+ (m) => m.type === "say" && m.say === "api_req_started",
+ )
+
+ if (lastApiReqStartedIndex !== -1) {
+ const lastApiReqStarted = modifiedClineMessages[lastApiReqStartedIndex]
+ const { cost, cancelReason }: ClineApiReqInfo = JSON.parse(lastApiReqStarted.text || "{}")
+ if (cost === undefined && cancelReason === undefined) {
+ modifiedClineMessages.splice(lastApiReqStartedIndex, 1)
+ }
+ }
+
+ await this.overwriteClineMessages(modifiedClineMessages)
+ this.clineMessages = await this.getSavedClineMessages()
+
+ // Now present the cline messages to the user and ask if they want to
+ // resume (NOTE: we ran into a bug before where the
+ // apiConversationHistory wouldn't be initialized when opening a old
+ // task, and it was because we were waiting for resume).
+ // This is important in case the user deletes messages without resuming
+ // the task first.
+ this.apiConversationHistory = await this.getSavedApiConversationHistory()
+
+ const lastClineMessage = this.clineMessages
+ .slice()
+ .reverse()
+ .find((m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task")) // could be multiple resume tasks
+
+ let askType: ClineAsk
+ if (lastClineMessage?.ask === "completion_result") {
+ askType = "resume_completed_task"
+ } else {
+ askType = "resume_task"
+ }
+
+ this.isInitialized = true
+
+ const { response, text, images } = await this.ask(askType) // calls poststatetowebview
+ let responseText: string | undefined
+ let responseImages: string[] | undefined
+ if (response === "messageResponse") {
+ await this.say("user_feedback", text, images)
+ responseText = text
+ responseImages = images
+ }
+
+ // Make sure that the api conversation history can be resumed by the API,
+ // even if it goes out of sync with cline messages.
+ let existingApiConversationHistory: ApiMessage[] = await this.getSavedApiConversationHistory()
+
+ // v2.0 xml tags refactor caveat: since we don't use tools anymore, we need to replace all tool use blocks with a text block since the API disallows conversations with tool uses and no tool schema
+ const conversationWithoutToolBlocks = existingApiConversationHistory.map((message) => {
+ if (Array.isArray(message.content)) {
+ const newContent = message.content.map((block) => {
+ if (block.type === "tool_use") {
+ // it's important we convert to the new tool schema format so the model doesn't get confused about how to invoke tools
+ const inputAsXml = Object.entries(block.input as Record)
+ .map(([key, value]) => `<${key}>\n${value}\n${key}>`)
+ .join("\n")
+ return {
+ type: "text",
+ text: `<${block.name}>\n${inputAsXml}\n${block.name}>`,
+ } as Anthropic.Messages.TextBlockParam
+ } else if (block.type === "tool_result") {
+ // Convert block.content to text block array, removing images
+ const contentAsTextBlocks = Array.isArray(block.content)
+ ? block.content.filter((item) => item.type === "text")
+ : [{ type: "text", text: block.content }]
+ const textContent = contentAsTextBlocks.map((item) => item.text).join("\n\n")
+ const toolName = findToolName(block.tool_use_id, existingApiConversationHistory)
+ return {
+ type: "text",
+ text: `[${toolName} Result]\n\n${textContent}`,
+ } as Anthropic.Messages.TextBlockParam
+ }
+ return block
+ })
+ return { ...message, content: newContent }
+ }
+ return message
+ })
+ existingApiConversationHistory = conversationWithoutToolBlocks
+
+ // FIXME: remove tool use blocks altogether
+
+ // if the last message is an assistant message, we need to check if there's tool use since every tool use has to have a tool response
+ // if there's no tool use and only a text block, then we can just add a user message
+ // (note this isn't relevant anymore since we use custom tool prompts instead of tool use blocks, but this is here for legacy purposes in case users resume old tasks)
+
+ // if the last message is a user message, we can need to get the assistant message before it to see if it made tool calls, and if so, fill in the remaining tool responses with 'interrupted'
+
+ let modifiedOldUserContent: Anthropic.Messages.ContentBlockParam[] // either the last message if its user message, or the user message before the last (assistant) message
+ let modifiedApiConversationHistory: ApiMessage[] // need to remove the last user message to replace with new modified user message
+ if (existingApiConversationHistory.length > 0) {
+ const lastMessage = existingApiConversationHistory[existingApiConversationHistory.length - 1]
+
+ if (lastMessage.role === "assistant") {
+ const content = Array.isArray(lastMessage.content)
+ ? lastMessage.content
+ : [{ type: "text", text: lastMessage.content }]
+ const hasToolUse = content.some((block) => block.type === "tool_use")
+
+ if (hasToolUse) {
+ const toolUseBlocks = content.filter(
+ (block) => block.type === "tool_use",
+ ) as Anthropic.Messages.ToolUseBlock[]
+ const toolResponses: Anthropic.ToolResultBlockParam[] = toolUseBlocks.map((block) => ({
+ type: "tool_result",
+ tool_use_id: block.id,
+ content: "Task was interrupted before this tool call could be completed.",
+ }))
+ modifiedApiConversationHistory = [...existingApiConversationHistory] // no changes
+ modifiedOldUserContent = [...toolResponses]
+ } else {
+ modifiedApiConversationHistory = [...existingApiConversationHistory]
+ modifiedOldUserContent = []
+ }
+ } else if (lastMessage.role === "user") {
+ const previousAssistantMessage: ApiMessage | undefined =
+ existingApiConversationHistory[existingApiConversationHistory.length - 2]
+
+ const existingUserContent: Anthropic.Messages.ContentBlockParam[] = Array.isArray(lastMessage.content)
+ ? lastMessage.content
+ : [{ type: "text", text: lastMessage.content }]
+ if (previousAssistantMessage && previousAssistantMessage.role === "assistant") {
+ const assistantContent = Array.isArray(previousAssistantMessage.content)
+ ? previousAssistantMessage.content
+ : [{ type: "text", text: previousAssistantMessage.content }]
+
+ const toolUseBlocks = assistantContent.filter(
+ (block) => block.type === "tool_use",
+ ) as Anthropic.Messages.ToolUseBlock[]
+
+ if (toolUseBlocks.length > 0) {
+ const existingToolResults = existingUserContent.filter(
+ (block) => block.type === "tool_result",
+ ) as Anthropic.ToolResultBlockParam[]
+
+ const missingToolResponses: Anthropic.ToolResultBlockParam[] = toolUseBlocks
+ .filter(
+ (toolUse) => !existingToolResults.some((result) => result.tool_use_id === toolUse.id),
+ )
+ .map((toolUse) => ({
+ type: "tool_result",
+ tool_use_id: toolUse.id,
+ content: "Task was interrupted before this tool call could be completed.",
+ }))
+
+ modifiedApiConversationHistory = existingApiConversationHistory.slice(0, -1) // removes the last user message
+ modifiedOldUserContent = [...existingUserContent, ...missingToolResponses]
+ } else {
+ modifiedApiConversationHistory = existingApiConversationHistory.slice(0, -1)
+ modifiedOldUserContent = [...existingUserContent]
+ }
+ } else {
+ modifiedApiConversationHistory = existingApiConversationHistory.slice(0, -1)
+ modifiedOldUserContent = [...existingUserContent]
+ }
+ } else {
+ throw new Error("Unexpected: Last message is not a user or assistant message")
+ }
+ } else {
+ throw new Error("Unexpected: No existing API conversation history")
+ }
+
+ let newUserContent: Anthropic.Messages.ContentBlockParam[] = [...modifiedOldUserContent]
+
+ const agoText = ((): string => {
+ const timestamp = lastClineMessage?.ts ?? Date.now()
+ const now = Date.now()
+ const diff = now - timestamp
+ const minutes = Math.floor(diff / 60000)
+ const hours = Math.floor(minutes / 60)
+ const days = Math.floor(hours / 24)
+
+ if (days > 0) {
+ return `${days} day${days > 1 ? "s" : ""} ago`
+ }
+ if (hours > 0) {
+ return `${hours} hour${hours > 1 ? "s" : ""} ago`
+ }
+ if (minutes > 0) {
+ return `${minutes} minute${minutes > 1 ? "s" : ""} ago`
+ }
+ return "just now"
+ })()
+
+ const lastTaskResumptionIndex = newUserContent.findIndex(
+ (x) => x.type === "text" && x.text.startsWith("[TASK RESUMPTION]"),
+ )
+ if (lastTaskResumptionIndex !== -1) {
+ newUserContent.splice(lastTaskResumptionIndex, newUserContent.length - lastTaskResumptionIndex)
+ }
+
+ const wasRecent = lastClineMessage?.ts && Date.now() - lastClineMessage.ts < 30_000
+
+ newUserContent.push({
+ type: "text",
+ text:
+ `[TASK RESUMPTION] This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.${
+ wasRecent
+ ? "\n\nIMPORTANT: If the last tool use was a write_to_file that was interrupted, the file was reverted back to its original state before the interrupted edit, and you do NOT need to re-read the file as you already have its up-to-date contents."
+ : ""
+ }` +
+ (responseText
+ ? `\n\nNew instructions for task continuation:\n\n${responseText}\n`
+ : ""),
+ })
+
+ if (responseImages && responseImages.length > 0) {
+ newUserContent.push(...formatResponse.imageBlocks(responseImages))
+ }
+
+ await this.overwriteApiConversationHistory(modifiedApiConversationHistory)
+
+ console.log(`[subtasks] task ${this.taskId}.${this.instanceId} resuming from history item`)
+
+ await this.initiateTaskLoop(newUserContent)
+ }
+
+ public async abortTask(isAbandoned = false) {
+ console.log(`[subtasks] aborting task ${this.taskId}.${this.instanceId}`)
+
+ // Will stop any autonomously running promises.
+ if (isAbandoned) {
+ this.abandoned = true
+ }
+
+ this.abort = true
+ this.emit("taskAborted")
+
+ // Stop waiting for child task completion.
+ if (this.pauseInterval) {
+ clearInterval(this.pauseInterval)
+ this.pauseInterval = undefined
+ }
+
+ // Release any terminals associated with this task.
+ TerminalRegistry.releaseTerminalsForTask(this.taskId)
+
+ this.urlContentFetcher.closeBrowser()
+ this.browserSession.closeBrowser()
+ this.rooIgnoreController?.dispose()
+ this.fileContextTracker.dispose()
+
+ // If we're not streaming then `abortStream` (which reverts the diff
+ // view changes) won't be called, so we need to revert the changes here.
+ if (this.isStreaming && this.diffViewProvider.isEditing) {
+ await this.diffViewProvider.revertChanges()
+ }
+
+ // Save the countdown message in the automatic retry or other content.
+ await this.saveClineMessages()
+ }
+
+ // Used when a sub-task is launched and the parent task is waiting for it to
+ // finish.
+ // TBD: The 1s should be added to the settings, also should add a timeout to
+ // prevent infinite waiting.
+ public async waitForResume() {
+ await new Promise((resolve) => {
+ this.pauseInterval = setInterval(() => {
+ if (!this.isPaused) {
+ clearInterval(this.pauseInterval)
+ this.pauseInterval = undefined
+ resolve()
+ }
+ }, 1000)
+ })
+ }
+
+ // Task Loop
+
+ private async initiateTaskLoop(userContent: Anthropic.Messages.ContentBlockParam[]): Promise {
+ // Kicks off the checkpoints initialization process in the background.
+ getCheckpointService(this)
+
+ let nextUserContent = userContent
+ let includeFileDetails = true
+
+ this.emit("taskStarted")
+
+ while (!this.abort) {
+ const didEndLoop = await this.recursivelyMakeClineRequests(nextUserContent, includeFileDetails)
+ includeFileDetails = false // we only need file details the first time
+
+ // The way this agentic loop works is that cline will be given a
+ // task that he then calls tools to complete. Unless there's an
+ // attempt_completion call, we keep responding back to him with his
+ // tool's responses until he either attempt_completion or does not
+ // use anymore tools. If he does not use anymore tools, we ask him
+ // to consider if he's completed the task and then call
+ // attempt_completion, otherwise proceed with completing the task.
+ // There is a MAX_REQUESTS_PER_TASK limit to prevent infinite
+ // requests, but Cline is prompted to finish the task as efficiently
+ // as he can.
+
+ if (didEndLoop) {
+ // For now a task never 'completes'. This will only happen if
+ // the user hits max requests and denies resetting the count.
+ break
+ } else {
+ nextUserContent = [{ type: "text", text: formatResponse.noToolsUsed() }]
+ this.consecutiveMistakeCount++
+ }
+ }
+ }
+
+ public async recursivelyMakeClineRequests(
+ userContent: Anthropic.Messages.ContentBlockParam[],
+ includeFileDetails: boolean = false,
+ ): Promise {
+ if (this.abort) {
+ throw new Error(`[Cline#recursivelyMakeClineRequests] task ${this.taskId}.${this.instanceId} aborted`)
+ }
+
+ if (this.consecutiveMistakeCount >= this.consecutiveMistakeLimit) {
+ const { response, text, images } = await this.ask(
+ "mistake_limit_reached",
+ this.api.getModel().id.includes("claude")
+ ? `This may indicate a failure in his thought process or inability to use a tool properly, which can be mitigated with some user guidance (e.g. "Try breaking down the task into smaller steps").`
+ : "Roo Code uses complex prompts and iterative task execution that may be challenging for less capable models. For best results, it's recommended to use Claude 3.7 Sonnet for its advanced agentic coding capabilities.",
+ )
+
+ if (response === "messageResponse") {
+ userContent.push(
+ ...[
+ { type: "text" as const, text: formatResponse.tooManyMistakes(text) },
+ ...formatResponse.imageBlocks(images),
+ ],
+ )
+
+ await this.say("user_feedback", text, images)
+
+ // Track consecutive mistake errors in telemetry.
+ telemetryService.captureConsecutiveMistakeError(this.taskId)
+ }
+
+ this.consecutiveMistakeCount = 0
+ }
+
+ // Get previous api req's index to check token usage and determine if we
+ // need to truncate conversation history.
+ const previousApiReqIndex = findLastIndex(this.clineMessages, (m) => m.say === "api_req_started")
+
+ // In this Cline request loop, we need to check if this task instance
+ // has been asked to wait for a subtask to finish before continuing.
+ const provider = this.providerRef.deref()
+
+ if (this.isPaused && provider) {
+ provider.log(`[subtasks] paused ${this.taskId}.${this.instanceId}`)
+ await this.waitForResume()
+ provider.log(`[subtasks] resumed ${this.taskId}.${this.instanceId}`)
+ const currentMode = (await provider.getState())?.mode ?? defaultModeSlug
+
+ if (currentMode !== this.pausedModeSlug) {
+ // The mode has changed, we need to switch back to the paused mode.
+ await provider.handleModeSwitch(this.pausedModeSlug)
+
+ // Delay to allow mode change to take effect before next tool is executed.
+ await delay(500)
+
+ provider.log(
+ `[subtasks] task ${this.taskId}.${this.instanceId} has switched back to '${this.pausedModeSlug}' from '${currentMode}'`,
+ )
+ }
+ }
+
+ // Getting verbose details is an expensive operation, it uses ripgrep to
+ // top-down build file structure of project which for large projects can
+ // take a few seconds. For the best UX we show a placeholder api_req_started
+ // message with a loading spinner as this happens.
+ await this.say(
+ "api_req_started",
+ JSON.stringify({
+ request:
+ userContent.map((block) => formatContentBlockToMarkdown(block)).join("\n\n") + "\n\nLoading...",
+ }),
+ )
+
+ const parsedUserContent = await processUserContentMentions({
+ userContent,
+ cwd: this.cwd,
+ urlContentFetcher: this.urlContentFetcher,
+ fileContextTracker: this.fileContextTracker,
+ })
+
+ const environmentDetails = await getEnvironmentDetails(this, includeFileDetails)
+
+ // Add environment details as its own text block, separate from tool
+ // results.
+ const finalUserContent = [...parsedUserContent, { type: "text" as const, text: environmentDetails }]
+
+ await this.addToApiConversationHistory({ role: "user", content: finalUserContent })
+ telemetryService.captureConversationMessage(this.taskId, "user")
+
+ // Since we sent off a placeholder api_req_started message to update the
+ // webview while waiting to actually start the API request (to load
+ // potential details for example), we need to update the text of that
+ // message.
+ const lastApiReqIndex = findLastIndex(this.clineMessages, (m) => m.say === "api_req_started")
+
+ this.clineMessages[lastApiReqIndex].text = JSON.stringify({
+ request: finalUserContent.map((block) => formatContentBlockToMarkdown(block)).join("\n\n"),
+ } satisfies ClineApiReqInfo)
+
+ await this.saveClineMessages()
+ await provider?.postStateToWebview()
+
+ try {
+ let cacheWriteTokens = 0
+ let cacheReadTokens = 0
+ let inputTokens = 0
+ let outputTokens = 0
+ let totalCost: number | undefined
+
+ // We can't use `api_req_finished` anymore since it's a unique case
+ // where it could come after a streaming message (i.e. in the middle
+ // of being updated or executed).
+ // Fortunately `api_req_finished` was always parsed out for the GUI
+ // anyways, so it remains solely for legacy purposes to keep track
+ // of prices in tasks from history (it's worth removing a few months
+ // from now).
+ const updateApiReqMsg = (cancelReason?: ClineApiReqCancelReason, streamingFailedMessage?: string) => {
+ this.clineMessages[lastApiReqIndex].text = JSON.stringify({
+ ...JSON.parse(this.clineMessages[lastApiReqIndex].text || "{}"),
+ tokensIn: inputTokens,
+ tokensOut: outputTokens,
+ cacheWrites: cacheWriteTokens,
+ cacheReads: cacheReadTokens,
+ cost:
+ totalCost ??
+ calculateApiCostAnthropic(
+ this.api.getModel().info,
+ inputTokens,
+ outputTokens,
+ cacheWriteTokens,
+ cacheReadTokens,
+ ),
+ cancelReason,
+ streamingFailedMessage,
+ } satisfies ClineApiReqInfo)
+ }
+
+ const abortStream = async (cancelReason: ClineApiReqCancelReason, streamingFailedMessage?: string) => {
+ if (this.diffViewProvider.isEditing) {
+ await this.diffViewProvider.revertChanges() // closes diff view
+ }
+
+ // if last message is a partial we need to update and save it
+ const lastMessage = this.clineMessages.at(-1)
+
+ if (lastMessage && lastMessage.partial) {
+ // lastMessage.ts = Date.now() DO NOT update ts since it is used as a key for virtuoso list
+ lastMessage.partial = false
+ // instead of streaming partialMessage events, we do a save and post like normal to persist to disk
+ console.log("updating partial message", lastMessage)
+ // await this.saveClineMessages()
+ }
+
+ // Let assistant know their response was interrupted for when task is resumed
+ await this.addToApiConversationHistory({
+ role: "assistant",
+ content: [
+ {
+ type: "text",
+ text:
+ assistantMessage +
+ `\n\n[${
+ cancelReason === "streaming_failed"
+ ? "Response interrupted by API Error"
+ : "Response interrupted by user"
+ }]`,
+ },
+ ],
+ })
+
+ // Update `api_req_started` to have cancelled and cost, so that
+ // we can display the cost of the partial stream.
+ updateApiReqMsg(cancelReason, streamingFailedMessage)
+ await this.saveClineMessages()
+
+ // Signals to provider that it can retrieve the saved messages
+ // from disk, as abortTask can not be awaited on in nature.
+ this.didFinishAbortingStream = true
+ }
+
+ // Reset streaming state.
+ this.currentStreamingContentIndex = 0
+ this.assistantMessageContent = []
+ this.didCompleteReadingStream = false
+ this.userMessageContent = []
+ this.userMessageContentReady = false
+ this.didRejectTool = false
+ this.didAlreadyUseTool = false
+ this.presentAssistantMessageLocked = false
+ this.presentAssistantMessageHasPendingUpdates = false
+
+ await this.diffViewProvider.reset()
+
+ // Yields only if the first chunk is successful, otherwise will
+ // allow the user to retry the request (most likely due to rate
+ // limit error, which gets thrown on the first chunk).
+ const stream = this.attemptApiRequest(previousApiReqIndex)
+ let assistantMessage = ""
+ let reasoningMessage = ""
+ this.isStreaming = true
+
+ try {
+ for await (const chunk of stream) {
+ if (!chunk) {
+ // Sometimes chunk is undefined, no idea that can cause
+ // it, but this workaround seems to fix it.
+ continue
+ }
+
+ switch (chunk.type) {
+ case "reasoning":
+ reasoningMessage += chunk.text
+ await this.say("reasoning", reasoningMessage, undefined, true)
+ break
+ case "usage":
+ inputTokens += chunk.inputTokens
+ outputTokens += chunk.outputTokens
+ cacheWriteTokens += chunk.cacheWriteTokens ?? 0
+ cacheReadTokens += chunk.cacheReadTokens ?? 0
+ totalCost = chunk.totalCost
+ break
+ case "text":
+ assistantMessage += chunk.text
+
+ // Parse raw assistant message into content blocks.
+ const prevLength = this.assistantMessageContent.length
+ this.assistantMessageContent = parseAssistantMessage(assistantMessage)
+
+ if (this.assistantMessageContent.length > prevLength) {
+ // New content we need to present, reset to
+ // false in case previous content set this to true.
+ this.userMessageContentReady = false
+ }
+
+ // Present content to user.
+ presentAssistantMessage(this)
+ break
+ }
+
+ if (this.abort) {
+ console.log(`aborting stream, this.abandoned = ${this.abandoned}`)
+
+ if (!this.abandoned) {
+ // Only need to gracefully abort if this instance
+ // isn't abandoned (sometimes OpenRouter stream
+ // hangs, in which case this would affect future
+ // instances of Cline).
+ await abortStream("user_cancelled")
+ }
+
+ break // Aborts the stream.
+ }
+
+ if (this.didRejectTool) {
+ // `userContent` has a tool rejection, so interrupt the
+ // assistant's response to present the user's feedback.
+ assistantMessage += "\n\n[Response interrupted by user feedback]"
+ // Instead of setting this premptively, we allow the
+ // present iterator to finish and set
+ // userMessageContentReady when its ready.
+ // this.userMessageContentReady = true
+ break
+ }
+
+ // PREV: We need to let the request finish for openrouter to
+ // get generation details.
+ // UPDATE: It's better UX to interrupt the request at the
+ // cost of the API cost not being retrieved.
+ if (this.didAlreadyUseTool) {
+ assistantMessage +=
+ "\n\n[Response interrupted by a tool use result. Only one tool may be used at a time and should be placed at the end of the message.]"
+ break
+ }
+ }
+ } catch (error) {
+ // Abandoned happens when extension is no longer waiting for the
+ // Cline instance to finish aborting (error is thrown here when
+ // any function in the for loop throws due to this.abort).
+ if (!this.abandoned) {
+ // If the stream failed, there's various states the task
+ // could be in (i.e. could have streamed some tools the user
+ // may have executed), so we just resort to replicating a
+ // cancel task.
+ this.abortTask()
+
+ await abortStream(
+ "streaming_failed",
+ error.message ?? JSON.stringify(serializeError(error), null, 2),
+ )
+
+ const history = await provider?.getTaskWithId(this.taskId)
+
+ if (history) {
+ await provider?.initClineWithHistoryItem(history.historyItem)
+ }
+ }
+ } finally {
+ this.isStreaming = false
+ }
+
+ // Need to call here in case the stream was aborted.
+ if (this.abort || this.abandoned) {
+ throw new Error(`[Cline#recursivelyMakeClineRequests] task ${this.taskId}.${this.instanceId} aborted`)
+ }
+
+ this.didCompleteReadingStream = true
+
+ // Set any blocks to be complete to allow `presentAssistantMessage`
+ // to finish and set `userMessageContentReady` to true.
+ // (Could be a text block that had no subsequent tool uses, or a
+ // text block at the very end, or an invalid tool use, etc. Whatever
+ // the case, `presentAssistantMessage` relies on these blocks either
+ // to be completed or the user to reject a block in order to proceed
+ // and eventually set userMessageContentReady to true.)
+ const partialBlocks = this.assistantMessageContent.filter((block) => block.partial)
+ partialBlocks.forEach((block) => (block.partial = false))
+
+ // Can't just do this b/c a tool could be in the middle of executing.
+ // this.assistantMessageContent.forEach((e) => (e.partial = false))
+
+ if (partialBlocks.length > 0) {
+ // If there is content to update then it will complete and
+ // update `this.userMessageContentReady` to true, which we
+ // `pWaitFor` before making the next request. All this is really
+ // doing is presenting the last partial message that we just set
+ // to complete.
+ presentAssistantMessage(this)
+ }
+
+ updateApiReqMsg()
+ await this.saveClineMessages()
+ await this.providerRef.deref()?.postStateToWebview()
+
+ // Now add to apiConversationHistory.
+ // Need to save assistant responses to file before proceeding to
+ // tool use since user can exit at any moment and we wouldn't be
+ // able to save the assistant's response.
+ let didEndLoop = false
+
+ if (assistantMessage.length > 0) {
+ await this.addToApiConversationHistory({
+ role: "assistant",
+ content: [{ type: "text", text: assistantMessage }],
+ })
+
+ telemetryService.captureConversationMessage(this.taskId, "assistant")
+
+ // NOTE: This comment is here for future reference - this was a
+ // workaround for `userMessageContent` not getting set to true.
+ // It was due to it not recursively calling for partial blocks
+ // when `didRejectTool`, so it would get stuck waiting for a
+ // partial block to complete before it could continue.
+ // In case the content blocks finished it may be the api stream
+ // finished after the last parsed content block was executed, so
+ // we are able to detect out of bounds and set
+ // `userMessageContentReady` to true (note you should not call
+ // `presentAssistantMessage` since if the last block i
+ // completed it will be presented again).
+ // const completeBlocks = this.assistantMessageContent.filter((block) => !block.partial) // If there are any partial blocks after the stream ended we can consider them invalid.
+ // if (this.currentStreamingContentIndex >= completeBlocks.length) {
+ // this.userMessageContentReady = true
+ // }
+
+ await pWaitFor(() => this.userMessageContentReady)
+
+ // If the model did not tool use, then we need to tell it to
+ // either use a tool or attempt_completion.
+ const didToolUse = this.assistantMessageContent.some((block) => block.type === "tool_use")
+
+ if (!didToolUse) {
+ this.userMessageContent.push({ type: "text", text: formatResponse.noToolsUsed() })
+ this.consecutiveMistakeCount++
+ }
+
+ const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent)
+ didEndLoop = recDidEndLoop
+ } else {
+ // If there's no assistant_responses, that means we got no text
+ // or tool_use content blocks from API which we should assume is
+ // an error.
+ await this.say(
+ "error",
+ "Oops! Something went wrong. Please check the notifications on the bottom right of the window for more details, or contact PearAI Support on Discord.",
+ )
+
+ await this.addToApiConversationHistory({
+ role: "assistant",
+ content: [{ type: "text", text: "Failure: I did not provide a response." }],
+ })
+ }
+
+ return didEndLoop // Will always be false for now.
+ } catch (error) {
+ // This should never happen since the only thing that can throw an
+ // error is the attemptApiRequest, which is wrapped in a try catch
+ // that sends an ask where if noButtonClicked, will clear current
+ // task and destroy this instance. However to avoid unhandled
+ // promise rejection, we will end this loop which will end execution
+ // of this instance (see `startTask`).
+ return true // Needs to be true so parent loop knows to end task.
+ }
+ }
+
+ public async *attemptApiRequest(previousApiReqIndex: number, retryAttempt: number = 0): ApiStream {
+ let mcpHub: McpHub | undefined
+
+ const { apiConfiguration, mcpEnabled, autoApprovalEnabled, alwaysApproveResubmit, requestDelaySeconds } =
+ (await this.providerRef.deref()?.getState()) ?? {}
+
+ let rateLimitDelay = 0
+
+ // Only apply rate limiting if this isn't the first request
+ if (this.lastApiRequestTime) {
+ const now = Date.now()
+ const timeSinceLastRequest = now - this.lastApiRequestTime
+ const rateLimit = apiConfiguration?.rateLimitSeconds || 0
+ rateLimitDelay = Math.ceil(Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000)
+ }
+
+ // Only show rate limiting message if we're not retrying. If retrying, we'll include the delay there.
+ if (rateLimitDelay > 0 && retryAttempt === 0) {
+ // Show countdown timer
+ for (let i = rateLimitDelay; i > 0; i--) {
+ const delayMessage = `Rate limiting for ${i} seconds...`
+ await this.say("api_req_retry_delayed", delayMessage, undefined, true)
+ await delay(1000)
+ }
+ }
+
+ // Update last request time before making the request
+ this.lastApiRequestTime = Date.now()
+
+ if (mcpEnabled ?? true) {
+ const provider = this.providerRef.deref()
+
+ if (!provider) {
+ throw new Error("Provider reference lost during view transition")
+ }
+
+ // Wait for MCP hub initialization through McpServerManager
+ mcpHub = await McpServerManager.getInstance(provider.context, provider)
+
+ if (!mcpHub) {
+ throw new Error("Failed to get MCP hub from server manager")
+ }
+
+ // Wait for MCP servers to be connected before generating system prompt
+ await pWaitFor(() => !mcpHub!.isConnecting, { timeout: 10_000 }).catch(() => {
+ console.error("MCP servers failed to connect in time")
+ })
+ }
+
+ const rooIgnoreInstructions = this.rooIgnoreController?.getInstructions()
+
+ const {
+ browserViewportSize,
+ mode,
+ customModePrompts,
+ customInstructions,
+ experiments,
+ enableMcpServerCreation,
+ browserToolEnabled,
+ language,
+ } = (await this.providerRef.deref()?.getState()) ?? {}
+
+ const { customModes } = (await this.providerRef.deref()?.getState()) ?? {}
+
+ const systemPrompt = await (async () => {
+ const provider = this.providerRef.deref()
+
+ if (!provider) {
+ throw new Error("Provider not available")
+ }
+
+ return SYSTEM_PROMPT(
+ provider.context,
+ this.cwd,
+ (this.api.getModel().info.supportsComputerUse ?? false) && (browserToolEnabled ?? true),
+ mcpHub,
+ this.diffStrategy,
+ browserViewportSize,
+ mode,
+ customModePrompts,
+ customModes,
+ customInstructions,
+ this.diffEnabled,
+ experiments,
+ enableMcpServerCreation,
+ language,
+ rooIgnoreInstructions,
+ )
+ })()
+
+ // If the previous API request's total token usage is close to the
+ // context window, truncate the conversation history to free up space
+ // for the new request.
+ if (previousApiReqIndex >= 0) {
+ const previousRequest = this.clineMessages[previousApiReqIndex]?.text
+
+ if (!previousRequest) {
+ return
+ }
+
+ const {
+ tokensIn = 0,
+ tokensOut = 0,
+ cacheWrites = 0,
+ cacheReads = 0,
+ }: ClineApiReqInfo = JSON.parse(previousRequest)
+
+ const totalTokens = tokensIn + tokensOut + cacheWrites + cacheReads
+
+ // Default max tokens value for thinking models when no specific
+ // value is set.
+ const DEFAULT_THINKING_MODEL_MAX_TOKENS = 16_384
+
+ const modelInfo = this.api.getModel().info
+
+ const maxTokens = modelInfo.thinking
+ ? this.apiConfiguration.modelMaxTokens || DEFAULT_THINKING_MODEL_MAX_TOKENS
+ : modelInfo.maxTokens
+
+ const contextWindow = modelInfo.contextWindow
+
+ const autoCondenseContext = experiments?.autoCondenseContext ?? false
+ const trimmedMessages = await truncateConversationIfNeeded({
+ messages: this.apiConversationHistory,
+ totalTokens,
+ maxTokens,
+ contextWindow,
+ apiHandler: this.api,
+ autoCondenseContext,
+ })
+ if (trimmedMessages !== this.apiConversationHistory) {
+ await this.overwriteApiConversationHistory(trimmedMessages)
+ }
+ }
+
+ const messagesSinceLastSummary = getMessagesSinceLastSummary(this.apiConversationHistory)
+ const cleanConversationHistory = maybeRemoveImageBlocks(messagesSinceLastSummary, this.api).map(
+ ({ role, content }) => ({ role, content }),
+ )
+
+ const stream = this.api.createMessage(systemPrompt, cleanConversationHistory)
+ const iterator = stream[Symbol.asyncIterator]()
+
+ try {
+ // Awaiting first chunk to see if it will throw an error.
+ this.isWaitingForFirstChunk = true
+ const firstChunk = await iterator.next()
+ yield firstChunk.value
+ this.isWaitingForFirstChunk = false
+ } catch (error) {
+ this.isWaitingForFirstChunk = false
+ // note that this api_req_failed ask is unique in that we only present this option if the api hasn't streamed any content yet (ie it fails on the first chunk due), as it would allow them to hit a retry button. However if the api failed mid-stream, it could be in any arbitrary state where some tools may have executed, so that error is handled differently and requires cancelling the task entirely.
+ if (autoApprovalEnabled && alwaysApproveResubmit) {
+ let errorMsg
+
+ if (error.error?.metadata?.raw) {
+ errorMsg = JSON.stringify(error.error.metadata.raw, null, 2)
+ } else if (error.message) {
+ errorMsg = error.message
+ } else {
+ errorMsg = "Unknown error"
+ }
+
+ const baseDelay = requestDelaySeconds || 5
+ let exponentialDelay = Math.ceil(baseDelay * Math.pow(2, retryAttempt))
+
+ // If the error is a 429, and the error details contain a retry delay, use that delay instead of exponential backoff
+ if (error.status === 429) {
+ const geminiRetryDetails = error.errorDetails?.find(
+ (detail: any) => detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo",
+ )
+ if (geminiRetryDetails) {
+ const match = geminiRetryDetails?.retryDelay?.match(/^(\d+)s$/)
+ if (match) {
+ exponentialDelay = Number(match[1]) + 1
+ }
+ }
+ }
+
+ // Wait for the greater of the exponential delay or the rate limit delay
+ const finalDelay = Math.max(exponentialDelay, rateLimitDelay)
+
+ // Show countdown timer with exponential backoff
+ for (let i = finalDelay; i > 0; i--) {
+ await this.say(
+ "api_req_retry_delayed",
+ `${errorMsg}\n\nRetry attempt ${retryAttempt + 1}\nRetrying in ${i} seconds...`,
+ undefined,
+ true,
+ )
+ await delay(1000)
+ }
+
+ await this.say(
+ "api_req_retry_delayed",
+ `${errorMsg}\n\nRetry attempt ${retryAttempt + 1}\nRetrying now...`,
+ undefined,
+ false,
+ )
+
+ // Delegate generator output from the recursive call with
+ // incremented retry count.
+ yield* this.attemptApiRequest(previousApiReqIndex, retryAttempt + 1)
+
+ return
+ } else {
+ const { response } = await this.ask(
+ "api_req_failed",
+ error.message ?? JSON.stringify(serializeError(error), null, 2),
+ )
+
+ if (response !== "yesButtonClicked") {
+ // This will never happen since if noButtonClicked, we will
+ // clear current task, aborting this instance.
+ throw new Error("API request failed")
+ }
+
+ await this.say("api_req_retried")
+
+ // Delegate generator output from the recursive call.
+ yield* this.attemptApiRequest(previousApiReqIndex)
+ return
+ }
+ }
+
+ // No error, so we can continue to yield all remaining chunks.
+ // (Needs to be placed outside of try/catch since it we want caller to
+ // handle errors not with api_req_failed as that is reserved for first
+ // chunk failures only.)
+ // This delegates to another generator or iterable object. In this case,
+ // it's saying "yield all remaining values from this iterator". This
+ // effectively passes along all subsequent chunks from the original
+ // stream.
+ yield* iterator
+ }
+
+ // Checkpoints
+
+ public async checkpointSave() {
+ return checkpointSave(this)
+ }
+
+ public async checkpointRestore(options: CheckpointRestoreOptions) {
+ return checkpointRestore(this, options)
+ }
+
+ public async checkpointDiff(options: CheckpointDiffOptions) {
+ return checkpointDiff(this, options)
+ }
+
+ // Metrics
+
+ public combineMessages(messages: ClineMessage[]) {
+ return combineApiRequests(combineCommandSequences(messages))
+ }
+
+ public getTokenUsage() {
+ return getApiMetrics(this.combineMessages(this.clineMessages.slice(1)))
+ }
+
+ public recordToolUsage(toolName: ToolName) {
+ if (!this.toolUsage[toolName]) {
+ this.toolUsage[toolName] = { attempts: 0, failures: 0 }
+ }
+
+ this.toolUsage[toolName].attempts++
+ }
+
+ public recordToolError(toolName: ToolName, error?: string) {
+ if (!this.toolUsage[toolName]) {
+ this.toolUsage[toolName] = { attempts: 0, failures: 0 }
+ }
+
+ this.toolUsage[toolName].failures++
+
+ if (error) {
+ this.emit("taskToolFailed", this.taskId, toolName, error)
+ }
+ }
+
+ // Getters
+
+ public get cwd() {
+ return this.workspacePath
+ }
+}
diff --git a/src/core/__tests__/Cline.test.ts b/src/core/task/__tests__/Task.test.ts
similarity index 80%
rename from src/core/__tests__/Cline.test.ts
rename to src/core/task/__tests__/Task.test.ts
index 00a9c4dc6bf..84756b8a2de 100644
--- a/src/core/__tests__/Cline.test.ts
+++ b/src/core/task/__tests__/Task.test.ts
@@ -1,4 +1,4 @@
-// npx jest src/core/__tests__/Cline.test.ts
+// npx jest src/core/task/__tests__/Task.test.ts
import * as os from "os"
import * as path from "path"
@@ -6,47 +6,18 @@ import * as path from "path"
import * as vscode from "vscode"
import { Anthropic } from "@anthropic-ai/sdk"
-import { GlobalState } from "../../schemas"
-import { Cline } from "../Cline"
-import { ClineProvider } from "../webview/ClineProvider"
-import { ApiConfiguration, ModelInfo } from "../../shared/api"
-import { ApiStreamChunk } from "../../api/transform/stream"
-import { ContextProxy } from "../config/ContextProxy"
+import { GlobalState } from "../../../schemas"
+import { Task } from "../Task"
+import { ClineProvider } from "../../webview/ClineProvider"
+import { ProviderSettings, ModelInfo } from "../../../shared/api"
+import { ApiStreamChunk } from "../../../api/transform/stream"
+import { ContextProxy } from "../../config/ContextProxy"
+import { processUserContentMentions } from "../../mentions/processUserContentMentions"
jest.mock("execa", () => ({
execa: jest.fn(),
}))
-// Mock RooIgnoreController
-jest.mock("../ignore/RooIgnoreController")
-
-// Mock storagePathManager to prevent dynamic import issues
-jest.mock("../../shared/storagePathManager", () => ({
- getTaskDirectoryPath: jest
- .fn()
- .mockImplementation((globalStoragePath, taskId) => Promise.resolve(`${globalStoragePath}/tasks/${taskId}`)),
- getSettingsDirectoryPath: jest
- .fn()
- .mockImplementation((globalStoragePath) => Promise.resolve(`${globalStoragePath}/settings`)),
-}))
-
-// Mock fileExistsAtPath
-jest.mock("../../utils/fs", () => ({
- fileExistsAtPath: jest.fn().mockImplementation((filePath) => {
- return filePath.includes("ui_messages.json") || filePath.includes("api_conversation_history.json")
- }),
-}))
-
-// Mock fs/promises
-const mockMessages = [
- {
- ts: Date.now(),
- type: "say",
- say: "text",
- text: "historical task",
- },
-]
-
jest.mock("fs/promises", () => ({
mkdir: jest.fn().mockResolvedValue(undefined),
writeFile: jest.fn().mockResolvedValue(undefined),
@@ -76,37 +47,21 @@ jest.mock("fs/promises", () => ({
rmdir: jest.fn().mockResolvedValue(undefined),
}))
-// Mock dependencies
+jest.mock("p-wait-for", () => ({
+ __esModule: true,
+ default: jest.fn().mockImplementation(async () => Promise.resolve()),
+}))
+
jest.mock("vscode", () => {
const mockDisposable = { dispose: jest.fn() }
- const mockEventEmitter = {
- event: jest.fn(),
- fire: jest.fn(),
- }
-
- const mockTextDocument = {
- uri: {
- fsPath: "/mock/workspace/path/file.ts",
- },
- }
-
- const mockTextEditor = {
- document: mockTextDocument,
- }
-
- const mockTab = {
- input: {
- uri: {
- fsPath: "/mock/workspace/path/file.ts",
- },
- },
- }
-
- const mockTabGroup = {
- tabs: [mockTab],
- }
+ const mockEventEmitter = { event: jest.fn(), fire: jest.fn() }
+ const mockTextDocument = { uri: { fsPath: "/mock/workspace/path/file.ts" } }
+ const mockTextEditor = { document: mockTextDocument }
+ const mockTab = { input: { uri: { fsPath: "/mock/workspace/path/file.ts" } } }
+ const mockTabGroup = { tabs: [mockTab] }
return {
+ TabInputTextDiff: jest.fn(),
CodeActionKind: {
QuickFix: { value: "quickfix" },
RefactorRewrite: { value: "refactor.rewrite" },
@@ -118,6 +73,7 @@ jest.mock("vscode", () => {
visibleTextEditors: [mockTextEditor],
tabGroups: {
all: [mockTabGroup],
+ close: jest.fn(),
onDidChangeTabs: jest.fn(() => ({ dispose: jest.fn() })),
},
showErrorMessage: jest.fn(),
@@ -125,9 +81,7 @@ jest.mock("vscode", () => {
workspace: {
workspaceFolders: [
{
- uri: {
- fsPath: "/mock/workspace/path",
- },
+ uri: { fsPath: "/mock/workspace/path" },
name: "mock-workspace",
index: 0,
},
@@ -156,15 +110,55 @@ jest.mock("vscode", () => {
}
})
-// Mock p-wait-for to resolve immediately
-jest.mock("p-wait-for", () => ({
- __esModule: true,
- default: jest.fn().mockImplementation(async () => Promise.resolve()),
+jest.mock("../../mentions", () => ({
+ parseMentions: jest.fn().mockImplementation((text) => {
+ return Promise.resolve(`processed: ${text}`)
+ }),
+ openMention: jest.fn(),
+ getLatestTerminalOutput: jest.fn(),
+}))
+
+jest.mock("../../../integrations/misc/extract-text", () => ({
+ extractTextFromFile: jest.fn().mockResolvedValue("Mock file content"),
+}))
+
+jest.mock("../../environment/getEnvironmentDetails", () => ({
+ getEnvironmentDetails: jest.fn().mockResolvedValue(""),
+}))
+
+// Mock RooIgnoreController
+jest.mock("../../ignore/RooIgnoreController")
+
+// Mock storagePathManager to prevent dynamic import issues
+jest.mock("../../../shared/storagePathManager", () => ({
+ getTaskDirectoryPath: jest
+ .fn()
+ .mockImplementation((globalStoragePath, taskId) => Promise.resolve(`${globalStoragePath}/tasks/${taskId}`)),
+ getSettingsDirectoryPath: jest
+ .fn()
+ .mockImplementation((globalStoragePath) => Promise.resolve(`${globalStoragePath}/settings`)),
+}))
+
+// Mock fileExistsAtPath
+jest.mock("../../../utils/fs", () => ({
+ fileExistsAtPath: jest.fn().mockImplementation((filePath) => {
+ return filePath.includes("ui_messages.json") || filePath.includes("api_conversation_history.json")
+ }),
}))
+// Mock fs/promises
+const mockMessages = [
+ {
+ ts: Date.now(),
+ type: "say",
+ say: "text",
+ text: "historical task",
+ },
+]
+
describe("Cline", () => {
let mockProvider: jest.Mocked
- let mockApiConfig: ApiConfiguration
+ let mockApiConfig: ProviderSettings
let mockOutputChannel: any
let mockExtensionContext: vscode.ExtensionContext
@@ -278,24 +272,21 @@ describe("Cline", () => {
describe("constructor", () => {
it("should respect provided settings", async () => {
- const cline = new Cline({
+ const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
- customInstructions: "custom instructions",
fuzzyMatchThreshold: 0.95,
task: "test task",
startTask: false,
})
- expect(cline.customInstructions).toBe("custom instructions")
expect(cline.diffEnabled).toBe(false)
})
it("should use default fuzzy match threshold when not provided", async () => {
- const cline = new Cline({
+ const cline = new Task({
provider: mockProvider,
apiConfiguration: mockApiConfig,
- customInstructions: "custom instructions",
enableDiff: true,
fuzzyMatchThreshold: 0.95,
task: "test task",
@@ -310,99 +301,16 @@ describe("Cline", () => {
it("should require either task or historyItem", () => {
expect(() => {
- new Cline({ provider: mockProvider, apiConfiguration: mockApiConfig })
+ new Task({ provider: mockProvider, apiConfiguration: mockApiConfig })
}).toThrow("Either historyItem or task/images must be provided")
})
})
describe("getEnvironmentDetails", () => {
- let originalDate: DateConstructor
- let mockDate: Date
-
- beforeEach(() => {
- originalDate = global.Date
- const fixedTime = new Date("2024-01-01T12:00:00Z")
- mockDate = new Date(fixedTime)
- mockDate.getTimezoneOffset = jest.fn().mockReturnValue(420) // UTC-7
-
- class MockDate extends Date {
- constructor() {
- super()
- return mockDate
- }
- static override now() {
- return mockDate.getTime()
- }
- }
-
- global.Date = MockDate as DateConstructor
-
- // Create a proper mock of Intl.DateTimeFormat
- const mockDateTimeFormat = {
- resolvedOptions: () => ({
- timeZone: "America/Los_Angeles",
- }),
- format: () => "1/1/2024, 5:00:00 AM",
- }
-
- const MockDateTimeFormat = function (this: any) {
- return mockDateTimeFormat
- } as any
-
- MockDateTimeFormat.prototype = mockDateTimeFormat
- MockDateTimeFormat.supportedLocalesOf = jest.fn().mockReturnValue(["en-US"])
-
- global.Intl.DateTimeFormat = MockDateTimeFormat
- })
-
- afterEach(() => {
- global.Date = originalDate
- })
-
- it("should include timezone information in environment details", async () => {
- const cline = new Cline({
- provider: mockProvider,
- apiConfiguration: mockApiConfig,
- task: "test task",
- startTask: false,
- })
-
- const details = await cline["getEnvironmentDetails"](false)
-
- // Verify timezone information is present and formatted correctly.
- expect(details).toContain("America/Los_Angeles")
- expect(details).toMatch(/UTC-7:00/) // Fixed offset for America/Los_Angeles.
- expect(details).toContain("# Current Time")
- expect(details).toMatch(/1\/1\/2024.*5:00:00 AM.*\(America\/Los_Angeles, UTC-7:00\)/) // Full time string format.
- })
-
describe("API conversation handling", () => {
- /**
- * Mock environment details retrieval to avoid filesystem access in tests
- *
- * This setup:
- * 1. Prevents file listing operations that might cause test instability
- * 2. Preserves test-specific mocks when they exist (via _mockGetEnvironmentDetails)
- * 3. Provides a stable, empty environment by default
- */
- beforeEach(() => {
- // Mock the method with a stable implementation
- jest.spyOn(Cline.prototype, "getEnvironmentDetails").mockImplementation(
- // Use 'any' type to allow for dynamic test properties
- async function (this: any, _verbose: boolean = false): Promise {
- // Use test-specific mock if available
- if (this._mockGetEnvironmentDetails) {
- return this._mockGetEnvironmentDetails()
- }
- // Default to empty environment details for stability
- return ""
- },
- )
- })
-
it("should clean conversation history before sending to API", async () => {
// Cline.create will now use our mocked getEnvironmentDetails
- const [cline, task] = Cline.create({
+ const [cline, task] = Task.create({
provider: mockProvider,
apiConfiguration: mockApiConfig,
task: "test task",
@@ -420,12 +328,6 @@ describe("Cline", () => {
const cleanMessageSpy = jest.fn().mockReturnValue(mockStreamForClean)
jest.spyOn(cline.api, "createMessage").mockImplementation(cleanMessageSpy)
- // Mock getEnvironmentDetails to return empty details.
- jest.spyOn(cline as any, "getEnvironmentDetails").mockResolvedValue("")
-
- // Mock loadContext to return unmodified content.
- jest.spyOn(cline as any, "loadContext").mockImplementation(async (content) => [content, ""])
-
// Add test message to conversation history.
cline.apiConversationHistory = [
{
@@ -516,7 +418,7 @@ describe("Cline", () => {
]
// Test with model that supports images
- const [clineWithImages, taskWithImages] = Cline.create({
+ const [clineWithImages, taskWithImages] = Task.create({
provider: mockProvider,
apiConfiguration: configWithImages,
task: "test task",
@@ -539,7 +441,7 @@ describe("Cline", () => {
clineWithImages.apiConversationHistory = conversationHistory
// Test with model that doesn't support images
- const [clineWithoutImages, taskWithoutImages] = Cline.create({
+ const [clineWithoutImages, taskWithoutImages] = Task.create({
provider: mockProvider,
apiConfiguration: configWithoutImages,
task: "test task",
@@ -574,15 +476,6 @@ describe("Cline", () => {
configurable: true,
})
- // Mock environment details and context loading
- jest.spyOn(clineWithImages as any, "getEnvironmentDetails").mockResolvedValue("")
- jest.spyOn(clineWithoutImages as any, "getEnvironmentDetails").mockResolvedValue("")
- jest.spyOn(clineWithImages as any, "loadContext").mockImplementation(async (content) => [content, ""])
- jest.spyOn(clineWithoutImages as any, "loadContext").mockImplementation(async (content) => [
- content,
- "",
- ])
-
// Set up mock streams
const mockStreamWithImages = (async function* () {
yield { type: "text", text: "test response" }
@@ -639,7 +532,7 @@ describe("Cline", () => {
})
it.skip("should handle API retry with countdown", async () => {
- const [cline, task] = Cline.create({
+ const [cline, task] = Task.create({
provider: mockProvider,
apiConfiguration: mockApiConfig,
task: "test task",
@@ -763,7 +656,7 @@ describe("Cline", () => {
})
it.skip("should not apply retry delay twice", async () => {
- const [cline, task] = Cline.create({
+ const [cline, task] = Task.create({
provider: mockProvider,
apiConfiguration: mockApiConfig,
task: "test task",
@@ -885,18 +778,14 @@ describe("Cline", () => {
await task.catch(() => {})
})
- describe("loadContext", () => {
+ describe("processUserContentMentions", () => {
it("should process mentions in task and feedback tags", async () => {
- const [cline, task] = Cline.create({
+ const [cline, task] = Task.create({
provider: mockProvider,
apiConfiguration: mockApiConfig,
task: "test task",
})
- // Mock parseMentions to track calls
- const mockParseMentions = jest.fn().mockImplementation((text) => `processed: ${text}`)
- jest.spyOn(require("../../core/mentions"), "parseMentions").mockImplementation(mockParseMentions)
-
const userContent = [
{
type: "text",
@@ -928,30 +817,28 @@ describe("Cline", () => {
} as Anthropic.ToolResultBlockParam,
]
- // Process the content
- const [processedContent] = await cline["loadContext"](userContent)
+ const processedContent = await processUserContentMentions({
+ userContent,
+ cwd: cline.cwd,
+ urlContentFetcher: cline.urlContentFetcher,
+ fileContextTracker: cline.fileContextTracker,
+ })
// Regular text should not be processed
expect((processedContent[0] as Anthropic.TextBlockParam).text).toBe("Regular text with @/some/path")
// Text within task tags should be processed
expect((processedContent[1] as Anthropic.TextBlockParam).text).toContain("processed:")
- expect(mockParseMentions).toHaveBeenCalledWith(
+ expect((processedContent[1] as Anthropic.TextBlockParam).text).toContain(
"Text with @/some/path in task tags",
- expect.any(String),
- expect.any(Object),
- expect.any(Object),
)
// Feedback tag content should be processed
const toolResult1 = processedContent[2] as Anthropic.ToolResultBlockParam
const content1 = Array.isArray(toolResult1.content) ? toolResult1.content[0] : toolResult1.content
expect((content1 as Anthropic.TextBlockParam).text).toContain("processed:")
- expect(mockParseMentions).toHaveBeenCalledWith(
+ expect((content1 as Anthropic.TextBlockParam).text).toContain(
"Check @/some/path",
- expect.any(String),
- expect.any(Object),
- expect.any(Object),
)
// Regular tool result should not be processed
diff --git a/src/core/tools/ToolRepetitionDetector.ts b/src/core/tools/ToolRepetitionDetector.ts
new file mode 100644
index 00000000000..a82574ba0e3
--- /dev/null
+++ b/src/core/tools/ToolRepetitionDetector.ts
@@ -0,0 +1,95 @@
+import { ToolUse } from "../../shared/tools"
+import { t } from "../../i18n"
+
+/**
+ * Class for detecting consecutive identical tool calls
+ * to prevent the AI from getting stuck in a loop.
+ */
+export class ToolRepetitionDetector {
+ private previousToolCallJson: string | null = null
+ private consecutiveIdenticalToolCallCount: number = 0
+ private readonly consecutiveIdenticalToolCallLimit: number
+
+ /**
+ * Creates a new ToolRepetitionDetector
+ * @param limit The maximum number of identical consecutive tool calls allowed
+ */
+ constructor(limit: number = 3) {
+ this.consecutiveIdenticalToolCallLimit = limit
+ }
+
+ /**
+ * Checks if the current tool call is identical to the previous one
+ * and determines if execution should be allowed
+ *
+ * @param currentToolCallBlock ToolUse object representing the current tool call
+ * @returns Object indicating if execution is allowed and a message to show if not
+ */
+ public check(currentToolCallBlock: ToolUse): {
+ allowExecution: boolean
+ askUser?: {
+ messageKey: string
+ messageDetail: string
+ }
+ } {
+ // Serialize the block to a canonical JSON string for comparison
+ const currentToolCallJson = this.serializeToolUse(currentToolCallBlock)
+
+ // Compare with previous tool call
+ if (this.previousToolCallJson === currentToolCallJson) {
+ this.consecutiveIdenticalToolCallCount++
+ } else {
+ this.consecutiveIdenticalToolCallCount = 1 // Start with 1 for the first occurrence
+ this.previousToolCallJson = currentToolCallJson
+ }
+
+ // Check if limit is reached
+ if (this.consecutiveIdenticalToolCallCount >= this.consecutiveIdenticalToolCallLimit) {
+ // Reset counters to allow recovery if user guides the AI past this point
+ this.consecutiveIdenticalToolCallCount = 0
+ this.previousToolCallJson = null
+
+ // Return result indicating execution should not be allowed
+ return {
+ allowExecution: false,
+ askUser: {
+ messageKey: "mistake_limit_reached",
+ messageDetail: t("tools:toolRepetitionLimitReached", { toolName: currentToolCallBlock.name }),
+ },
+ }
+ }
+
+ // Execution is allowed
+ return { allowExecution: true }
+ }
+
+ /**
+ * Serializes a ToolUse object into a canonical JSON string for comparison
+ *
+ * @param toolUse The ToolUse object to serialize
+ * @returns JSON string representation of the tool use with sorted parameter keys
+ */
+ private serializeToolUse(toolUse: ToolUse): string {
+ // Create a new parameters object with alphabetically sorted keys
+ const sortedParams: Record = {}
+
+ // Get parameter keys and sort them alphabetically
+ const sortedKeys = Object.keys(toolUse.params).sort()
+
+ // Populate the sorted parameters object in a type-safe way
+ for (const key of sortedKeys) {
+ if (Object.prototype.hasOwnProperty.call(toolUse.params, key)) {
+ sortedParams[key] = toolUse.params[key as keyof typeof toolUse.params]
+ }
+ }
+
+ // Create the object with the tool name and sorted parameters
+ const toolObject = {
+ name: toolUse.name,
+ parameters: sortedParams,
+ }
+
+ // Convert to a canonical JSON string
+ return JSON.stringify(toolObject)
+ }
+}
diff --git a/src/core/tools/__tests__/ToolRepetitionDetector.test.ts b/src/core/tools/__tests__/ToolRepetitionDetector.test.ts
new file mode 100644
index 00000000000..846011b5d82
--- /dev/null
+++ b/src/core/tools/__tests__/ToolRepetitionDetector.test.ts
@@ -0,0 +1,304 @@
+// npx jest src/core/tools/__tests__/ToolRepetitionDetector.test.ts
+
+import type { ToolName } from "../../../schemas"
+import type { ToolUse } from "../../../shared/tools"
+
+import { ToolRepetitionDetector } from "../ToolRepetitionDetector"
+
+jest.mock("../../../i18n", () => ({
+ t: jest.fn((key, options) => {
+ // For toolRepetitionLimitReached key, return a message with the tool name.
+ if (key === "tools:toolRepetitionLimitReached" && options?.toolName) {
+ return `Roo appears to be stuck in a loop, attempting the same action (${options.toolName}) repeatedly. This might indicate a problem with its current strategy.`
+ }
+ return key
+ }),
+}))
+
+function createToolUse(name: string, displayName?: string, params: Record = {}): ToolUse {
+ return {
+ type: "tool_use",
+ name: (displayName || name) as ToolName,
+ params,
+ partial: false,
+ }
+}
+
+describe("ToolRepetitionDetector", () => {
+ // ===== Initialization tests =====
+ describe("initialization", () => {
+ it("should default to a limit of 3 if no argument provided", () => {
+ const detector = new ToolRepetitionDetector()
+ // We'll verify this through behavior in subsequent tests
+
+ // First call (counter = 1)
+ const result1 = detector.check(createToolUse("test", "test-tool"))
+ expect(result1.allowExecution).toBe(true)
+
+ // Second identical call (counter = 2)
+ const result2 = detector.check(createToolUse("test", "test-tool"))
+ expect(result2.allowExecution).toBe(true)
+
+ // Third identical call (counter = 3) reaches the default limit
+ const result3 = detector.check(createToolUse("test", "test-tool"))
+ expect(result3.allowExecution).toBe(false)
+ })
+
+ it("should use the custom limit when provided", () => {
+ const customLimit = 2
+ const detector = new ToolRepetitionDetector(customLimit)
+
+ // First call (counter = 1)
+ const result1 = detector.check(createToolUse("test", "test-tool"))
+ expect(result1.allowExecution).toBe(true)
+
+ // Second identical call (counter = 2) reaches the custom limit
+ const result2 = detector.check(createToolUse("test", "test-tool"))
+ expect(result2.allowExecution).toBe(false)
+ })
+ })
+
+ // ===== No Repetition tests =====
+ describe("no repetition", () => {
+ it("should allow execution for different tool calls", () => {
+ const detector = new ToolRepetitionDetector()
+
+ const result1 = detector.check(createToolUse("first", "first-tool"))
+ expect(result1.allowExecution).toBe(true)
+ expect(result1.askUser).toBeUndefined()
+
+ const result2 = detector.check(createToolUse("second", "second-tool"))
+ expect(result2.allowExecution).toBe(true)
+ expect(result2.askUser).toBeUndefined()
+
+ const result3 = detector.check(createToolUse("third", "third-tool"))
+ expect(result3.allowExecution).toBe(true)
+ expect(result3.askUser).toBeUndefined()
+ })
+
+ it("should reset the counter when different tool calls are made", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // First call
+ detector.check(createToolUse("same", "same-tool"))
+
+ // Second identical call would reach limit of 2, but we'll make a different call
+ detector.check(createToolUse("different", "different-tool"))
+
+ // Back to the first tool - should be allowed since counter was reset
+ const result = detector.check(createToolUse("same", "same-tool"))
+ expect(result.allowExecution).toBe(true)
+ })
+ })
+
+ // ===== Repetition Below Limit tests =====
+ describe("repetition below limit", () => {
+ it("should allow execution when repetition is below limit and block when limit reached", () => {
+ const detector = new ToolRepetitionDetector(3)
+
+ // First call (counter = 1)
+ const result1 = detector.check(createToolUse("repeat", "repeat-tool"))
+ expect(result1.allowExecution).toBe(true)
+
+ // Second identical call (counter = 2)
+ const result2 = detector.check(createToolUse("repeat", "repeat-tool"))
+ expect(result2.allowExecution).toBe(true)
+
+ // Third identical call (counter = 3) reaches limit
+ const result3 = detector.check(createToolUse("repeat", "repeat-tool"))
+ expect(result3.allowExecution).toBe(false)
+ })
+ })
+
+ // ===== Repetition Reaches Limit tests =====
+ describe("repetition reaches limit", () => {
+ it("should block execution when repetition reaches the limit", () => {
+ const detector = new ToolRepetitionDetector(3)
+
+ // First call (counter = 1)
+ detector.check(createToolUse("repeat", "repeat-tool"))
+
+ // Second identical call (counter = 2)
+ detector.check(createToolUse("repeat", "repeat-tool"))
+
+ // Third identical call (counter = 3) - should reach limit
+ const result = detector.check(createToolUse("repeat", "repeat-tool"))
+
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ expect(result.askUser?.messageKey).toBe("mistake_limit_reached")
+ expect(result.askUser?.messageDetail).toContain("repeat-tool")
+ })
+
+ it("should reset internal state after limit is reached", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // Reach the limit
+ detector.check(createToolUse("repeat", "repeat-tool"))
+ const limitResult = detector.check(createToolUse("repeat", "repeat-tool")) // This reaches limit
+ expect(limitResult.allowExecution).toBe(false)
+
+ // Use a new tool call - should be allowed since state was reset
+ const result = detector.check(createToolUse("new", "new-tool"))
+ expect(result.allowExecution).toBe(true)
+ })
+ })
+
+ // ===== Repetition After Limit (Post-Reset) tests =====
+ describe("repetition after limit", () => {
+ it("should allow execution of previously problematic tool after reset", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // Reach the limit with a specific tool
+ detector.check(createToolUse("problem", "problem-tool"))
+ const limitResult = detector.check(createToolUse("problem", "problem-tool")) // This reaches limit
+ expect(limitResult.allowExecution).toBe(false)
+
+ // The same tool that previously caused problems should now be allowed
+ const result = detector.check(createToolUse("problem", "problem-tool"))
+ expect(result.allowExecution).toBe(true)
+ })
+
+ it("should require reaching the limit again after reset", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // Reach the limit
+ detector.check(createToolUse("repeat", "repeat-tool"))
+ const limitResult = detector.check(createToolUse("repeat", "repeat-tool")) // This reaches limit
+ expect(limitResult.allowExecution).toBe(false)
+
+ // First call after reset
+ detector.check(createToolUse("repeat", "repeat-tool"))
+
+ // Second identical call (counter = 2) should reach limit again
+ const result = detector.check(createToolUse("repeat", "repeat-tool"))
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ })
+ })
+
+ // ===== Tool Name Interpolation tests =====
+ describe("tool name interpolation", () => {
+ it("should include tool name in the error message", () => {
+ const detector = new ToolRepetitionDetector(2)
+ const toolName = "special-tool-name"
+
+ // Reach the limit
+ detector.check(createToolUse("test", toolName))
+ const result = detector.check(createToolUse("test", toolName))
+
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser?.messageDetail).toContain(toolName)
+ })
+ })
+
+ // ===== Edge Cases =====
+ describe("edge cases", () => {
+ it("should handle empty tool call", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // Create an empty tool call - a tool with no parameters
+ // Use the empty tool directly in the check calls
+ detector.check(createToolUse("empty-tool", "empty-tool"))
+ const result = detector.check(createToolUse("empty-tool"))
+
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ })
+
+ it("should handle different tool names with identical serialized JSON", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // First, call with tool-name-1 twice to set up the counter
+ const toolUse1 = createToolUse("tool-name-1", "tool-name-1", { param: "value" })
+ detector.check(toolUse1)
+
+ // Create a tool that will serialize to the same JSON as toolUse1
+ // We need to mock the serializeToolUse method to return the same value
+ const toolUse2 = createToolUse("tool-name-2", "tool-name-2", { param: "value" })
+
+ // Override the private method to force identical serialization
+ const originalSerialize = (detector as any).serializeToolUse
+ ;(detector as any).serializeToolUse = (tool: ToolUse) => {
+ // Use string comparison for the name since it's technically an enum
+ if (String(tool.name) === "tool-name-2") {
+ return (detector as any).serializeToolUse(toolUse1) // Return the same JSON as toolUse1
+ }
+ return originalSerialize(tool)
+ }
+
+ // This should detect as a repetition now
+ const result = detector.check(toolUse2)
+
+ // Restore the original method
+ ;(detector as any).serializeToolUse = originalSerialize
+
+ // Since we're directly manipulating the internal state for testing,
+ // we still expect it to consider this a repetition
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ })
+
+ it("should treat tools with same parameters in different order as identical", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // First call with parameters in one order
+ const toolUse1 = createToolUse("same-tool", "same-tool", { a: "1", b: "2", c: "3" })
+ detector.check(toolUse1)
+
+ // Create tool with same parameters but in different order
+ const toolUse2 = createToolUse("same-tool", "same-tool", { c: "3", a: "1", b: "2" })
+
+ // This should still detect as a repetition due to canonical JSON with sorted keys
+ const result = detector.check(toolUse2)
+
+ // Since parameters are sorted alphabetically in the serialized JSON,
+ // these should be considered identical
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ })
+ })
+
+ // ===== Explicit Nth Call Blocking tests =====
+ describe("explicit Nth call blocking behavior", () => {
+ it("should block on the 1st call for limit 1", () => {
+ const detector = new ToolRepetitionDetector(1)
+
+ // First call (counter = 1) should be blocked
+ const result = detector.check(createToolUse("tool", "tool-name"))
+
+ expect(result.allowExecution).toBe(false)
+ expect(result.askUser).toBeDefined()
+ })
+
+ it("should block on the 2nd call for limit 2", () => {
+ const detector = new ToolRepetitionDetector(2)
+
+ // First call (counter = 1)
+ const result1 = detector.check(createToolUse("tool", "tool-name"))
+ expect(result1.allowExecution).toBe(true)
+
+ // Second call (counter = 2) should be blocked
+ const result2 = detector.check(createToolUse("tool", "tool-name"))
+ expect(result2.allowExecution).toBe(false)
+ expect(result2.askUser).toBeDefined()
+ })
+
+ it("should block on the 3rd call for limit 3 (default)", () => {
+ const detector = new ToolRepetitionDetector(3)
+
+ // First call (counter = 1)
+ const result1 = detector.check(createToolUse("tool", "tool-name"))
+ expect(result1.allowExecution).toBe(true)
+
+ // Second call (counter = 2)
+ const result2 = detector.check(createToolUse("tool", "tool-name"))
+ expect(result2.allowExecution).toBe(true)
+
+ // Third call (counter = 3) should be blocked
+ const result3 = detector.check(createToolUse("tool", "tool-name"))
+ expect(result3.allowExecution).toBe(false)
+ expect(result3.askUser).toBeDefined()
+ })
+ })
+})
diff --git a/src/core/tools/__tests__/executeCommandTool.test.ts b/src/core/tools/__tests__/executeCommandTool.test.ts
index ee70ae5c097..615d72042df 100644
--- a/src/core/tools/__tests__/executeCommandTool.test.ts
+++ b/src/core/tools/__tests__/executeCommandTool.test.ts
@@ -2,7 +2,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
-import { Cline } from "../../Cline"
+import { Task } from "../../task/Task"
import { formatResponse } from "../../prompts/responses"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../../shared/tools"
import { ToolUsage } from "../../../schemas"
@@ -13,7 +13,7 @@ jest.mock("execa", () => ({
execa: jest.fn(),
}))
-jest.mock("../../Cline")
+jest.mock("../../task/Task")
jest.mock("../../prompts/responses")
// Create a mock for the executeCommand function
@@ -74,7 +74,7 @@ beforeEach(() => {
describe("executeCommandTool", () => {
// Setup common test variables
- let mockCline: jest.Mocked> & { consecutiveMistakeCount: number; didRejectTool: boolean }
+ let mockCline: jest.Mocked> & { consecutiveMistakeCount: number; didRejectTool: boolean }
let mockAskApproval: jest.Mock
let mockHandleError: jest.Mock
let mockPushToolResult: jest.Mock
@@ -160,7 +160,7 @@ describe("executeCommandTool", () => {
// Execute
await executeCommandTool(
- mockCline as unknown as Cline,
+ mockCline as unknown as Task,
mockToolUse,
mockAskApproval as unknown as AskApproval,
mockHandleError as unknown as HandleError,
@@ -181,7 +181,7 @@ describe("executeCommandTool", () => {
// Execute
await executeCommandTool(
- mockCline as unknown as Cline,
+ mockCline as unknown as Task,
mockToolUse,
mockAskApproval as unknown as AskApproval,
mockHandleError as unknown as HandleError,
@@ -204,7 +204,7 @@ describe("executeCommandTool", () => {
// Execute
await executeCommandTool(
- mockCline as unknown as Cline,
+ mockCline as unknown as Task,
mockToolUse,
mockAskApproval as unknown as AskApproval,
mockHandleError as unknown as HandleError,
@@ -228,7 +228,7 @@ describe("executeCommandTool", () => {
// Execute
await executeCommandTool(
- mockCline as unknown as Cline,
+ mockCline as unknown as Task,
mockToolUse,
mockAskApproval as unknown as AskApproval,
mockHandleError as unknown as HandleError,
@@ -258,7 +258,7 @@ describe("executeCommandTool", () => {
// Execute
await executeCommandTool(
- mockCline as unknown as Cline,
+ mockCline as unknown as Task,
mockToolUse,
mockAskApproval as unknown as AskApproval,
mockHandleError as unknown as HandleError,
diff --git a/src/core/__tests__/read-file-xml.test.ts b/src/core/tools/__tests__/readFileTool.test.ts
similarity index 57%
rename from src/core/__tests__/read-file-xml.test.ts
rename to src/core/tools/__tests__/readFileTool.test.ts
index 1228750a7df..f0b3600a261 100644
--- a/src/core/__tests__/read-file-xml.test.ts
+++ b/src/core/tools/__tests__/readFileTool.test.ts
@@ -1,42 +1,58 @@
-// npx jest src/core/__tests__/read-file-xml.test.ts
+// npx jest src/core/tools/__tests__/readFileTool.test.ts
import * as path from "path"
-import { countFileLines } from "../../integrations/misc/line-counter"
-import { readLines } from "../../integrations/misc/read-lines"
-import { extractTextFromFile } from "../../integrations/misc/extract-text"
-import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
+import { countFileLines } from "../../../integrations/misc/line-counter"
+import { readLines } from "../../../integrations/misc/read-lines"
+import { extractTextFromFile } from "../../../integrations/misc/extract-text"
+import { parseSourceCodeDefinitionsForFile } from "../../../services/tree-sitter"
import { isBinaryFile } from "isbinaryfile"
-import { ReadFileToolUse } from "../../shared/tools"
-
-// Mock dependencies
-jest.mock("../../integrations/misc/line-counter")
-jest.mock("../../integrations/misc/read-lines")
-jest.mock("../../integrations/misc/extract-text", () => {
- const actual = jest.requireActual("../../integrations/misc/extract-text")
- // Create a spy on the actual addLineNumbers function
+import { ReadFileToolUse, ToolParamName, ToolResponse } from "../../../shared/tools"
+import { readFileTool } from "../readFileTool"
+
+jest.mock("path", () => {
+ const originalPath = jest.requireActual("path")
+ return {
+ ...originalPath,
+ resolve: jest.fn().mockImplementation((...args) => args.join("/")),
+ }
+})
+
+jest.mock("fs/promises", () => ({
+ mkdir: jest.fn().mockResolvedValue(undefined),
+ writeFile: jest.fn().mockResolvedValue(undefined),
+ readFile: jest.fn().mockResolvedValue("{}"),
+}))
+
+jest.mock("isbinaryfile")
+
+jest.mock("../../../integrations/misc/line-counter")
+jest.mock("../../../integrations/misc/read-lines")
+
+let mockInputContent = ""
+
+jest.mock("../../../integrations/misc/extract-text", () => {
+ const actual = jest.requireActual("../../../integrations/misc/extract-text")
+ // Create a spy on the actual addLineNumbers function.
const addLineNumbersSpy = jest.spyOn(actual, "addLineNumbers")
return {
...actual,
- // Expose the spy so tests can access it
+ // Expose the spy so tests can access it.
__addLineNumbersSpy: addLineNumbersSpy,
extractTextFromFile: jest.fn().mockImplementation((_filePath) => {
- // Use the actual addLineNumbers function
+ // Use the actual addLineNumbers function.
const content = mockInputContent
return Promise.resolve(actual.addLineNumbers(content))
}),
}
})
-// Get a reference to the spy
-const addLineNumbersSpy = jest.requireMock("../../integrations/misc/extract-text").__addLineNumbersSpy
+const addLineNumbersSpy = jest.requireMock("../../../integrations/misc/extract-text").__addLineNumbersSpy
-// Variable to control what content is used by the mock
-let mockInputContent = ""
-jest.mock("../../services/tree-sitter")
-jest.mock("isbinaryfile")
-jest.mock("../ignore/RooIgnoreController", () => ({
+jest.mock("../../../services/tree-sitter")
+
+jest.mock("../../ignore/RooIgnoreController", () => ({
RooIgnoreController: class {
initialize() {
return Promise.resolve()
@@ -46,22 +62,345 @@ jest.mock("../ignore/RooIgnoreController", () => ({
}
},
}))
-jest.mock("fs/promises", () => ({
- mkdir: jest.fn().mockResolvedValue(undefined),
- writeFile: jest.fn().mockResolvedValue(undefined),
- readFile: jest.fn().mockResolvedValue("{}"),
-}))
-jest.mock("../../utils/fs", () => ({
+
+jest.mock("../../../utils/fs", () => ({
fileExistsAtPath: jest.fn().mockReturnValue(true),
}))
-// Mock path
-jest.mock("path", () => {
- const originalPath = jest.requireActual("path")
- return {
- ...originalPath,
- resolve: jest.fn().mockImplementation((...args) => args.join("/")),
+describe("read_file tool with maxReadFileLine setting", () => {
+ // Test data
+ const testFilePath = "test/file.txt"
+ const absoluteFilePath = "/test/file.txt"
+ const fileContent = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5"
+ const numberedFileContent = "1 | Line 1\n2 | Line 2\n3 | Line 3\n4 | Line 4\n5 | Line 5\n"
+ const sourceCodeDef = "\n\n# file.txt\n1--5 | Content"
+ const expectedFullFileXml = `${testFilePath}\n\n${numberedFileContent}\n`
+
+ // Mocked functions with correct types
+ const mockedCountFileLines = countFileLines as jest.MockedFunction
+ const mockedReadLines = readLines as jest.MockedFunction
+ const mockedExtractTextFromFile = extractTextFromFile as jest.MockedFunction
+ const mockedParseSourceCodeDefinitionsForFile = parseSourceCodeDefinitionsForFile as jest.MockedFunction<
+ typeof parseSourceCodeDefinitionsForFile
+ >
+
+ const mockedIsBinaryFile = isBinaryFile as jest.MockedFunction
+ const mockedPathResolve = path.resolve as jest.MockedFunction
+
+ const mockCline: any = {}
+ let mockProvider: any
+ let toolResult: ToolResponse | undefined
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+
+ mockedPathResolve.mockReturnValue(absoluteFilePath)
+ mockedIsBinaryFile.mockResolvedValue(false)
+
+ mockInputContent = fileContent
+
+ // Setup the extractTextFromFile mock implementation with the current
+ // mockInputContent.
+ mockedExtractTextFromFile.mockImplementation((_filePath) => {
+ const actual = jest.requireActual("../../../integrations/misc/extract-text")
+ return Promise.resolve(actual.addLineNumbers(mockInputContent))
+ })
+
+ // No need to setup the extractTextFromFile mock implementation here
+ // as it's already defined at the module level.
+
+ mockProvider = {
+ getState: jest.fn(),
+ deref: jest.fn().mockReturnThis(),
+ }
+
+ mockCline.cwd = "/"
+ mockCline.task = "Test"
+ mockCline.providerRef = mockProvider
+ mockCline.rooIgnoreController = {
+ validateAccess: jest.fn().mockReturnValue(true),
+ }
+ mockCline.say = jest.fn().mockResolvedValue(undefined)
+ mockCline.ask = jest.fn().mockResolvedValue(true)
+ mockCline.presentAssistantMessage = jest.fn()
+
+ mockCline.fileContextTracker = {
+ trackFileContext: jest.fn().mockResolvedValue(undefined),
+ }
+
+ mockCline.recordToolUsage = jest.fn().mockReturnValue(undefined)
+ mockCline.recordToolError = jest.fn().mockReturnValue(undefined)
+
+ toolResult = undefined
+ })
+
+ /**
+ * Helper function to execute the read file tool with different maxReadFileLine settings
+ */
+ async function executeReadFileTool(
+ params: Partial = {},
+ options: {
+ maxReadFileLine?: number
+ totalLines?: number
+ skipAddLineNumbersCheck?: boolean // Flag to skip addLineNumbers check
+ } = {},
+ ): Promise {
+ // Configure mocks based on test scenario
+ const maxReadFileLine = options.maxReadFileLine ?? 500
+ const totalLines = options.totalLines ?? 5
+
+ mockProvider.getState.mockResolvedValue({ maxReadFileLine })
+ mockedCountFileLines.mockResolvedValue(totalLines)
+
+ // Reset the spy before each test
+ addLineNumbersSpy.mockClear()
+
+ // Create a tool use object
+ const toolUse: ReadFileToolUse = {
+ type: "tool_use",
+ name: "read_file",
+ params: { path: testFilePath, ...params },
+ partial: false,
+ }
+
+ await readFileTool(
+ mockCline,
+ toolUse,
+ mockCline.ask,
+ jest.fn(),
+ (result: ToolResponse) => {
+ toolResult = result
+ },
+ (_: ToolParamName, content?: string) => content ?? "",
+ )
+
+ // Verify addLineNumbers was called appropriately
+ if (!options.skipAddLineNumbersCheck) {
+ expect(addLineNumbersSpy).toHaveBeenCalled()
+ } else {
+ expect(addLineNumbersSpy).not.toHaveBeenCalled()
+ }
+
+ return toolResult
}
+
+ describe("when maxReadFileLine is negative", () => {
+ it("should read the entire file using extractTextFromFile", async () => {
+ // Setup - use default mockInputContent
+ mockInputContent = fileContent
+
+ // Execute
+ const result = await executeReadFileTool({}, { maxReadFileLine: -1 })
+
+ // Verify
+ expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
+ expect(mockedReadLines).not.toHaveBeenCalled()
+ expect(mockedParseSourceCodeDefinitionsForFile).not.toHaveBeenCalled()
+ expect(result).toBe(expectedFullFileXml)
+ })
+
+ it("should ignore range parameters and read entire file when maxReadFileLine is -1", async () => {
+ // Setup - use default mockInputContent
+ mockInputContent = fileContent
+
+ // Execute with range parameters
+ const result = await executeReadFileTool(
+ {
+ start_line: "2",
+ end_line: "4",
+ },
+ { maxReadFileLine: -1 },
+ )
+
+ // Verify that extractTextFromFile is still used (not readLines)
+ expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
+ expect(mockedReadLines).not.toHaveBeenCalled()
+ expect(mockedParseSourceCodeDefinitionsForFile).not.toHaveBeenCalled()
+ expect(result).toBe(expectedFullFileXml)
+ })
+
+ it("should not show line snippet in approval message when maxReadFileLine is -1", async () => {
+ // This test verifies the line snippet behavior for the approval message
+ // Setup - use default mockInputContent
+ mockInputContent = fileContent
+
+ // Execute - we'll reuse executeReadFileTool to run the tool
+ await executeReadFileTool({}, { maxReadFileLine: -1 })
+
+ // Verify the empty line snippet for full read was passed to the approval message
+ // Look at the parameters passed to the 'ask' method in the approval message
+ const askCall = mockCline.ask.mock.calls[0]
+ const completeMessage = JSON.parse(askCall[1])
+
+ // Verify the reason (lineSnippet) is empty or undefined for full read
+ expect(completeMessage.reason).toBeFalsy()
+ })
+ })
+
+ describe("when maxReadFileLine is 0", () => {
+ it("should return an empty content with source code definitions", async () => {
+ // Setup - for maxReadFileLine = 0, the implementation won't call readLines
+ mockedParseSourceCodeDefinitionsForFile.mockResolvedValue(sourceCodeDef)
+
+ // Execute - skip addLineNumbers check as it's not called for maxReadFileLine=0
+ const result = await executeReadFileTool(
+ {},
+ {
+ maxReadFileLine: 0,
+ totalLines: 5,
+ skipAddLineNumbersCheck: true,
+ },
+ )
+
+ // Verify
+ expect(mockedExtractTextFromFile).not.toHaveBeenCalled()
+ expect(mockedReadLines).not.toHaveBeenCalled() // Per implementation line 141
+ expect(mockedParseSourceCodeDefinitionsForFile).toHaveBeenCalledWith(
+ absoluteFilePath,
+ mockCline.rooIgnoreController,
+ )
+
+ // Verify XML structure
+ expect(result).toContain(`${testFilePath}`)
+ expect(result).toContain("Showing only 0 of 5 total lines")
+ expect(result).toContain("")
+ expect(result).toContain("")
+ expect(result).toContain(sourceCodeDef.trim())
+ expect(result).toContain("")
+ expect(result).not.toContain(" {
+ it("should read only maxReadFileLine lines and add source code definitions", async () => {
+ // Setup
+ const content = "Line 1\nLine 2\nLine 3"
+ mockedReadLines.mockResolvedValue(content)
+ mockedParseSourceCodeDefinitionsForFile.mockResolvedValue(sourceCodeDef)
+
+ // Execute
+ const result = await executeReadFileTool({}, { maxReadFileLine: 3 })
+
+ // Verify - check behavior but not specific implementation details
+ expect(mockedExtractTextFromFile).not.toHaveBeenCalled()
+ expect(mockedReadLines).toHaveBeenCalled()
+ expect(mockedParseSourceCodeDefinitionsForFile).toHaveBeenCalledWith(
+ absoluteFilePath,
+ mockCline.rooIgnoreController,
+ )
+
+ // Verify XML structure
+ expect(result).toContain(`${testFilePath}`)
+ expect(result).toContain('')
+ expect(result).toContain("1 | Line 1")
+ expect(result).toContain("2 | Line 2")
+ expect(result).toContain("3 | Line 3")
+ expect(result).toContain("")
+ expect(result).toContain("Showing only 3 of 5 total lines")
+ expect(result).toContain("")
+ expect(result).toContain("")
+ expect(result).toContain(sourceCodeDef.trim())
+ expect(result).toContain("")
+ expect(result).toContain("")
+ expect(result).toContain(sourceCodeDef.trim())
+ })
+ })
+
+ describe("when maxReadFileLine equals or exceeds file length", () => {
+ it("should use extractTextFromFile when maxReadFileLine > totalLines", async () => {
+ // Setup
+ mockedCountFileLines.mockResolvedValue(5) // File shorter than maxReadFileLine
+ mockInputContent = fileContent
+
+ // Execute
+ const result = await executeReadFileTool({}, { maxReadFileLine: 10, totalLines: 5 })
+
+ // Verify
+ expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
+ expect(result).toBe(expectedFullFileXml)
+ })
+
+ it("should read with extractTextFromFile when file has few lines", async () => {
+ // Setup
+ mockedCountFileLines.mockResolvedValue(3) // File shorter than maxReadFileLine
+ mockInputContent = fileContent
+
+ // Execute
+ const result = await executeReadFileTool({}, { maxReadFileLine: 5, totalLines: 3 })
+
+ // Verify
+ expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
+ expect(mockedReadLines).not.toHaveBeenCalled()
+ // Create a custom expected XML with lines="1-3" since totalLines is 3
+ const expectedXml = `${testFilePath}\n\n${numberedFileContent}\n`
+ expect(result).toBe(expectedXml)
+ })
+ })
+
+ describe("when file is binary", () => {
+ it("should always use extractTextFromFile regardless of maxReadFileLine", async () => {
+ // Setup
+ mockedIsBinaryFile.mockResolvedValue(true)
+ // For binary files, we're using a maxReadFileLine of 3 and totalLines is assumed to be 3
+ mockedCountFileLines.mockResolvedValue(3)
+
+ // For binary files, we need a special mock implementation that doesn't use addLineNumbers
+ // Save the original mock implementation
+ const originalMockImplementation = mockedExtractTextFromFile.getMockImplementation()
+ // Create a special mock implementation that doesn't call addLineNumbers
+ mockedExtractTextFromFile.mockImplementation(() => {
+ return Promise.resolve(numberedFileContent)
+ })
+
+ // Reset the spy to clear any previous calls
+ addLineNumbersSpy.mockClear()
+
+ // Execute - skip addLineNumbers check as we're directly providing the numbered content
+ const result = await executeReadFileTool(
+ {},
+ {
+ maxReadFileLine: 3,
+ totalLines: 3,
+ skipAddLineNumbersCheck: true,
+ },
+ )
+
+ // Restore the original mock implementation after the test
+ mockedExtractTextFromFile.mockImplementation(originalMockImplementation)
+
+ // Verify
+ expect(mockedExtractTextFromFile).toHaveBeenCalledWith(absoluteFilePath)
+ expect(mockedReadLines).not.toHaveBeenCalled()
+ // Create a custom expected XML with lines="1-3" for binary files
+ const expectedXml = `${testFilePath}\n\n${numberedFileContent}\n`
+ expect(result).toBe(expectedXml)
+ })
+ })
+
+ describe("with range parameters", () => {
+ it("should honor start_line and end_line when provided", async () => {
+ // Setup
+ mockedReadLines.mockResolvedValue("Line 2\nLine 3\nLine 4")
+
+ // Execute using executeReadFileTool with range parameters
+ const rangeResult = await executeReadFileTool({
+ start_line: "2",
+ end_line: "4",
+ })
+
+ // Verify
+ expect(mockedReadLines).toHaveBeenCalledWith(absoluteFilePath, 3, 1) // end_line - 1, start_line - 1
+ expect(addLineNumbersSpy).toHaveBeenCalledWith(expect.any(String), 2) // start with proper line numbers
+
+ // Verify XML structure with lines attribute
+ expect(rangeResult).toContain(`${testFilePath}`)
+ expect(rangeResult).toContain(``)
+ expect(rangeResult).toContain("2 | Line 2")
+ expect(rangeResult).toContain("3 | Line 3")
+ expect(rangeResult).toContain("4 | Line 4")
+ expect(rangeResult).toContain("")
+ })
+ })
})
describe("read_file tool XML output structure", () => {
@@ -85,27 +424,21 @@ describe("read_file tool XML output structure", () => {
// Mock instances
const mockCline: any = {}
let mockProvider: any
- let toolResult: string | undefined
+ let toolResult: ToolResponse | undefined
beforeEach(() => {
jest.clearAllMocks()
- // Setup path resolution
mockedPathResolve.mockReturnValue(absoluteFilePath)
-
- // Setup mocks for file operations
mockedIsBinaryFile.mockResolvedValue(false)
- // Set the default content for the mock
mockInputContent = fileContent
- // Setup mock provider
mockProvider = {
getState: jest.fn().mockResolvedValue({ maxReadFileLine: 500 }),
deref: jest.fn().mockReturnThis(),
}
- // Setup Cline instance with mock methods
mockCline.cwd = "/"
mockCline.task = "Test"
mockCline.providerRef = mockProvider
@@ -116,14 +449,14 @@ describe("read_file tool XML output structure", () => {
mockCline.ask = jest.fn().mockResolvedValue(true)
mockCline.presentAssistantMessage = jest.fn()
mockCline.sayAndCreateMissingParamError = jest.fn().mockResolvedValue("Missing required parameter")
- // Add mock for getFileContextTracker method
- mockCline.getFileContextTracker = jest.fn().mockReturnValue({
+
+ mockCline.fileContextTracker = {
trackFileContext: jest.fn().mockResolvedValue(undefined),
- })
+ }
+
mockCline.recordToolUsage = jest.fn().mockReturnValue(undefined)
mockCline.recordToolError = jest.fn().mockReturnValue(undefined)
- // Reset tool result
toolResult = undefined
})
@@ -139,7 +472,7 @@ describe("read_file tool XML output structure", () => {
validateAccess?: boolean
skipAddLineNumbersCheck?: boolean // Flag to skip addLineNumbers check
} = {},
- ): Promise {
+ ): Promise {
// Configure mocks based on test scenario
const totalLines = options.totalLines ?? 5
const maxReadFileLine = options.maxReadFileLine ?? 500
@@ -162,9 +495,6 @@ describe("read_file tool XML output structure", () => {
partial: false,
}
- // Import the tool implementation dynamically to avoid hoisting issues
- const { readFileTool } = require("../tools/readFileTool")
-
// Reset the spy's call history before each test
addLineNumbersSpy.mockClear()
@@ -174,10 +504,10 @@ describe("read_file tool XML output structure", () => {
toolUse,
mockCline.ask,
jest.fn(),
- (result: string) => {
+ (result: ToolResponse) => {
toolResult = result
},
- (param: string, value: string) => value,
+ (param: ToolParamName, content?: string) => content ?? "",
)
// Verify addLineNumbers was called (unless explicitly skipped)
if (!options.skipAddLineNumbersCheck) {
@@ -410,7 +740,9 @@ describe("read_file tool XML output structure", () => {
// Should contain all the requested lines, not just maxReadFileLine lines
expect(result).toBeDefined()
- if (result) {
+ expect(typeof result).toBe("string")
+
+ if (typeof result === "string") {
expect(result.split("\n").length).toBeGreaterThan(maxReadFileLine)
}
})
@@ -507,19 +839,16 @@ describe("read_file tool XML output structure", () => {
partial: false,
}
- // Import the tool implementation dynamically
- const { readFileTool } = require("../tools/readFileTool")
-
// Execute the tool
await readFileTool(
mockCline,
toolUse,
mockCline.ask,
jest.fn(),
- (result: string) => {
+ (result: ToolResponse) => {
toolResult = result
},
- (param: string, value: string) => value,
+ (param: ToolParamName, content?: string) => content ?? "",
)
// Verify
@@ -565,6 +894,7 @@ describe("read_file tool XML output structure", () => {
// Execute
const result = await executeReadFileTool({}, { maxReadFileLine, totalLines })
+ console.log(result)
// Verify
// Empty files should include a content tag and notice
diff --git a/src/core/__tests__/mode-validator.test.ts b/src/core/tools/__tests__/validateToolUse.test.ts
similarity index 95%
rename from src/core/__tests__/mode-validator.test.ts
rename to src/core/tools/__tests__/validateToolUse.test.ts
index 1111f24b9f2..da2550b4d6c 100644
--- a/src/core/__tests__/mode-validator.test.ts
+++ b/src/core/tools/__tests__/validateToolUse.test.ts
@@ -1,8 +1,8 @@
-// npx jest src/core/__tests__/mode-validator.test.ts
+// npx jest src/core/tools/__tests__/validateToolUse.test.ts
-import { isToolAllowedForMode, modes, ModeConfig } from "../../shared/modes"
-import { TOOL_GROUPS } from "../../shared/tools"
-import { validateToolUse } from "../mode-validator"
+import { isToolAllowedForMode, modes, ModeConfig } from "../../../shared/modes"
+import { TOOL_GROUPS } from "../../../shared/tools"
+import { validateToolUse } from "../validateToolUse"
const [codeMode, architectMode, askMode] = modes.map((mode) => mode.slug)
diff --git a/src/core/tools/accessMcpResourceTool.ts b/src/core/tools/accessMcpResourceTool.ts
index 3161a3f8d5c..22b1aba9095 100644
--- a/src/core/tools/accessMcpResourceTool.ts
+++ b/src/core/tools/accessMcpResourceTool.ts
@@ -1,10 +1,10 @@
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
import { ToolUse, RemoveClosingTag, AskApproval, HandleError, PushToolResult } from "../../shared/tools"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { formatResponse } from "../prompts/responses"
export async function accessMcpResourceTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/applyDiffTool.ts b/src/core/tools/applyDiffTool.ts
index 590040f2bab..9fbe1e1de1a 100644
--- a/src/core/tools/applyDiffTool.ts
+++ b/src/core/tools/applyDiffTool.ts
@@ -3,7 +3,7 @@ import fs from "fs/promises"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { getReadablePath } from "../../utils/path"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, RemoveClosingTag } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { AskApproval, HandleError, PushToolResult } from "../../shared/tools"
@@ -14,7 +14,7 @@ import { telemetryService } from "../../services/telemetry/TelemetryService"
import { unescapeHtmlEntities } from "../../utils/text-normalization"
export async function applyDiffTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -31,6 +31,7 @@ export async function applyDiffTool(
const sharedMessageProps: ClineSayTool = {
tool: "appliedDiff",
path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)),
+ diff: diffContent,
}
try {
@@ -46,8 +47,10 @@ export async function applyDiffTool(
return
}
- const partialMessage = JSON.stringify(sharedMessageProps)
- await cline.ask("tool", partialMessage, block.partial, toolProgressStatus).catch(() => {})
+ await cline
+ .ask("tool", JSON.stringify(sharedMessageProps), block.partial, toolProgressStatus)
+ .catch(() => {})
+
return
} else {
if (!relPath) {
@@ -164,7 +167,7 @@ export async function applyDiffTool(
// Track file edit operation
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "roo_edited" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "roo_edited" as RecordSource)
}
// Used to determine if we should wait for busy terminal to update before sending api request
diff --git a/src/core/tools/askFollowupQuestionTool.ts b/src/core/tools/askFollowupQuestionTool.ts
index 46ce2e4e072..d5adf6d4cd7 100644
--- a/src/core/tools/askFollowupQuestionTool.ts
+++ b/src/core/tools/askFollowupQuestionTool.ts
@@ -1,10 +1,10 @@
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { parseXml } from "../../utils/xml"
export async function askFollowupQuestionTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts
index b65ce34b19a..a5e469c77fe 100644
--- a/src/core/tools/attemptCompletionTool.ts
+++ b/src/core/tools/attemptCompletionTool.ts
@@ -1,6 +1,6 @@
import Anthropic from "@anthropic-ai/sdk"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import {
ToolResponse,
ToolUse,
@@ -16,7 +16,7 @@ import { telemetryService } from "../../services/telemetry/TelemetryService"
import { type ExecuteCommandOptions, executeCommand } from "./executeCommandTool"
export async function attemptCompletionTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -46,7 +46,7 @@ export async function attemptCompletionTool(
await cline.say("completion_result", removeClosingTag("result", result), undefined, false)
telemetryService.captureTaskCompleted(cline.taskId)
- cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.getToolUsage())
+ cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
await cline.ask("command", removeClosingTag("command", command), block.partial).catch(() => {})
}
@@ -72,17 +72,17 @@ export async function attemptCompletionTool(
// Haven't sent a command message yet so first send completion_result then command.
await cline.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(cline.taskId)
- cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.getToolUsage())
+ cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
}
// Complete command message.
- const executionId = Date.now().toString()
- const didApprove = await askApproval("command", command, { id: executionId })
+ const didApprove = await askApproval("command", command)
if (!didApprove) {
return
}
+ const executionId = cline.lastMessageTs?.toString() ?? Date.now().toString()
const options: ExecuteCommandOptions = { executionId, command }
const [userRejected, execCommandResult] = await executeCommand(cline, options)
@@ -97,7 +97,7 @@ export async function attemptCompletionTool(
} else {
await cline.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(cline.taskId)
- cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.getToolUsage())
+ cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
}
if (cline.parentTask) {
@@ -108,7 +108,7 @@ export async function attemptCompletionTool(
}
// tell the provider to remove the current subtask and resume the previous task in the stack
- await cline.providerRef.deref()?.finishSubTask(lastMessage?.text ?? "")
+ await cline.providerRef.deref()?.finishSubTask(result)
return
}
diff --git a/src/core/tools/browserActionTool.ts b/src/core/tools/browserActionTool.ts
index 093a89a7d5d..13cb9b0ec26 100644
--- a/src/core/tools/browserActionTool.ts
+++ b/src/core/tools/browserActionTool.ts
@@ -1,4 +1,4 @@
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import {
BrowserAction,
@@ -9,7 +9,7 @@ import {
import { formatResponse } from "../prompts/responses"
export async function browserActionTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/executeCommandTool.ts b/src/core/tools/executeCommandTool.ts
index 4bd303904f7..6f5fc714a88 100644
--- a/src/core/tools/executeCommandTool.ts
+++ b/src/core/tools/executeCommandTool.ts
@@ -3,7 +3,7 @@ import * as path from "path"
import delay from "delay"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { CommandExecutionStatus } from "../../schemas"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolResponse } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
@@ -16,7 +16,7 @@ import { Terminal } from "../../integrations/terminal/Terminal"
class ShellIntegrationError extends Error {}
export async function executeCommandTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -48,14 +48,14 @@ export async function executeCommandTool(
cline.consecutiveMistakeCount = 0
- const executionId = Date.now().toString()
command = unescapeHtmlEntities(command) // Unescape HTML entities.
- const didApprove = await askApproval("command", command, { id: executionId })
+ const didApprove = await askApproval("command", command)
if (!didApprove) {
return
}
+ const executionId = cline.lastMessageTs?.toString() ?? Date.now().toString()
const clineProvider = await cline.providerRef.deref()
const clineProviderState = await clineProvider?.getState()
const { terminalOutputLineLimit = 500, terminalShellIntegrationDisabled = false } = clineProviderState ?? {}
@@ -114,7 +114,7 @@ export type ExecuteCommandOptions = {
}
export async function executeCommand(
- cline: Cline,
+ cline: Task,
{
executionId,
command,
@@ -149,9 +149,12 @@ export async function executeCommand(
const terminalProvider = terminalShellIntegrationDisabled ? "execa" : "vscode"
const clineProvider = await cline.providerRef.deref()
+ let accumulatedOutput = ""
const callbacks: RooTerminalCallbacks = {
- onLine: async (output: string, process: RooTerminalProcess) => {
- const status: CommandExecutionStatus = { executionId, status: "output", output }
+ onLine: async (lines: string, process: RooTerminalProcess) => {
+ accumulatedOutput += lines
+ const compressedOutput = Terminal.compressTerminalOutput(accumulatedOutput, terminalOutputLineLimit)
+ const status: CommandExecutionStatus = { executionId, status: "output", output: compressedOutput }
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
if (runInBackground) {
@@ -195,7 +198,7 @@ export async function executeCommand(
const terminal = await TerminalRegistry.getOrCreateTerminal(workingDir, !!customCwd, cline.taskId, terminalProvider)
if (terminal instanceof Terminal) {
- terminal.terminal.show()
+ terminal.terminal.show(true)
// Update the working directory in case the terminal we asked for has
// a different working directory so that the model will know where the
diff --git a/src/core/tools/fetchInstructionsTool.ts b/src/core/tools/fetchInstructionsTool.ts
index d72c19ce907..5325f98fbf4 100644
--- a/src/core/tools/fetchInstructionsTool.ts
+++ b/src/core/tools/fetchInstructionsTool.ts
@@ -1,11 +1,11 @@
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { fetchInstructions } from "../prompts/instructions/instructions"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { formatResponse } from "../prompts/responses"
import { ToolUse, AskApproval, HandleError, PushToolResult } from "../../shared/tools"
export async function fetchInstructionsTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/insertContentTool.ts b/src/core/tools/insertContentTool.ts
index 8e6c5fc89ea..bcb217326a2 100644
--- a/src/core/tools/insertContentTool.ts
+++ b/src/core/tools/insertContentTool.ts
@@ -3,7 +3,7 @@ import fs from "fs/promises"
import path from "path"
import { getReadablePath } from "../../utils/path"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { ClineSayTool } from "../../shared/ExtensionMessage"
@@ -12,7 +12,7 @@ import { fileExistsAtPath } from "../../utils/fs"
import { insertGroups } from "../diff/insert-groups"
export async function insertContentTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -26,13 +26,13 @@ export async function insertContentTool(
const sharedMessageProps: ClineSayTool = {
tool: "insertContent",
path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)),
+ diff: content,
lineNumber: line ? parseInt(line, 10) : undefined,
}
try {
if (block.partial) {
- const partialMessage = JSON.stringify(sharedMessageProps)
- await cline.ask("tool", partialMessage, block.partial).catch(() => {})
+ await cline.ask("tool", JSON.stringify(sharedMessageProps), block.partial).catch(() => {})
return
}
@@ -132,7 +132,7 @@ export async function insertContentTool(
// Track file edit operation
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "roo_edited" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "roo_edited" as RecordSource)
}
cline.didEditFile = true
@@ -145,14 +145,15 @@ export async function insertContentTool(
return
}
- const userFeedbackDiff = JSON.stringify({
- tool: "insertContent",
- path: getReadablePath(cline.cwd, relPath),
- lineNumber: lineNumber,
- diff: userEdits,
- } satisfies ClineSayTool)
-
- await cline.say("user_feedback_diff", userFeedbackDiff)
+ await cline.say(
+ "user_feedback_diff",
+ JSON.stringify({
+ tool: "insertContent",
+ path: getReadablePath(cline.cwd, relPath),
+ diff: userEdits,
+ lineNumber: lineNumber,
+ } satisfies ClineSayTool),
+ )
pushToolResult(
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
diff --git a/src/core/tools/listCodeDefinitionNamesTool.ts b/src/core/tools/listCodeDefinitionNamesTool.ts
index 5f1e5ad8837..f0cdde01ebc 100644
--- a/src/core/tools/listCodeDefinitionNamesTool.ts
+++ b/src/core/tools/listCodeDefinitionNamesTool.ts
@@ -2,14 +2,14 @@ import path from "path"
import fs from "fs/promises"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { getReadablePath } from "../../utils/path"
import { parseSourceCodeForDefinitionsTopLevel, parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
export async function listCodeDefinitionNamesTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -64,7 +64,7 @@ export async function listCodeDefinitionNamesTool(
}
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "read_tool" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource)
}
pushToolResult(result)
diff --git a/src/core/tools/listFilesTool.ts b/src/core/tools/listFilesTool.ts
index 7c785526e8b..6d40de711c4 100644
--- a/src/core/tools/listFilesTool.ts
+++ b/src/core/tools/listFilesTool.ts
@@ -1,6 +1,6 @@
import * as path from "path"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { formatResponse } from "../prompts/responses"
import { listFiles } from "../../services/glob/list-files"
@@ -23,7 +23,7 @@ import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } f
*/
export async function listFilesTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts
index 7b6030eee35..e589e01e564 100644
--- a/src/core/tools/newTaskTool.ts
+++ b/src/core/tools/newTaskTool.ts
@@ -1,12 +1,12 @@
import delay from "delay"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
import { formatResponse } from "../prompts/responses"
export async function newTaskTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/readFileTool.ts b/src/core/tools/readFileTool.ts
index e982420bf15..fade9b2d11c 100644
--- a/src/core/tools/readFileTool.ts
+++ b/src/core/tools/readFileTool.ts
@@ -1,7 +1,7 @@
import path from "path"
import { isBinaryFile } from "isbinaryfile"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { formatResponse } from "../prompts/responses"
import { t } from "../../i18n"
@@ -15,7 +15,7 @@ import { extractTextFromFile, addLineNumbers } from "../../integrations/misc/ext
import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
export async function readFileTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -164,7 +164,21 @@ export async function readFileTool(
const res = await Promise.all([
maxReadFileLine > 0 ? readLines(absolutePath, maxReadFileLine - 1, 0) : "",
- parseSourceCodeDefinitionsForFile(absolutePath, cline.rooIgnoreController),
+ (async () => {
+ try {
+ return await parseSourceCodeDefinitionsForFile(absolutePath, cline.rooIgnoreController)
+ } catch (error) {
+ if (error instanceof Error && error.message.startsWith("Unsupported language:")) {
+ console.warn(`[read_file] Warning: ${error.message}`)
+ return undefined
+ } else {
+ console.error(
+ `[read_file] Unhandled error: ${error instanceof Error ? error.message : String(error)}`,
+ )
+ return undefined
+ }
+ }
+ })(),
])
content = res[0].length > 0 ? addLineNumbers(res[0]) : ""
@@ -231,7 +245,7 @@ export async function readFileTool(
// Track file read operation
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "read_tool" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "read_tool" as RecordSource)
}
// Format the result into the required XML structure
diff --git a/src/core/tools/searchAndReplaceTool.ts b/src/core/tools/searchAndReplaceTool.ts
index 7a503b5f1ee..417e2046df8 100644
--- a/src/core/tools/searchAndReplaceTool.ts
+++ b/src/core/tools/searchAndReplaceTool.ts
@@ -4,7 +4,7 @@ import fs from "fs/promises"
import delay from "delay"
// Internal imports
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolUse } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { ClineSayTool } from "../../shared/ExtensionMessage"
@@ -21,7 +21,7 @@ import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
* Validates required parameters for search and replace operation
*/
async function validateParams(
- cline: Cline,
+ cline: Task,
relPath: string | undefined,
search: string | undefined,
replace: string | undefined,
@@ -61,7 +61,7 @@ async function validateParams(
* @param removeClosingTag - Function to remove closing tags
*/
export async function searchAndReplaceTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -215,7 +215,7 @@ export async function searchAndReplaceTool(
// Track file edit operation
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "roo_edited" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "roo_edited" as RecordSource)
}
cline.didEditFile = true
@@ -226,13 +226,14 @@ export async function searchAndReplaceTool(
return
}
- const userFeedbackDiff = JSON.stringify({
- tool: "appliedDiff",
- path: getReadablePath(cline.cwd, relPath),
- diff: userEdits,
- } satisfies ClineSayTool)
-
- await cline.say("user_feedback_diff", userFeedbackDiff)
+ await cline.say(
+ "user_feedback_diff",
+ JSON.stringify({
+ tool: "appliedDiff",
+ path: getReadablePath(cline.cwd, relPath),
+ diff: userEdits,
+ } satisfies ClineSayTool),
+ )
// Format and send response with user's updates
const resultMessage = [
diff --git a/src/core/tools/searchFilesTool.ts b/src/core/tools/searchFilesTool.ts
index 33a8b8b3cc3..6528f20d541 100644
--- a/src/core/tools/searchFilesTool.ts
+++ b/src/core/tools/searchFilesTool.ts
@@ -1,13 +1,13 @@
import path from "path"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { getReadablePath } from "../../utils/path"
import { regexSearchFiles } from "../../services/ripgrep"
export async function searchFilesTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/switchModeTool.ts b/src/core/tools/switchModeTool.ts
index 28f719ff2d6..8ce906b41fc 100644
--- a/src/core/tools/switchModeTool.ts
+++ b/src/core/tools/switchModeTool.ts
@@ -1,12 +1,12 @@
import delay from "delay"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
export async function switchModeTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/tools/useMcpToolTool.ts b/src/core/tools/useMcpToolTool.ts
index 882f214a6f9..b8339bc8d0e 100644
--- a/src/core/tools/useMcpToolTool.ts
+++ b/src/core/tools/useMcpToolTool.ts
@@ -1,10 +1,10 @@
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
export async function useMcpToolTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
diff --git a/src/core/mode-validator.ts b/src/core/tools/validateToolUse.ts
similarity index 75%
rename from src/core/mode-validator.ts
rename to src/core/tools/validateToolUse.ts
index 4c5e8fbf7fb..0b1623f0575 100644
--- a/src/core/mode-validator.ts
+++ b/src/core/tools/validateToolUse.ts
@@ -1,5 +1,5 @@
-import { ToolName } from "../schemas"
-import { Mode, isToolAllowedForMode, ModeConfig } from "../shared/modes"
+import { ToolName } from "../../schemas"
+import { Mode, isToolAllowedForMode, ModeConfig } from "../../shared/modes"
export function validateToolUse(
toolName: ToolName,
diff --git a/src/core/tools/writeToFileTool.ts b/src/core/tools/writeToFileTool.ts
index a23aea97145..2c37f95b74e 100644
--- a/src/core/tools/writeToFileTool.ts
+++ b/src/core/tools/writeToFileTool.ts
@@ -2,7 +2,7 @@ import path from "path"
import delay from "delay"
import * as vscode from "vscode"
-import { Cline } from "../Cline"
+import { Task } from "../task/Task"
import { ClineSayTool } from "../../shared/ExtensionMessage"
import { formatResponse } from "../prompts/responses"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
@@ -15,7 +15,7 @@ import { detectCodeOmission } from "../../integrations/editor/detect-omission"
import { unescapeHtmlEntities } from "../../utils/text-normalization"
export async function writeToFileTool(
- cline: Cline,
+ cline: Task,
block: ToolUse,
askApproval: AskApproval,
handleError: HandleError,
@@ -72,6 +72,7 @@ export async function writeToFileTool(
const sharedMessageProps: ClineSayTool = {
tool: fileExists ? "editedExistingFile" : "newFileCreated",
path: getReadablePath(cline.cwd, removeClosingTag("path", relPath)),
+ content: newContent,
isOutsideWorkspace,
}
@@ -211,7 +212,7 @@ export async function writeToFileTool(
// Track file edit operation
if (relPath) {
- await cline.getFileContextTracker().trackFileContext(relPath, "roo_edited" as RecordSource)
+ await cline.fileContextTracker.trackFileContext(relPath, "roo_edited" as RecordSource)
}
cline.didEditFile = true // used to determine if we should wait for busy terminal to update before sending api request
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 4bd50398fdc..557c1cab814 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -9,16 +9,10 @@ import axios from "axios"
import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
-import { CreatorModeConfig, GlobalState, ProviderSettings, RooCodeSettings } from "../../schemas"
+import type { GlobalState, ProviderName, ProviderSettings, RooCodeSettings, ProviderSettingsEntry, CreatorModeConfig } from "../../schemas"
import { t } from "../../i18n"
import { setPanel } from "../../activate/registerCommands"
-import {
- ApiConfiguration,
- ApiProvider,
- requestyDefaultModelId,
- openRouterDefaultModelId,
- glamaDefaultModelId,
-} from "../../shared/api"
+import { requestyDefaultModelId, openRouterDefaultModelId, glamaDefaultModelId } from "../../shared/api"
import { findLast } from "../../shared/array"
import { supportPrompt } from "../../shared/support-prompt"
import { GlobalFileNames } from "../../shared/globalFileNames"
@@ -41,8 +35,8 @@ import { ContextProxy } from "../config/ContextProxy"
import { ProviderSettingsManager } from "../config/ProviderSettingsManager"
import { CustomModesManager } from "../config/CustomModesManager"
import { buildApiHandler } from "../../api"
-import { CodeActionName } from "../CodeActionProvider"
-import { Cline, ClineOptions } from "../Cline"
+import { CodeActionName } from "../../activate/CodeActionProvider"
+import { Task, TaskOptions } from "../task/Task"
import { getNonce } from "./getNonce"
import { getUri } from "./getUri"
import { getSystemPromptFilePath } from "../prompts/sections/custom-system-prompt"
@@ -59,7 +53,7 @@ import { PearAIAgentModelsConfig } from "../../api/providers/pearai/pearai"
*/
export type ClineProviderEvents = {
- clineCreated: [cline: Cline]
+ clineCreated: [cline: Task]
}
export class ClineProvider extends EventEmitter implements vscode.WebviewViewProvider {
@@ -68,7 +62,7 @@ export class ClineProvider extends EventEmitter implements
private static activeInstances: Set = new Set()
private disposables: vscode.Disposable[] = []
private view?: vscode.WebviewView | vscode.WebviewPanel
- private clineStack: Cline[] = []
+ private clineStack: Task[] = []
private _workspaceTracker?: WorkspaceTracker // workSpaceTracker read-only for access outside this class
public get workspaceTracker(): WorkspaceTracker | undefined {
return this._workspaceTracker
@@ -77,7 +71,7 @@ export class ClineProvider extends EventEmitter implements
public isViewLaunched = false
public settingsImportedAt?: number
- public readonly latestAnnouncementId = "apr-30-2025-3-15" // Update for v3.15.0 announcement
+ public readonly latestAnnouncementId = "may-14-2025-3-17" // Update for v3.17.0 announcement
public readonly providerSettingsManager: ProviderSettingsManager
public readonly customModesManager: CustomModesManager
@@ -129,7 +123,7 @@ export class ClineProvider extends EventEmitter implements
// Adds a new Cline instance to clineStack, marking the start of a new task.
// The instance is pushed to the top of the stack (LIFO order).
// When the task is completed, the top instance is removed, reactivating the previous task.
- async addClineToStack(cline: Cline) {
+ async addClineToStack(cline: Task) {
console.log(`[subtasks] adding task ${cline.taskId}.${cline.instanceId} to stack`)
// Add this cline instance into the stack that represents the order of all the called tasks.
@@ -174,7 +168,7 @@ export class ClineProvider extends EventEmitter implements
// returns the current cline object in the stack (the top one)
// if the stack is empty, returns undefined
- getCurrentCline(): Cline | undefined {
+ getCurrentCline(): Task | undefined {
if (this.clineStack.length === 0) {
return undefined
}
@@ -190,15 +184,15 @@ export class ClineProvider extends EventEmitter implements
return this.clineStack.map((cline) => cline.taskId)
}
- // remove the current task/cline instance (at the top of the stack), ao this task is finished
+ // remove the current task/cline instance (at the top of the stack), so this task is finished
// and resume the previous task/cline instance (if it exists)
// this is used when a sub task is finished and the parent task needs to be resumed
async finishSubTask(lastMessage: string) {
console.log(`[subtasks] finishing subtask ${lastMessage}`)
// remove the last cline instance from the stack (this is the finished sub task)
await this.removeClineFromStack()
- // resume the last cline instance in the stack (if it exists - this is the 'parnt' calling task)
- this.getCurrentCline()?.resumePausedTask(lastMessage)
+ // resume the last cline instance in the stack (if it exists - this is the 'parent' calling task)
+ await this.getCurrentCline()?.resumePausedTask(lastMessage)
}
/*
@@ -265,7 +259,7 @@ export class ClineProvider extends EventEmitter implements
return false
}
- // check if there is a cline instance in the stack (if this provider has an active task)
+ // Check if there is a cline instance in the stack (if this provider has an active task)
if (visibleProvider.getCurrentCline()) {
return true
}
@@ -460,7 +454,7 @@ export class ClineProvider extends EventEmitter implements
return data
}
- public async initClineWithSubTask(parent: Cline, task?: string, images?: string[]) {
+ public async initClineWithSubTask(parent: Task, task?: string, images?: string[]) {
return this.initClineWithTask(task, images, parent)
}
@@ -470,28 +464,20 @@ export class ClineProvider extends EventEmitter implements
public async initClineWithTask(
task?: string,
images?: string[],
- parentTask?: Cline,
+ parentTask?: Task,
options: Partial<
Pick<
- ClineOptions,
- | "customInstructions"
- | "enableDiff"
- | "enableCheckpoints"
- | "fuzzyMatchThreshold"
- | "consecutiveMistakeLimit"
- | "experiments"
+ TaskOptions,
+ "enableDiff" | "enableCheckpoints" | "fuzzyMatchThreshold" | "consecutiveMistakeLimit" | "experiments"
>
> = {},
creatorModeConfig?: CreatorModeConfig,
) {
const {
apiConfiguration,
- customModePrompts,
diffEnabled: enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
- mode,
- customInstructions: globalInstructions,
experiments,
} = await this.getState()
@@ -509,7 +495,7 @@ export class ClineProvider extends EventEmitter implements
const pearaiAgentModels = await this.getPearAIAgentModels()
- const cline = new Cline({
+ const cline = new Task({
provider: this,
apiConfiguration: {
...apiConfiguration,
@@ -518,6 +504,8 @@ export class ClineProvider extends EventEmitter implements
},
creatorModeConfig,
customInstructions: effectiveInstructions,
+ provider: this,
+ apiConfiguration,
enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
@@ -541,19 +529,16 @@ export class ClineProvider extends EventEmitter implements
}
public async initClineWithHistoryItem(
- historyItem: HistoryItem & { rootTask?: Cline; parentTask?: Cline },
+ historyItem: HistoryItem & { rootTask?: Task; parentTask?: Task },
options?: { creatorModeConfig?: CreatorModeConfig }
) {
await this.removeClineFromStack()
const {
apiConfiguration,
- customModePrompts,
diffEnabled: enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
- mode,
- customInstructions: globalInstructions,
experiments,
} = await this.getState()
@@ -561,7 +546,7 @@ export class ClineProvider extends EventEmitter implements
const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n")
const pearaiAgentModels = await this.getPearAIAgentModels()
- const cline = new Cline({
+ const cline = new Task({
provider: this,
apiConfiguration: { ...apiConfiguration, pearaiAgentModels: pearaiAgentModels },
customInstructions: effectiveInstructions,
@@ -803,7 +788,6 @@ export class ClineProvider extends EventEmitter implements
* @param newMode The mode to switch to
*/
public async handleModeSwitch(newMode: Mode) {
- // Capture mode switch telemetry event
const cline = this.getCurrentCline()
if (cline) {
@@ -820,33 +804,37 @@ export class ClineProvider extends EventEmitter implements
// Update listApiConfigMeta first to ensure UI has latest data
await this.updateGlobalState("listApiConfigMeta", listApiConfig)
- // If this mode has a saved config, use it
+ // If this mode has a saved config, use it.
if (savedConfigId) {
- const config = listApiConfig?.find((c) => c.id === savedConfigId)
-
- if (config?.name) {
- let apiConfig = await this.providerSettingsManager.loadConfig(config.name)
-
- // Switch to pearai-model-creator model if we are in Creator Mode
- if (newMode == PEARAI_CREATOR_MODE_WEBAPP_MANAGER_SLUG || newMode.includes('creator')) {
- apiConfig = {
- ...apiConfig,
- apiProvider: "pearai",
- apiModelId: "pearai-model-creator",
- }
- }
-
- await Promise.all([
- this.updateGlobalState("currentApiConfigName", config.name),
- this.updateApiConfiguration(apiConfig),
- ])
+ const profile = listApiConfig.find(({ id }) => id === savedConfigId)
+
+ // TODO: Nang to look at
+ // if (config?.name) {
+ // let apiConfig = await this.providerSettingsManager.loadConfig(config.name)
+
+ // // Switch to pearai-model-creator model if we are in Creator Mode
+ // if (newMode == PEARAI_CREATOR_MODE_WEBAPP_MANAGER_SLUG || newMode.includes('creator')) {
+ // apiConfig = {
+ // ...apiConfig,
+ // apiProvider: "pearai",
+ // apiModelId: "pearai-model-creator",
+ // }
+ // }
+
+ // await Promise.all([
+ // this.updateGlobalState("currentApiConfigName", config.name),
+ // this.updateApiConfiguration(apiConfig),
+ // ])
+ // }
+ if (profile?.name) {
+ await this.activateProviderProfile({ name: profile.name })
}
} else {
- // If no saved config for this mode, save current config as default
+ // If no saved config for this mode, save current config as default.
const currentApiConfigName = this.getGlobalState("currentApiConfigName")
if (currentApiConfigName) {
- const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
+ const config = listApiConfig.find((c) => c.name === currentApiConfigName)
if (config?.id) {
await this.providerSettingsManager.setModeConfig(newMode, config.id)
@@ -867,25 +855,133 @@ export class ClineProvider extends EventEmitter implements
...providerSettings,
creatorModeConfig: currentCline?.creatorModeConfig,
}
+ }
+ // Provider Profile Management
- if (mode) {
- const currentApiConfigName = this.getGlobalState("currentApiConfigName")
- const listApiConfig = await this.providerSettingsManager.listConfig()
- const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
+ getProviderProfileEntries(): ProviderSettingsEntry[] {
+ return this.contextProxy.getValues().listApiConfigMeta || []
+ }
+
+ getProviderProfileEntry(name: string): ProviderSettingsEntry | undefined {
+ return this.getProviderProfileEntries().find((profile) => profile.name === name)
+ }
+
+ public hasProviderProfileEntry(name: string): boolean {
+ return !!this.getProviderProfileEntry(name)
+ }
+
+ async upsertProviderProfile(
+ name: string,
+ providerSettings: ProviderSettings,
+ activate: boolean = true,
+ ): Promise {
+ try {
+ // TODO: Do we need to be calling `activateProfile`? It's not
+ // clear to me what the source of truth should be; in some cases
+ // we rely on the `ContextProxy`'s data store and in other cases
+ // we rely on the `ProviderSettingsManager`'s data store. It might
+ // be simpler to unify these two.
+ const id = await this.providerSettingsManager.saveConfig(name, providerSettings)
+
+ if (activate) {
+ const { mode } = await this.getState()
+
+ // These promises do the following:
+ // 1. Adds or updates the list of provider profiles.
+ // 2. Sets the current provider profile.
+ // 3. Sets the current mode's provider profile.
+ // 4. Copies the provider settings to the context.
+ //
+ // Note: 1, 2, and 4 can be done in one `ContextProxy` call:
+ // this.contextProxy.setValues({ ...providerSettings, listApiConfigMeta: ..., currentApiConfigName: ... })
+ // We should probably switch to that and verify that it works.
+ // I left the original implementation in just to be safe.
+ await Promise.all([
+ this.updateGlobalState("listApiConfigMeta", await this.providerSettingsManager.listConfig()),
+ this.updateGlobalState("currentApiConfigName", name),
+ this.providerSettingsManager.setModeConfig(mode, id),
+ this.contextProxy.setProviderSettings(providerSettings),
+ ])
- if (config?.id) {
- await this.providerSettingsManager.setModeConfig(mode, config.id)
+ // Change the provider for the current task.
+ // TODO: We should rename `buildApiHandler` for clarity (e.g. `getProviderClient`).
+ const task = this.getCurrentCline()
+
+ if (task) {
+ task.api = buildApiHandler(providerSettings)
+ }
+ } else {
+ await this.updateGlobalState("listApiConfigMeta", await this.providerSettingsManager.listConfig())
}
+
+ // await this.contextProxy.setProviderSettings(updatedConfig)
+
+ // if (this.getCurrentCline()) {
+ // this.getCurrentCline()!.api = buildApiHandler(updatedConfig)
+ await this.postStateToWebview()
+ return id
+ } catch (error) {
+ this.log(
+ `Error create new api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
+ )
+
+ vscode.window.showErrorMessage(t("common:errors.create_api_config"))
+ return undefined
}
+ }
- await this.contextProxy.setProviderSettings(updatedConfig)
+ async deleteProviderProfile(profileToDelete: ProviderSettingsEntry) {
+ const globalSettings = this.contextProxy.getValues()
+ let profileToActivate: string | undefined = globalSettings.currentApiConfigName
- if (this.getCurrentCline()) {
- this.getCurrentCline()!.api = buildApiHandler(updatedConfig)
+ if (profileToDelete.name === profileToActivate) {
+ profileToActivate = this.getProviderProfileEntries().find(({ name }) => name !== profileToDelete.name)?.name
}
+
+ if (!profileToActivate) {
+ throw new Error("You cannot delete the last profile")
+ }
+
+ const entries = this.getProviderProfileEntries().filter(({ name }) => name !== profileToDelete.name)
+
+ await this.contextProxy.setValues({
+ ...globalSettings,
+ currentApiConfigName: profileToActivate,
+ listApiConfigMeta: entries,
+ })
+
+ await this.postStateToWebview()
+ }
+
+ async activateProviderProfile(args: { name: string } | { id: string }) {
+ const { name, id, ...providerSettings } = await this.providerSettingsManager.activateProfile(args)
+
+ // See `upsertProviderProfile` for a description of what this is doing.
+ await Promise.all([
+ this.contextProxy.setValue("listApiConfigMeta", await this.providerSettingsManager.listConfig()),
+ this.contextProxy.setValue("currentApiConfigName", name),
+ this.contextProxy.setProviderSettings(providerSettings),
+ ])
+
+ const { mode } = await this.getState()
+
+ if (id) {
+ await this.providerSettingsManager.setModeConfig(mode, id)
+ }
+
+ // Change the provider for the current task.
+ const task = this.getCurrentCline()
+
+ if (task) {
+ task.api = buildApiHandler(providerSettings)
+ }
+
+ await this.postStateToWebview()
}
+ // Task Management
+
async cancelTask() {
const cline = this.getCurrentCline()
@@ -933,11 +1029,6 @@ export class ClineProvider extends EventEmitter implements
async updateCustomInstructions(instructions?: string) {
// User may be clearing the field.
await this.updateGlobalState("customInstructions", instructions || undefined)
-
- if (this.getCurrentCline()) {
- this.getCurrentCline()!.customInstructions = instructions || undefined
- }
-
await this.postStateToWebview()
}
@@ -995,14 +1086,14 @@ export class ClineProvider extends EventEmitter implements
throw error
}
- const newConfiguration: ApiConfiguration = {
+ const newConfiguration: ProviderSettings = {
...apiConfiguration,
apiProvider: "openrouter",
openRouterApiKey: apiKey,
openRouterModelId: apiConfiguration?.openRouterModelId || openRouterDefaultModelId,
}
- await this.upsertApiConfiguration(currentApiConfigName, newConfiguration)
+ await this.upsertProviderProfile(currentApiConfigName, newConfiguration)
}
// Glama
@@ -1025,14 +1116,14 @@ export class ClineProvider extends EventEmitter implements
const { apiConfiguration, currentApiConfigName } = await this.getState()
- const newConfiguration: ApiConfiguration = {
+ const newConfiguration: ProviderSettings = {
...apiConfiguration,
apiProvider: "glama",
glamaApiKey: apiKey,
glamaModelId: apiConfiguration?.glamaModelId || glamaDefaultModelId,
}
- await this.upsertApiConfiguration(currentApiConfigName, newConfiguration)
+ await this.upsertProviderProfile(currentApiConfigName, newConfiguration)
}
// Requesty
@@ -1040,36 +1131,14 @@ export class ClineProvider extends EventEmitter implements
async handleRequestyCallback(code: string) {
let { apiConfiguration, currentApiConfigName } = await this.getState()
- const newConfiguration: ApiConfiguration = {
+ const newConfiguration: ProviderSettings = {
...apiConfiguration,
apiProvider: "requesty",
requestyApiKey: code,
requestyModelId: apiConfiguration?.requestyModelId || requestyDefaultModelId,
}
- await this.upsertApiConfiguration(currentApiConfigName, newConfiguration)
- }
-
- // Save configuration
-
- async upsertApiConfiguration(configName: string, apiConfiguration: ApiConfiguration) {
- try {
- await this.providerSettingsManager.saveConfig(configName, apiConfiguration)
- const listApiConfig = await this.providerSettingsManager.listConfig()
-
- await Promise.all([
- this.updateGlobalState("listApiConfigMeta", listApiConfig),
- this.updateApiConfiguration(apiConfiguration),
- this.updateGlobalState("currentApiConfigName", configName),
- ])
-
- await this.postStateToWebview()
- } catch (error) {
- this.log(
- `Error create new api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
- )
- vscode.window.showErrorMessage(t("common:errors.create_api_config"))
- }
+ await this.upsertProviderProfile(currentApiConfigName, newConfiguration)
}
// Task history
@@ -1365,7 +1434,7 @@ export class ClineProvider extends EventEmitter implements
const customModes = await this.customModesManager.getCustomModes()
// Determine apiProvider with the same logic as before.
- const apiProvider: ApiProvider = stateValues.apiProvider ? stateValues.apiProvider : "anthropic"
+ const apiProvider: ProviderName = stateValues.apiProvider ? stateValues.apiProvider : "anthropic"
// Build the apiConfiguration object combining state values and secrets.
const providerSettings = this.contextProxy.getProviderSettings()
@@ -1544,10 +1613,12 @@ export class ClineProvider extends EventEmitter implements
const appVersion = this.context.extension?.packageJSON?.version
const vscodeVersion = vscode.version
const platform = process.platform
+ const editorName = vscode.env.appName // Get the editor name (VS Code, Cursor, etc.)
const properties: Record = {
vscodeVersion,
platform,
+ editorName,
}
// Add extension version
@@ -1589,6 +1660,10 @@ export class ClineProvider extends EventEmitter implements
if (currentCline?.creatorModeConfig?.creatorMode) {
properties.isCreatorMode = true
}
+ // Add isSubtask property that indicates whether this task is a subtask
+ if (currentCline) {
+ properties.isSubtask = !!currentCline.parentTask
+ }
return properties
}
diff --git a/src/core/webview/__tests__/ClineProvider.test.ts b/src/core/webview/__tests__/ClineProvider.test.ts
index 344c9672186..d3b7f80e166 100644
--- a/src/core/webview/__tests__/ClineProvider.test.ts
+++ b/src/core/webview/__tests__/ClineProvider.test.ts
@@ -1,53 +1,42 @@
// npx jest src/core/webview/__tests__/ClineProvider.test.ts
+import Anthropic from "@anthropic-ai/sdk"
import * as vscode from "vscode"
import axios from "axios"
import { ClineProvider } from "../ClineProvider"
-import { ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
+import { ProviderSettingsEntry, ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
import { setSoundEnabled } from "../../../utils/sound"
import { setTtsEnabled } from "../../../utils/tts"
import { defaultModeSlug } from "../../../shared/modes"
import { experimentDefault } from "../../../shared/experiments"
import { ContextProxy } from "../../config/ContextProxy"
import { AGENT_RULES_DIR } from "../../../shared/constants"
+import { Task, TaskOptions } from "../../task/Task"
// Mock setup must come before imports
jest.mock("../../prompts/sections/custom-instructions")
-// Mock dependencies
jest.mock("vscode")
+
jest.mock("delay")
-// Mock BrowserSession
-jest.mock("../../../services/browser/BrowserSession", () => ({
- BrowserSession: jest.fn().mockImplementation(() => ({
- testConnection: jest.fn().mockImplementation(async (url) => {
- if (url === "http://localhost:9222") {
- return {
- success: true,
- message: "Successfully connected to Chrome",
- endpoint: "ws://localhost:9222/devtools/browser/123",
- }
- } else {
- return {
- success: false,
- message: "Failed to connect to Chrome",
- endpoint: undefined,
- }
- }
- }),
- })),
+jest.mock("p-wait-for", () => ({
+ __esModule: true,
+ default: jest.fn().mockResolvedValue(undefined),
}))
-// Mock browserDiscovery
-jest.mock("../../../services/browser/browserDiscovery", () => ({
- discoverChromeHostUrl: jest.fn().mockImplementation(async () => {
- return "http://localhost:9222"
- }),
- tryChromeHostUrl: jest.fn().mockImplementation(async (url) => {
- return url === "http://localhost:9222"
- }),
+jest.mock("fs/promises", () => ({
+ mkdir: jest.fn(),
+ writeFile: jest.fn(),
+ readFile: jest.fn(),
+ unlink: jest.fn(),
+ rmdir: jest.fn(),
+}))
+
+jest.mock("axios", () => ({
+ get: jest.fn().mockResolvedValue({ data: { data: [] } }),
+ post: jest.fn(),
}))
jest.mock(
@@ -75,6 +64,35 @@ jest.mock(
{ virtual: true },
)
+jest.mock("../../../services/browser/BrowserSession", () => ({
+ BrowserSession: jest.fn().mockImplementation(() => ({
+ testConnection: jest.fn().mockImplementation(async (url) => {
+ if (url === "http://localhost:9222") {
+ return {
+ success: true,
+ message: "Successfully connected to Chrome",
+ endpoint: "ws://localhost:9222/devtools/browser/123",
+ }
+ } else {
+ return {
+ success: false,
+ message: "Failed to connect to Chrome",
+ endpoint: undefined,
+ }
+ }
+ }),
+ })),
+}))
+
+jest.mock("../../../services/browser/browserDiscovery", () => ({
+ discoverChromeHostUrl: jest.fn().mockImplementation(async () => {
+ return "http://localhost:9222"
+ }),
+ tryChromeHostUrl: jest.fn().mockImplementation(async (url) => {
+ return url === "http://localhost:9222"
+ }),
+}))
+
// Initialize mocks
const mockAddCustomInstructions = jest.fn().mockResolvedValue("Combined instructions")
@@ -116,7 +134,6 @@ jest.mock(
{ virtual: true },
)
-// Mock dependencies
jest.mock("vscode", () => ({
ExtensionContext: jest.fn(),
OutputChannel: jest.fn(),
@@ -157,50 +174,24 @@ jest.mock("vscode", () => ({
},
}))
-// Mock sound utility
jest.mock("../../../utils/sound", () => ({
setSoundEnabled: jest.fn(),
}))
-// Mock tts utility
jest.mock("../../../utils/tts", () => ({
setTtsEnabled: jest.fn(),
setTtsSpeed: jest.fn(),
}))
-// Mock ESM modules
-jest.mock("p-wait-for", () => ({
- __esModule: true,
- default: jest.fn().mockResolvedValue(undefined),
-}))
-
-// Mock fs/promises
-jest.mock("fs/promises", () => ({
- mkdir: jest.fn(),
- writeFile: jest.fn(),
- readFile: jest.fn(),
- unlink: jest.fn(),
- rmdir: jest.fn(),
-}))
-
-// Mock axios
-jest.mock("axios", () => ({
- get: jest.fn().mockResolvedValue({ data: { data: [] } }),
- post: jest.fn(),
-}))
-
-// Mock buildApiHandler
jest.mock("../../../api", () => ({
buildApiHandler: jest.fn(),
}))
-// Mock system prompt
jest.mock("../../prompts/system", () => ({
SYSTEM_PROMPT: jest.fn().mockImplementation(async () => "mocked system prompt"),
codeMode: "code",
}))
-// Mock WorkspaceTracker
jest.mock("../../../integrations/workspace/WorkspaceTracker", () => {
return jest.fn().mockImplementation(() => ({
initializeFilePaths: jest.fn(),
@@ -208,9 +199,8 @@ jest.mock("../../../integrations/workspace/WorkspaceTracker", () => {
}))
})
-// Mock Cline
-jest.mock("../../Cline", () => ({
- Cline: jest
+jest.mock("../../task/Task", () => ({
+ Task: jest
.fn()
.mockImplementation(
(_provider, _apiConfiguration, _customInstructions, _diffEnabled, _fuzzyMatchThreshold, _task, taskId) => ({
@@ -230,7 +220,6 @@ jest.mock("../../Cline", () => ({
),
}))
-// Mock extract-text
jest.mock("../../../integrations/misc/extract-text", () => ({
extractTextFromFile: jest.fn().mockImplementation(async (_filePath: string) => {
const content = "const x = 1;\nconst y = 2;\nconst z = 3;"
@@ -239,17 +228,13 @@ jest.mock("../../../integrations/misc/extract-text", () => ({
}),
}))
-// Spy on console.error and console.log to suppress expected messages
-beforeAll(() => {
- jest.spyOn(console, "error").mockImplementation(() => {})
- jest.spyOn(console, "log").mockImplementation(() => {})
-})
-
afterAll(() => {
jest.restoreAllMocks()
})
describe("ClineProvider", () => {
+ let defaultTaskOptions: TaskOptions
+
let provider: ClineProvider
let mockContext: vscode.ExtensionContext
let mockOutputChannel: vscode.OutputChannel
@@ -328,6 +313,13 @@ describe("ClineProvider", () => {
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", new ContextProxy(mockContext))
+ defaultTaskOptions = {
+ provider,
+ apiConfiguration: {
+ apiProvider: "openrouter",
+ },
+ }
+
// @ts-ignore - Access private property for testing
updateGlobalStateSpy = jest.spyOn(provider.contextProxy, "setValue")
@@ -452,8 +444,7 @@ describe("ClineProvider", () => {
test("clearTask aborts current task", async () => {
// Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline = new Cline() // Create a new mocked instance
+ const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
// add the mock object to the stack
await provider.addClineToStack(mockCline)
@@ -476,9 +467,8 @@ describe("ClineProvider", () => {
test("addClineToStack adds multiple Cline instances to the stack", async () => {
// Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline1 = new Cline() // Create a new mocked instance
- const mockCline2 = new Cline() // Create a new mocked instance
+ const mockCline1 = new Task(defaultTaskOptions) // Create a new mocked instance
+ const mockCline2 = new Task(defaultTaskOptions) // Create a new mocked instance
Object.defineProperty(mockCline1, "taskId", { value: "test-task-id-1", writable: true })
Object.defineProperty(mockCline2, "taskId", { value: "test-task-id-2", writable: true })
@@ -601,14 +591,16 @@ describe("ClineProvider", () => {
expect(state.alwaysApproveResubmit).toBe(false)
})
- test("loads saved API config when switching modes", async () => {
+ it("loads saved API config when switching modes", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
+ const profile: ProviderSettingsEntry = { name: "test-config", id: "test-id", apiProvider: "anthropic" }
+
;(provider as any).providerSettingsManager = {
getModeConfigId: jest.fn().mockResolvedValue("test-id"),
- listConfig: jest.fn().mockResolvedValue([{ name: "test-config", id: "test-id", apiProvider: "anthropic" }]),
- loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
+ listConfig: jest.fn().mockResolvedValue([profile]),
+ activateProfile: jest.fn().mockResolvedValue(profile),
setModeConfig: jest.fn(),
} as any
@@ -617,11 +609,11 @@ describe("ClineProvider", () => {
// Should load the saved config for architect mode
expect(provider.providerSettingsManager.getModeConfigId).toHaveBeenCalledWith("architect")
- expect(provider.providerSettingsManager.loadConfig).toHaveBeenCalledWith("test-config")
+ expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ name: "test-config" })
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "test-config")
})
- test("saves current config when switching to mode without config", async () => {
+ it("saves current config when switching to mode without config", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
@@ -642,16 +634,15 @@ describe("ClineProvider", () => {
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")
})
- test("saves config as default for current mode when loading config", async () => {
+ it("saves config as default for current mode when loading config", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
+ const profile: ProviderSettingsEntry = { apiProvider: "anthropic", id: "new-id", name: "new-config" }
+
;(provider as any).providerSettingsManager = {
- loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic", id: "new-id" }),
- loadConfigById: jest
- .fn()
- .mockResolvedValue({ config: { apiProvider: "anthropic", id: "new-id" }, name: "new-config" }),
- listConfig: jest.fn().mockResolvedValue([{ name: "new-config", id: "new-id", apiProvider: "anthropic" }]),
+ activateProfile: jest.fn().mockResolvedValue(profile),
+ listConfig: jest.fn().mockResolvedValue([profile]),
setModeConfig: jest.fn(),
getModeConfigId: jest.fn().mockResolvedValue(undefined),
} as any
@@ -666,18 +657,19 @@ describe("ClineProvider", () => {
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "new-id")
})
- test("load API configuration by ID works and updates mode config", async () => {
+ it("load API configuration by ID works and updates mode config", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
+ const profile: ProviderSettingsEntry = {
+ name: "config-by-id",
+ id: "config-id-123",
+ apiProvider: "anthropic",
+ }
+
;(provider as any).providerSettingsManager = {
- loadConfigById: jest.fn().mockResolvedValue({
- config: { apiProvider: "anthropic", id: "config-id-123" },
- name: "config-by-id",
- }),
- listConfig: jest
- .fn()
- .mockResolvedValue([{ name: "config-by-id", id: "config-id-123", apiProvider: "anthropic" }]),
+ activateProfile: jest.fn().mockResolvedValue(profile),
+ listConfig: jest.fn().mockResolvedValue([profile]),
setModeConfig: jest.fn(),
getModeConfigId: jest.fn().mockResolvedValue(undefined),
} as any
@@ -691,8 +683,8 @@ describe("ClineProvider", () => {
// Should save new config as default for architect mode
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "config-id-123")
- // Ensure the loadConfigById method was called with the correct ID
- expect(provider.providerSettingsManager.loadConfigById).toHaveBeenCalledWith("config-id-123")
+ // Ensure the `activateProfile` method was called with the correct ID
+ expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ id: "config-id-123" })
})
test("handles browserToolEnabled setting", async () => {
@@ -815,49 +807,6 @@ describe("ClineProvider", () => {
expect(mockPostMessage).toHaveBeenCalled()
})
- test("uses mode-specific custom instructions in Cline initialization", async () => {
- // Setup mock state
- const modeCustomInstructions = "Code mode instructions"
- const mockApiConfig = {
- apiProvider: "openrouter",
- }
-
- jest.spyOn(provider, "getState").mockResolvedValue({
- apiConfiguration: mockApiConfig,
- customModePrompts: {
- code: { customInstructions: modeCustomInstructions },
- },
- mode: "code",
- diffEnabled: true,
- enableCheckpoints: false,
- fuzzyMatchThreshold: 1.0,
- experiments: experimentDefault,
- } as any)
-
- // Reset Cline mock
- const { Cline } = require("../../Cline")
- ;(Cline as jest.Mock).mockClear()
-
- // Initialize Cline with a task
- await provider.initClineWithTask("Test task")
-
- // Verify Cline was initialized with mode-specific instructions
- expect(Cline).toHaveBeenCalledWith({
- provider,
- apiConfiguration: mockApiConfig,
- customInstructions: modeCustomInstructions,
- enableDiff: true,
- enableCheckpoints: false,
- fuzzyMatchThreshold: 1.0,
- task: "Test task",
- experiments: experimentDefault,
- rootTask: undefined,
- parentTask: undefined,
- taskNumber: 1,
- onCreated: expect.any(Function),
- })
- })
-
test("handles mode-specific custom instructions updates", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
@@ -895,7 +844,7 @@ describe("ClineProvider", () => {
})
})
- test("saves mode config when updating API configuration", async () => {
+ it("saves mode config when updating API configuration", async () => {
// Setup mock context with mode and config name
mockContext = {
...mockContext,
@@ -921,12 +870,14 @@ describe("ClineProvider", () => {
;(provider as any).providerSettingsManager = {
listConfig: jest.fn().mockResolvedValue([{ name: "test-config", id: "test-id", apiProvider: "anthropic" }]),
+ saveConfig: jest.fn().mockResolvedValue("test-id"),
setModeConfig: jest.fn(),
} as any
// Update API configuration
await messageHandler({
- type: "apiConfiguration",
+ type: "upsertApiConfiguration",
+ text: "test-config",
apiConfiguration: { apiProvider: "anthropic" },
})
@@ -959,13 +910,19 @@ describe("ClineProvider", () => {
{ ts: 4000, type: "say", say: "browser_action" }, // Response to delete
{ ts: 5000, type: "say", say: "user_feedback" }, // Next user message
{ ts: 6000, type: "say", say: "user_feedback" }, // Final message
- ]
-
- const mockApiHistory = [{ ts: 1000 }, { ts: 2000 }, { ts: 3000 }, { ts: 4000 }, { ts: 5000 }, { ts: 6000 }]
-
- // Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline = new Cline() // Create a new mocked instance
+ ] as ClineMessage[]
+
+ const mockApiHistory = [
+ { ts: 1000 },
+ { ts: 2000 },
+ { ts: 3000 },
+ { ts: 4000 },
+ { ts: 5000 },
+ { ts: 6000 },
+ ] as (Anthropic.MessageParam & { ts?: number })[]
+
+ // Setup Task instance with auto-mock from the top of the file
+ const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
mockCline.clineMessages = mockMessages // Set test-specific messages
mockCline.apiConversationHistory = mockApiHistory // Set API history
await provider.addClineToStack(mockCline) // Add the mocked instance to the stack
@@ -1006,13 +963,19 @@ describe("ClineProvider", () => {
{ ts: 2000, type: "say", say: "text", value: 3000 }, // Message to delete
{ ts: 3000, type: "say", say: "user_feedback" },
{ ts: 4000, type: "say", say: "user_feedback" },
- ]
+ ] as ClineMessage[]
- const mockApiHistory = [{ ts: 1000 }, { ts: 2000 }, { ts: 3000 }, { ts: 4000 }]
+ const mockApiHistory = [
+ { ts: 1000 },
+ { ts: 2000 },
+ { ts: 3000 },
+ { ts: 4000 },
+ ] as (Anthropic.MessageParam & {
+ ts?: number
+ })[]
// Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline = new Cline() // Create a new mocked instance
+ const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
mockCline.clineMessages = mockMessages
mockCline.apiConversationHistory = mockApiHistory
await provider.addClineToStack(mockCline)
@@ -1038,10 +1001,11 @@ describe("ClineProvider", () => {
;(vscode.window.showInformationMessage as jest.Mock).mockResolvedValue("Cancel")
// Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline = new Cline() // Create a new mocked instance
- mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }]
- mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }]
+ const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
+ mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }] as ClineMessage[]
+ mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }] as (Anthropic.MessageParam & {
+ ts?: number
+ })[]
await provider.addClineToStack(mockCline)
// Trigger message deletion
@@ -1213,15 +1177,16 @@ describe("ClineProvider", () => {
})
test("passes diffEnabled: false to SYSTEM_PROMPT when diff is disabled", async () => {
- // Setup Cline instance with mocked api.getModel()
- const { Cline } = require("../../Cline")
- const mockCline = new Cline()
+ // Setup Task instance with mocked api.getModel()
+ const mockCline = new Task(defaultTaskOptions)
+
mockCline.api = {
getModel: jest.fn().mockReturnValue({
id: "claude-3-sonnet",
info: { supportsComputerUse: true },
}),
- }
+ } as any
+
await provider.addClineToStack(mockCline)
// Mock getState to return diffEnabled: false
@@ -1537,13 +1502,17 @@ describe("ClineProvider", () => {
await provider.resolveWebviewView(mockWebviewView)
})
- test("loads saved API config when switching modes", async () => {
+ it("loads saved API config when switching modes", async () => {
+ const profile: ProviderSettingsEntry = {
+ name: "saved-config",
+ id: "saved-config-id",
+ apiProvider: "anthropic",
+ }
+
;(provider as any).providerSettingsManager = {
getModeConfigId: jest.fn().mockResolvedValue("saved-config-id"),
- listConfig: jest
- .fn()
- .mockResolvedValue([{ name: "saved-config", id: "saved-config-id", apiProvider: "anthropic" }]),
- loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
+ listConfig: jest.fn().mockResolvedValue([profile]),
+ activateProfile: jest.fn().mockResolvedValue(profile),
setModeConfig: jest.fn(),
} as any
@@ -1555,7 +1524,7 @@ describe("ClineProvider", () => {
// Verify saved config was loaded
expect(provider.providerSettingsManager.getModeConfigId).toHaveBeenCalledWith("architect")
- expect(provider.providerSettingsManager.loadConfig).toHaveBeenCalledWith("saved-config")
+ expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ name: "saved-config" })
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "saved-config")
// Verify state was posted to webview
@@ -1671,14 +1640,11 @@ describe("ClineProvider", () => {
currentApiConfigName: "test-config",
} as any)
- // Trigger updateApiConfiguration
+ // Trigger upsertApiConfiguration
await messageHandler({
type: "upsertApiConfiguration",
text: "test-config",
- apiConfiguration: {
- apiProvider: "anthropic",
- apiKey: "test-key",
- },
+ apiConfiguration: { apiProvider: "anthropic", apiKey: "test-key" },
})
// Verify error was logged and user was notified
@@ -1743,9 +1709,8 @@ describe("ClineProvider", () => {
.mockResolvedValue([{ name: "test-config", id: "test-id", apiProvider: "anthropic" }]),
} as any
- // Setup Cline instance with auto-mock from the top of the file
- const { Cline } = require("../../Cline") // Get the mocked class
- const mockCline = new Cline() // Create a new mocked instance
+ // Setup Task instance with auto-mock from the top of the file
+ const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
await provider.addClineToStack(mockCline)
const testApiConfig = {
@@ -2085,6 +2050,7 @@ describe.skip("ContextProxy integration", () => {
})
describe("getTelemetryProperties", () => {
+ let defaultTaskOptions: TaskOptions
let provider: ClineProvider
let mockContext: vscode.ExtensionContext
let mockOutputChannel: vscode.OutputChannel
@@ -2114,9 +2080,15 @@ describe("getTelemetryProperties", () => {
mockOutputChannel = { appendLine: jest.fn() } as unknown as vscode.OutputChannel
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", new ContextProxy(mockContext))
- // Setup Cline instance with mocked getModel method
- const { Cline } = require("../../Cline")
- mockCline = new Cline()
+ defaultTaskOptions = {
+ provider,
+ apiConfiguration: {
+ apiProvider: "openrouter",
+ },
+ }
+
+ // Setup Task instance with mocked getModel method
+ mockCline = new Task(defaultTaskOptions)
mockCline.api = {
getModel: jest.fn().mockReturnValue({
id: "claude-3-7-sonnet-20250219",
diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts
new file mode 100644
index 00000000000..f676fa18f62
--- /dev/null
+++ b/src/core/webview/generateSystemPrompt.ts
@@ -0,0 +1,73 @@
+import { WebviewMessage } from "../../shared/WebviewMessage"
+import { defaultModeSlug, getModeBySlug, getGroupName } from "../../shared/modes"
+import { buildApiHandler } from "../../api"
+
+import { SYSTEM_PROMPT } from "../prompts/system"
+import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
+
+import { ClineProvider } from "./ClineProvider"
+
+export const generateSystemPrompt = async (provider: ClineProvider, message: WebviewMessage) => {
+ const {
+ apiConfiguration,
+ customModePrompts,
+ customInstructions,
+ browserViewportSize,
+ diffEnabled,
+ mcpEnabled,
+ fuzzyMatchThreshold,
+ experiments,
+ enableMcpServerCreation,
+ browserToolEnabled,
+ language,
+ } = await provider.getState()
+
+ const diffStrategy = new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
+
+ const cwd = provider.cwd
+
+ const mode = message.mode ?? defaultModeSlug
+ const customModes = await provider.customModesManager.getCustomModes()
+
+ const rooIgnoreInstructions = provider.getCurrentCline()?.rooIgnoreController?.getInstructions()
+
+ // Determine if browser tools can be used based on model support, mode, and user settings
+ let modelSupportsComputerUse = false
+
+ // Create a temporary API handler to check if the model supports computer use
+ // This avoids relying on an active Cline instance which might not exist during preview
+ try {
+ const tempApiHandler = buildApiHandler(apiConfiguration)
+ modelSupportsComputerUse = tempApiHandler.getModel().info.supportsComputerUse ?? false
+ } catch (error) {
+ console.error("Error checking if model supports computer use:", error)
+ }
+
+ // Check if the current mode includes the browser tool group
+ const modeConfig = getModeBySlug(mode, customModes)
+ const modeSupportsBrowser = modeConfig?.groups.some((group) => getGroupName(group) === "browser") ?? false
+
+ // Only enable browser tools if the model supports it, the mode includes browser tools,
+ // and browser tools are enabled in settings
+ const canUseBrowserTool = modelSupportsComputerUse && modeSupportsBrowser && (browserToolEnabled ?? true)
+
+ const systemPrompt = await SYSTEM_PROMPT(
+ provider.context,
+ cwd,
+ canUseBrowserTool,
+ mcpEnabled ? provider.getMcpHub() : undefined,
+ diffStrategy,
+ browserViewportSize ?? "900x600",
+ mode,
+ customModePrompts,
+ customModes,
+ customInstructions,
+ diffEnabled,
+ experiments,
+ enableMcpServerCreation,
+ language,
+ rooIgnoreInstructions,
+ )
+
+ return systemPrompt
+}
diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts
index 003e2523a0c..88a1fb42eb9 100644
--- a/src/core/webview/webviewMessageHandler.ts
+++ b/src/core/webview/webviewMessageHandler.ts
@@ -4,9 +4,9 @@ import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
import { ClineProvider } from "./ClineProvider"
-import { Language, ApiConfigMeta } from "../../schemas"
+import { Language, ProviderSettings } from "../../schemas"
import { changeLanguage, t } from "../../i18n"
-import { ApiConfiguration } from "../../shared/api"
+import { RouterName, toRouterName } from "../../shared/api"
import { supportPrompt } from "../../shared/support-prompt"
import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage"
@@ -32,14 +32,15 @@ import { openMention } from "../mentions"
import { telemetryService } from "../../services/telemetry/TelemetryService"
import { TelemetrySetting } from "../../shared/TelemetrySetting"
import { getWorkspacePath } from "../../utils/path"
-import { Mode, defaultModeSlug, getModeBySlug, getGroupName } from "../../shared/modes"
-import { SYSTEM_PROMPT } from "../prompts/system"
-import { buildApiHandler } from "../../api"
+import { Mode, defaultModeSlug } from "../../shared/modes"
import { GlobalState } from "../../schemas"
import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
-import { getModels } from "../../api/providers/fetchers/cache"
+import { getModels, flushModels} from "../../api/providers/fetchers/cache"
import { getpearAIExports } from "../../activate/registerPearListener"
import { AGENT_RULES_DIR } from "../../shared/constants"
+import { generateSystemPrompt } from "./generateSystemPrompt"
+
+const ALLOWED_VSCODE_SETTINGS = new Set(["terminal.integrated.inheritEnv"])
export const webviewMessageHandler = async (provider: ClineProvider, message: WebviewMessage) => {
// Utility functions provided for concise get/update of global state via contextProxy API.
@@ -91,19 +92,12 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
if (currentConfigName) {
if (!(await provider.providerSettingsManager.hasConfig(currentConfigName))) {
- // current config name not valid, get first config in list
- await updateGlobalState("currentApiConfigName", listApiConfig?.[0]?.name)
- if (listApiConfig?.[0]?.name) {
- const apiConfig = await provider.providerSettingsManager.loadConfig(
- listApiConfig?.[0]?.name,
- )
+ // Current config name not valid, get first config in list.
+ const name = listApiConfig[0]?.name
+ await updateGlobalState("currentApiConfigName", name)
- await Promise.all([
- updateGlobalState("listApiConfigMeta", listApiConfig),
- provider.postMessageToWebview({ type: "listApiConfig", listApiConfig }),
- provider.updateApiConfiguration(apiConfig),
- ])
- await provider.postStateToWebview()
+ if (name) {
+ await provider.activateProviderProfile({ name })
return
}
}
@@ -140,14 +134,12 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
// initializing new instance of Cline will make sure that any agentically running promises in old instance don't affect our new task. this essentially creates a fresh slate for the new task
const existingCline = provider.getCurrentCline()
const creatorModeConfig = existingCline?.creatorModeConfig
-
+
await provider.initClineWithTask(message.text, message.images, undefined, {}, creatorModeConfig)
- break
- case "apiConfiguration":
- if (message.apiConfiguration) {
- await provider.updateApiConfiguration(message.apiConfiguration)
- }
- await provider.postStateToWebview()
+ // Initializing new instance of Cline will make sure that any
+ // agentically running promises in old instance don't affect our new
+ // task. This essentially creates a fresh slate for the new task.
+ await provider.initClineWithTask(message.text, message.images)
break
case "customInstructions":
await provider.updateCustomInstructions(message.text)
@@ -292,12 +284,19 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
case "resetState":
await provider.resetState()
break
+ case "flushRouterModels":
+ const routerName: RouterName = toRouterName(message.text)
+ await flushModels(routerName)
+ break
case "requestRouterModels":
- const [openRouterModels, requestyModels, glamaModels, unboundModels] = await Promise.all([
- getModels("openrouter"),
- getModels("requesty"),
- getModels("glama"),
- getModels("unbound"),
+ const { apiConfiguration } = await provider.getState()
+
+ const [openRouterModels, requestyModels, glamaModels, unboundModels, litellmModels] = await Promise.all([
+ getModels("openrouter", apiConfiguration.openRouterApiKey),
+ getModels("requesty", apiConfiguration.requestyApiKey),
+ getModels("glama", apiConfiguration.glamaApiKey),
+ getModels("unbound", apiConfiguration.unboundApiKey),
+ getModels("litellm", apiConfiguration.litellmApiKey, apiConfiguration.litellmBaseUrl),
])
provider.postMessageToWebview({
@@ -307,6 +306,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
requesty: requestyModels,
glama: glamaModels,
unbound: unboundModels,
+ litellm: litellmModels,
},
})
break
@@ -341,7 +341,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
openImage(message.text!)
break
case "openFile":
- openFile(message.text!, message.values as { create?: boolean; content?: string })
+ openFile(message.text!, message.values as { create?: boolean; content?: string; line?: number })
break
case "openMention":
openMention(message.text)
@@ -380,16 +380,29 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
break
case "allowedCommands":
await provider.context.globalState.update("allowedCommands", message.commands)
- // Also update workspace settings
+
+ // Also update workspace settings.
await vscode.workspace
.getConfiguration("roo-cline")
.update("allowedCommands", message.commands, vscode.ConfigurationTarget.Global)
+
break
+ case "openCustomModesSettings": {
+ const customModesFilePath = await provider.customModesManager.getCustomModesFilePath()
+
+ if (customModesFilePath) {
+ openFile(customModesFilePath)
+ }
+
+ break
+ }
case "openMcpSettings": {
const mcpSettingsFilePath = await provider.getMcpHub()?.getMcpSettingsFilePath()
+
if (mcpSettingsFilePath) {
openFile(mcpSettingsFilePath)
}
+
break
}
case "openProjectMcpSettings": {
@@ -405,20 +418,16 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
try {
await fs.mkdir(rooDir, { recursive: true })
const exists = await fileExistsAtPath(mcpPath)
+
if (!exists) {
await fs.writeFile(mcpPath, JSON.stringify({ mcpServers: {} }, null, 2))
}
+
await openFile(mcpPath)
} catch (error) {
vscode.window.showErrorMessage(t("common:errors.create_mcp_json", { error: `${error}` }))
}
- break
- }
- case "openCustomModesSettings": {
- const customModesFilePath = await provider.customModesManager.getCustomModesFilePath()
- if (customModesFilePath) {
- openFile(customModesFilePath)
- }
+
break
}
case "deleteMcpServer": {
@@ -564,6 +573,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
if (!message.text) {
// Use testBrowserConnection for auto-discovery
const chromeHostUrl = await discoverChromeHostUrl()
+
if (chromeHostUrl) {
// Send the result back to the webview
await provider.postMessageToWebview({
@@ -583,6 +593,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
// Test the provided URL
const customHostUrl = message.text
const hostIsValid = await tryChromeHostUrl(message.text)
+
// Send the result back to the webview
await provider.postMessageToWebview({
type: "browserConnectionResult",
@@ -596,6 +607,42 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
case "fuzzyMatchThreshold":
await updateGlobalState("fuzzyMatchThreshold", message.value)
await provider.postStateToWebview()
+ break
+ case "updateVSCodeSetting": {
+ const { setting, value } = message
+
+ if (setting !== undefined && value !== undefined) {
+ if (ALLOWED_VSCODE_SETTINGS.has(setting)) {
+ await vscode.workspace.getConfiguration().update(setting, value, true)
+ } else {
+ vscode.window.showErrorMessage(`Cannot update restricted VSCode setting: ${setting}`)
+ }
+ }
+
+ break
+ }
+ case "getVSCodeSetting":
+ const { setting } = message
+
+ if (setting) {
+ try {
+ await provider.postMessageToWebview({
+ type: "vsCodeSetting",
+ setting,
+ value: vscode.workspace.getConfiguration().get(setting),
+ })
+ } catch (error) {
+ console.error(`Failed to get VSCode setting ${message.setting}:`, error)
+
+ await provider.postMessageToWebview({
+ type: "vsCodeSetting",
+ setting,
+ error: `Failed to get setting: ${error.message}`,
+ value: undefined,
+ })
+ }
+ }
+
break
case "alwaysApproveResubmit":
await updateGlobalState("alwaysApproveResubmit", message.bool ?? false)
@@ -894,45 +941,36 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
const { apiConfiguration, customSupportPrompts, listApiConfigMeta, enhancementApiConfigId } =
await provider.getState()
- // Try to get enhancement config first, fall back to current config
- let configToUse: ApiConfiguration = apiConfiguration
- if (enhancementApiConfigId) {
- const config = listApiConfigMeta?.find((c: ApiConfigMeta) => c.id === enhancementApiConfigId)
- if (config?.name) {
- const loadedConfig = await provider.providerSettingsManager.loadConfig(config.name)
- if (loadedConfig.apiProvider) {
- configToUse = loadedConfig
- }
+ // Try to get enhancement config first, fall back to current config.
+ let configToUse: ProviderSettings = apiConfiguration
+
+ if (enhancementApiConfigId && !!listApiConfigMeta.find(({ id }) => id === enhancementApiConfigId)) {
+ const { name: _, ...providerSettings } = await provider.providerSettingsManager.getProfile({
+ id: enhancementApiConfigId,
+ })
+
+ if (providerSettings.apiProvider) {
+ configToUse = providerSettings
}
}
const enhancedPrompt = await singleCompletionHandler(
configToUse,
- supportPrompt.create(
- "ENHANCE",
- {
- userInput: message.text,
- },
- customSupportPrompts,
- ),
+ supportPrompt.create("ENHANCE", { userInput: message.text }, customSupportPrompts),
)
- // Capture telemetry for prompt enhancement
+ // Capture telemetry for prompt enhancement.
const currentCline = provider.getCurrentCline()
telemetryService.capturePromptEnhanced(currentCline?.taskId)
- await provider.postMessageToWebview({
- type: "enhancedPrompt",
- text: enhancedPrompt,
- })
+ await provider.postMessageToWebview({ type: "enhancedPrompt", text: enhancedPrompt })
} catch (error) {
provider.log(
`Error enhancing prompt: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
)
+
vscode.window.showErrorMessage(t("common:errors.enhance_prompt"))
- await provider.postMessageToWebview({
- type: "enhancedPrompt",
- })
+ await provider.postMessageToWebview({ type: "enhancedPrompt" })
}
}
break
@@ -1039,7 +1077,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
break
case "upsertApiConfiguration":
if (message.text && message.apiConfiguration) {
- await provider.upsertApiConfiguration(message.text, message.apiConfiguration)
+ await provider.upsertProviderProfile(message.text, message.apiConfiguration)
}
break
case "renameApiConfiguration":
@@ -1051,30 +1089,23 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
break
}
- // Load the old configuration to get its ID
- const oldConfig = await provider.providerSettingsManager.loadConfig(oldName)
+ // Load the old configuration to get its ID.
+ const { id } = await provider.providerSettingsManager.getProfile({ name: oldName })
- // Create a new configuration with the same ID
- const newConfig = {
- ...message.apiConfiguration,
- id: oldConfig.id, // Preserve the ID
- }
+ // Create a new configuration with the new name and old ID.
+ await provider.providerSettingsManager.saveConfig(newName, { ...message.apiConfiguration, id })
- // Save with the new name but same ID
- await provider.providerSettingsManager.saveConfig(newName, newConfig)
+ // Delete the old configuration.
await provider.providerSettingsManager.deleteConfig(oldName)
- const listApiConfig = await provider.providerSettingsManager.listConfig()
-
- // Update listApiConfigMeta first to ensure UI has latest data
- await updateGlobalState("listApiConfigMeta", listApiConfig)
- await updateGlobalState("currentApiConfigName", newName)
-
- await provider.postStateToWebview()
+ // Re-activate to update the global settings related to the
+ // currently activated provider profile.
+ await provider.activateProviderProfile({ name: newName })
} catch (error) {
provider.log(
`Error rename api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
)
+
vscode.window.showErrorMessage(t("common:errors.rename_api_config"))
}
}
@@ -1082,16 +1113,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
case "loadApiConfiguration":
if (message.text) {
try {
- const apiConfig = await provider.providerSettingsManager.loadConfig(message.text)
- const listApiConfig = await provider.providerSettingsManager.listConfig()
-
- await Promise.all([
- updateGlobalState("listApiConfigMeta", listApiConfig),
- updateGlobalState("currentApiConfigName", message.text),
- provider.updateApiConfiguration(apiConfig),
- ])
-
- await provider.postStateToWebview()
+ await provider.activateProviderProfile({ name: message.text })
} catch (error) {
provider.log(
`Error load api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
@@ -1103,18 +1125,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
case "loadApiConfigurationById":
if (message.text) {
try {
- const { config: apiConfig, name } = await provider.providerSettingsManager.loadConfigById(
- message.text,
- )
- const listApiConfig = await provider.providerSettingsManager.listConfig()
-
- await Promise.all([
- updateGlobalState("listApiConfigMeta", listApiConfig),
- updateGlobalState("currentApiConfigName", name),
- provider.updateApiConfiguration(apiConfig),
- ])
-
- await provider.postStateToWebview()
+ await provider.activateProviderProfile({ id: message.text })
} catch (error) {
provider.log(
`Error load api configuration by ID: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
@@ -1135,29 +1146,25 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
break
}
- try {
- await provider.providerSettingsManager.deleteConfig(message.text)
- const listApiConfig = await provider.providerSettingsManager.listConfig()
-
- // Update listApiConfigMeta first to ensure UI has latest data
- await updateGlobalState("listApiConfigMeta", listApiConfig)
+ const oldName = message.text
- // If this was the current config, switch to first available
- const currentApiConfigName = getGlobalState("currentApiConfigName")
+ const newName = (await provider.providerSettingsManager.listConfig()).filter(
+ (c) => c.name !== oldName,
+ )[0]?.name
- if (message.text === currentApiConfigName && listApiConfig?.[0]?.name) {
- const apiConfig = await provider.providerSettingsManager.loadConfig(listApiConfig[0].name)
- await Promise.all([
- updateGlobalState("currentApiConfigName", listApiConfig[0].name),
- provider.updateApiConfiguration(apiConfig),
- ])
- }
+ if (!newName) {
+ vscode.window.showErrorMessage(t("common:errors.delete_api_config"))
+ return
+ }
- await provider.postStateToWebview()
+ try {
+ await provider.providerSettingsManager.deleteConfig(oldName)
+ await provider.activateProviderProfile({ name: newName })
} catch (error) {
provider.log(
`Error delete api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`,
)
+
vscode.window.showErrorMessage(t("common:errors.delete_api_config"))
}
}
@@ -1277,75 +1284,10 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
case "openPearAICreatorFeedbackOverlay":
const pearAIExports = await getpearAIExports();
const currentCline = provider.getCurrentCline();
-
-
+
+
// Open the feedback form with the chat history
pearAIExports.pearAPI.creatorMode.openFeedbackForm(currentCline?.clineMessages || []);
break
}
}
-
-const generateSystemPrompt = async (provider: ClineProvider, message: WebviewMessage) => {
- const {
- apiConfiguration,
- customModePrompts,
- customInstructions,
- browserViewportSize,
- diffEnabled,
- mcpEnabled,
- fuzzyMatchThreshold,
- experiments,
- enableMcpServerCreation,
- browserToolEnabled,
- language,
- } = await provider.getState()
-
- const diffStrategy = new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
-
- const cwd = provider.cwd
-
- const mode = message.mode ?? defaultModeSlug
- const customModes = await provider.customModesManager.getCustomModes()
-
- const rooIgnoreInstructions = provider.getCurrentCline()?.rooIgnoreController?.getInstructions()
-
- // Determine if browser tools can be used based on model support, mode, and user settings
- let modelSupportsComputerUse = false
-
- // Create a temporary API handler to check if the model supports computer use
- // This avoids relying on an active Cline instance which might not exist during preview
- try {
- const tempApiHandler = buildApiHandler(apiConfiguration)
- modelSupportsComputerUse = tempApiHandler.getModel().info.supportsComputerUse ?? false
- } catch (error) {
- console.error("Error checking if model supports computer use:", error)
- }
-
- // Check if the current mode includes the browser tool group
- const modeConfig = getModeBySlug(mode, customModes)
- const modeSupportsBrowser = modeConfig?.groups.some((group) => getGroupName(group) === "browser") ?? false
-
- // Only enable browser tools if the model supports it, the mode includes browser tools,
- // and browser tools are enabled in settings
- const canUseBrowserTool = modelSupportsComputerUse && modeSupportsBrowser && (browserToolEnabled ?? true)
-
- const systemPrompt = await SYSTEM_PROMPT(
- provider.context,
- cwd,
- canUseBrowserTool,
- mcpEnabled ? provider.getMcpHub() : undefined,
- diffStrategy,
- browserViewportSize ?? "900x600",
- mode,
- customModePrompts,
- customModes,
- customInstructions,
- diffEnabled,
- experiments,
- enableMcpServerCreation,
- language,
- rooIgnoreInstructions,
- )
-
- return systemPrompt
-}
diff --git a/src/exports/api.ts b/src/exports/api.ts
index 8498fa763f9..5cd9c073219 100644
--- a/src/exports/api.ts
+++ b/src/exports/api.ts
@@ -6,8 +6,15 @@ import * as path from "path"
import { getWorkspacePath } from "../utils/path"
import { ClineProvider } from "../core/webview/ClineProvider"
import { openClineInNewTab } from "../activate/registerCommands"
-import { RooCodeSettings, RooCodeEvents, RooCodeEventName } from "../schemas"
-import { IpcOrigin, IpcMessageType, TaskCommandName, TaskEvent } from "../schemas/ipc"
+import {
+ RooCodeSettings,
+ RooCodeEvents,
+ RooCodeEventName,
+ ProviderSettings,
+ ProviderSettingsEntry,
+ isSecretStateKey,
+} from "../schemas"
+import { IpcOrigin, IpcMessageType, TaskCommandName, TaskEvent } from "../schemas"
import { RooCodeAPI } from "./interface"
import { IpcServer } from "./ipc"
@@ -178,91 +185,6 @@ export class API extends EventEmitter implements RooCodeAPI {
await this.sidebarProvider.postMessageToWebview({ type: "invoke", invoke: "secondaryButtonClick" })
}
- public getConfiguration() {
- return this.sidebarProvider.getValues()
- }
-
- public async setConfiguration(values: RooCodeSettings) {
- await this.sidebarProvider.setValues(values)
- await this.sidebarProvider.providerSettingsManager.saveConfig(values.currentApiConfigName || "default", values)
- await this.sidebarProvider.postStateToWebview()
- }
-
- public async createProfile(name: string) {
- if (!name || !name.trim()) {
- throw new Error("Profile name cannot be empty")
- }
-
- const currentSettings = this.getConfiguration()
- const profiles = currentSettings.listApiConfigMeta || []
-
- if (profiles.some((profile) => profile.name === name)) {
- throw new Error(`A profile with the name "${name}" already exists`)
- }
-
- const id = this.sidebarProvider.providerSettingsManager.generateId()
-
- await this.setConfiguration({
- ...currentSettings,
- listApiConfigMeta: [
- ...profiles,
- {
- id,
- name: name.trim(),
- apiProvider: "openai" as const,
- },
- ],
- })
-
- return id
- }
-
- public getProfiles() {
- return (this.getConfiguration().listApiConfigMeta || []).map((profile) => profile.name)
- }
-
- public async setActiveProfile(name: string) {
- const currentSettings = this.getConfiguration()
- const profiles = currentSettings.listApiConfigMeta || []
-
- const profile = profiles.find((p) => p.name === name)
-
- if (!profile) {
- throw new Error(`Profile with name "${name}" does not exist`)
- }
-
- await this.setConfiguration({ ...currentSettings, currentApiConfigName: profile.name })
- }
-
- public getActiveProfile() {
- return this.getConfiguration().currentApiConfigName
- }
-
- public async deleteProfile(name: string) {
- const currentSettings = this.getConfiguration()
- const profiles = currentSettings.listApiConfigMeta || []
- const targetIndex = profiles.findIndex((p) => p.name === name)
-
- if (targetIndex === -1) {
- throw new Error(`Profile with name "${name}" does not exist`)
- }
-
- const profileToDelete = profiles[targetIndex]
- profiles.splice(targetIndex, 1)
-
- // If we're deleting the active profile, clear the currentApiConfigName.
- const newSettings: RooCodeSettings = {
- ...currentSettings,
- listApiConfigMeta: profiles,
- currentApiConfigName:
- currentSettings.currentApiConfigName === profileToDelete.name
- ? undefined
- : currentSettings.currentApiConfigName,
- }
-
- await this.setConfiguration(newSettings)
- }
-
public isReady() {
return this.sidebarProvider.viewLaunched
}
@@ -328,4 +250,103 @@ export class API extends EventEmitter implements RooCodeAPI {
this.logfile = undefined
}
}
+
+ // Global Settings Management
+
+ public getConfiguration(): RooCodeSettings {
+ return Object.fromEntries(
+ Object.entries(this.sidebarProvider.getValues()).filter(([key]) => !isSecretStateKey(key)),
+ )
+ }
+
+ public async setConfiguration(values: RooCodeSettings) {
+ await this.sidebarProvider.contextProxy.setValues(values)
+ await this.sidebarProvider.providerSettingsManager.saveConfig(values.currentApiConfigName || "default", values)
+ await this.sidebarProvider.postStateToWebview()
+ }
+
+ // Provider Profile Management
+
+ public getProfiles(): string[] {
+ return this.sidebarProvider.getProviderProfileEntries().map(({ name }) => name)
+ }
+
+ public getProfileEntry(name: string): ProviderSettingsEntry | undefined {
+ return this.sidebarProvider.getProviderProfileEntry(name)
+ }
+
+ public async createProfile(name: string, profile?: ProviderSettings, activate: boolean = true) {
+ const entry = this.getProfileEntry(name)
+
+ if (entry) {
+ throw new Error(`Profile with name "${name}" already exists`)
+ }
+
+ const id = await this.sidebarProvider.upsertProviderProfile(name, profile ?? {}, activate)
+
+ if (!id) {
+ throw new Error(`Failed to create profile with name "${name}"`)
+ }
+
+ return id
+ }
+
+ public async updateProfile(
+ name: string,
+ profile: ProviderSettings,
+ activate: boolean = true,
+ ): Promise {
+ const entry = this.getProfileEntry(name)
+
+ if (!entry) {
+ throw new Error(`Profile with name "${name}" does not exist`)
+ }
+
+ const id = await this.sidebarProvider.upsertProviderProfile(name, profile, activate)
+
+ if (!id) {
+ throw new Error(`Failed to update profile with name "${name}"`)
+ }
+
+ return id
+ }
+
+ public async upsertProfile(
+ name: string,
+ profile: ProviderSettings,
+ activate: boolean = true,
+ ): Promise {
+ const id = await this.sidebarProvider.upsertProviderProfile(name, profile, activate)
+
+ if (!id) {
+ throw new Error(`Failed to upsert profile with name "${name}"`)
+ }
+
+ return id
+ }
+
+ public async deleteProfile(name: string): Promise {
+ const entry = this.getProfileEntry(name)
+
+ if (!entry) {
+ throw new Error(`Profile with name "${name}" does not exist`)
+ }
+
+ await this.sidebarProvider.deleteProviderProfile(entry)
+ }
+
+ public getActiveProfile(): string | undefined {
+ return this.getConfiguration().currentApiConfigName
+ }
+
+ public async setActiveProfile(name: string): Promise {
+ const entry = this.getProfileEntry(name)
+
+ if (!entry) {
+ throw new Error(`Profile with name "${name}" does not exist`)
+ }
+
+ await this.sidebarProvider.activateProviderProfile({ name })
+ return this.getActiveProfile()
+ }
}
diff --git a/src/exports/interface.ts b/src/exports/interface.ts
index a0ef46a2260..ababc64557a 100644
--- a/src/exports/interface.ts
+++ b/src/exports/interface.ts
@@ -1,12 +1,47 @@
import { EventEmitter } from "events"
+import { Socket } from "node:net"
+
+/**
+ * Types
+ */
+
+import type {
+ GlobalSettings,
+ ProviderSettings,
+ ProviderSettingsEntry,
+ ClineMessage,
+ TokenUsage,
+ RooCodeEvents,
+ IpcMessage,
+ TaskCommand,
+ TaskEvent,
+} from "./types"
+
+export type {
+ GlobalSettings,
+ ProviderSettings,
+ ProviderSettingsEntry,
+ ClineMessage,
+ TokenUsage,
+ RooCodeEvents,
+ IpcMessage,
+ TaskCommand,
+ TaskEvent,
+}
+
+/**
+ * Enums
+ */
-import type { ProviderSettings, GlobalSettings, ClineMessage, TokenUsage, RooCodeEvents } from "./types"
-export type { RooCodeSettings, ProviderSettings, GlobalSettings, ClineMessage, TokenUsage, RooCodeEvents }
+import { RooCodeEventName, IpcOrigin, IpcMessageType } from "../schemas"
-import { RooCodeEventName } from "../schemas"
-export type { RooCodeEventName }
+export { RooCodeEventName, IpcOrigin, IpcMessageType }
-type RooCodeSettings = GlobalSettings & ProviderSettings
+/**
+ * RooCodeAPI
+ */
+
+export type RooCodeSettings = GlobalSettings & ProviderSettings
export interface RooCodeAPI extends EventEmitter {
/**
@@ -74,6 +109,11 @@ export interface RooCodeAPI extends EventEmitter {
*/
pressSecondaryButton(): Promise
+ /**
+ * Returns true if the API is ready to use.
+ */
+ isReady(): boolean
+
/**
* Returns the current configuration.
* @returns The current configuration.
@@ -87,30 +127,46 @@ export interface RooCodeAPI extends EventEmitter {
setConfiguration(values: RooCodeSettings): Promise
/**
- * Creates a new API configuration profile
+ * Returns a list of all configured profile names
+ * @returns Array of profile names
+ */
+ getProfiles(): string[]
+
+ /**
+ * Returns the profile entry for a given name
* @param name The name of the profile
- * @returns The ID of the created profile
+ * @returns The profile entry, or undefined if the profile does not exist
*/
- createProfile(name: string): Promise
+ getProfileEntry(name: string): ProviderSettingsEntry | undefined
/**
- * Returns a list of all configured profile names
- * @returns Array of profile names
+ * Creates a new API configuration profile
+ * @param name The name of the profile
+ * @param profile The profile to create; defaults to an empty object
+ * @param activate Whether to activate the profile after creation; defaults to true
+ * @returns The ID of the created profile
+ * @throws Error if the profile already exists
*/
- getProfiles(): string[]
+ createProfile(name: string, profile?: ProviderSettings, activate?: boolean): Promise
/**
- * Changes the active API configuration profile
- * @param name The name of the profile to activate
+ * Updates an existing API configuration profile
+ * @param name The name of the profile
+ * @param profile The profile to update
+ * @param activate Whether to activate the profile after update; defaults to true
+ * @returns The ID of the updated profile
* @throws Error if the profile does not exist
*/
- setActiveProfile(name: string): Promise
+ updateProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise
/**
- * Returns the name of the currently active profile
- * @returns The profile name, or undefined if no profile is active
+ * Creates a new API configuration profile or updates an existing one
+ * @param name The name of the profile
+ * @param profile The profile to create or update; defaults to an empty object
+ * @param activate Whether to activate the profile after upsert; defaults to true
+ * @returns The ID of the upserted profile
*/
- getActiveProfile(): string | undefined
+ upsertProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise
/**
* Deletes a profile by name
@@ -120,7 +176,38 @@ export interface RooCodeAPI extends EventEmitter {
deleteProfile(name: string): Promise
/**
- * Returns true if the API is ready to use.
+ * Returns the name of the currently active profile
+ * @returns The profile name, or undefined if no profile is active
*/
- isReady(): boolean
+ getActiveProfile(): string | undefined
+
+ /**
+ * Changes the active API configuration profile
+ * @param name The name of the profile to activate
+ * @throws Error if the profile does not exist
+ */
+ setActiveProfile(name: string): Promise
+}
+
+/**
+ * RooCodeIpcServer
+ */
+
+export type IpcServerEvents = {
+ [IpcMessageType.Connect]: [clientId: string]
+ [IpcMessageType.Disconnect]: [clientId: string]
+ [IpcMessageType.TaskCommand]: [clientId: string, data: TaskCommand]
+ [IpcMessageType.TaskEvent]: [relayClientId: string | undefined, data: TaskEvent]
+}
+
+export interface RooCodeIpcServer extends EventEmitter {
+ listen(): void
+
+ broadcast(message: IpcMessage): void
+
+ send(client: string | Socket, message: IpcMessage): void
+
+ get socketPath(): string
+
+ get isListening(): boolean
}
diff --git a/src/exports/ipc.ts b/src/exports/ipc.ts
index 33a5b1ff668..85950c5ee61 100644
--- a/src/exports/ipc.ts
+++ b/src/exports/ipc.ts
@@ -4,20 +4,14 @@ import * as crypto from "node:crypto"
import ipc from "node-ipc"
-import { IpcOrigin, IpcMessageType, IpcMessage, ipcMessageSchema, TaskCommand, TaskEvent } from "../schemas/ipc"
+import { IpcOrigin, IpcMessageType, type IpcMessage, ipcMessageSchema } from "../schemas"
+import type { IpcServerEvents, RooCodeIpcServer } from "./interface"
/**
* IpcServer
*/
-type IpcServerEvents = {
- [IpcMessageType.Connect]: [clientId: string]
- [IpcMessageType.Disconnect]: [clientId: string]
- [IpcMessageType.TaskCommand]: [clientId: string, data: TaskCommand]
- [IpcMessageType.TaskEvent]: [relayClientId: string | undefined, data: TaskEvent]
-}
-
-export class IpcServer extends EventEmitter {
+export class IpcServer extends EventEmitter implements RooCodeIpcServer {
private readonly _socketPath: string
private readonly _log: (...args: unknown[]) => void
private readonly _clients: Map
diff --git a/src/exports/roo-code.d.ts b/src/exports/roo-code.d.ts
index d3a05f43ced..4e2567429b7 100644
--- a/src/exports/roo-code.d.ts
+++ b/src/exports/roo-code.d.ts
@@ -1,4 +1,187 @@
import { EventEmitter } from "events"
+import { Socket } from "node:net"
+
+type GlobalSettings = {
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ rateLimitSeconds?: number | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+}
type ProviderSettings = {
apiProvider?:
@@ -22,8 +205,19 @@ type ProviderSettings = {
| "fake-ai"
| "pearai"
| "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
)
| undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
apiModelId?: string | undefined
apiKey?: string | undefined
anthropicBaseUrl?: string | undefined
@@ -41,7 +235,6 @@ type ProviderSettings = {
awsRegion?: string | undefined
awsUseCrossRegionInference?: boolean | undefined
awsUsePromptCache?: boolean | undefined
- awspromptCacheId?: string | undefined
awsProfile?: string | undefined
awsUseProfile?: boolean | undefined
awsCustomArn?: string | undefined
@@ -62,7 +255,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -121,16 +313,6 @@ type ProviderSettings = {
unboundModelId?: string | undefined
requestyApiKey?: string | undefined
requestyModelId?: string | undefined
- xaiApiKey?: string | undefined
- modelMaxTokens?: number | undefined
- modelMaxThinkingTokens?: number | undefined
- includeMaxTokens?: boolean | undefined
- reasoningEffort?: ("low" | "medium" | "high") | undefined
- promptCachingEnabled?: boolean | undefined
- diffEnabled?: boolean | undefined
- fuzzyMatchThreshold?: number | undefined
- modelTemperature?: (number | null) | undefined
- rateLimitSeconds?: number | undefined
fakeAi?: unknown | undefined
pearaiBaseUrl?: string | undefined
pearaiModelId?: string | undefined
@@ -143,7 +325,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -176,7 +357,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -209,181 +389,43 @@ type ProviderSettings = {
newProjectPath?: string | undefined
}
| undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
}
-type GlobalSettings = {
- currentApiConfigName?: string | undefined
- listApiConfigMeta?:
- | {
- id: string
- name: string
- apiProvider?:
- | (
- | "anthropic"
- | "glama"
- | "openrouter"
- | "bedrock"
- | "vertex"
- | "openai"
- | "ollama"
- | "vscode-lm"
- | "lmstudio"
- | "gemini"
- | "openai-native"
- | "mistral"
- | "deepseek"
- | "unbound"
- | "requesty"
- | "human-relay"
- | "fake-ai"
- | "pearai"
- | "xai"
- )
- | undefined
- }[]
- | undefined
- pinnedApiConfigs?:
- | {
- [x: string]: boolean
- }
- | undefined
- lastShownAnnouncementId?: string | undefined
- customInstructions?: string | undefined
- taskHistory?:
- | {
- id: string
- number: number
- ts: number
- task: string
- tokensIn: number
- tokensOut: number
- cacheWrites?: number | undefined
- cacheReads?: number | undefined
- totalCost: number
- size?: number | undefined
- workspace?: string | undefined
- creatorModeConfig?:
- | {
- creatorMode?: boolean | undefined
- newProjectType?: string | undefined
- newProjectPath?: string | undefined
- }
- | undefined
- }[]
- | undefined
- autoApprovalEnabled?: boolean | undefined
- alwaysAllowReadOnly?: boolean | undefined
- alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
- alwaysAllowWrite?: boolean | undefined
- alwaysAllowWriteOutsideWorkspace?: boolean | undefined
- writeDelayMs?: number | undefined
- alwaysAllowBrowser?: boolean | undefined
- alwaysApproveResubmit?: boolean | undefined
- requestDelaySeconds?: number | undefined
- alwaysAllowMcp?: boolean | undefined
- alwaysAllowModeSwitch?: boolean | undefined
- alwaysAllowSubtasks?: boolean | undefined
- alwaysAllowExecute?: boolean | undefined
- allowedCommands?: string[] | undefined
- browserToolEnabled?: boolean | undefined
- browserViewportSize?: string | undefined
- screenshotQuality?: number | undefined
- remoteBrowserEnabled?: boolean | undefined
- remoteBrowserHost?: string | undefined
- cachedChromeHostUrl?: string | undefined
- enableCheckpoints?: boolean | undefined
- ttsEnabled?: boolean | undefined
- ttsSpeed?: number | undefined
- soundEnabled?: boolean | undefined
- soundVolume?: number | undefined
- maxOpenTabsContext?: number | undefined
- maxWorkspaceFiles?: number | undefined
- showRooIgnoredFiles?: boolean | undefined
- maxReadFileLine?: number | undefined
- terminalOutputLineLimit?: number | undefined
- terminalShellIntegrationTimeout?: number | undefined
- terminalShellIntegrationDisabled?: boolean | undefined
- terminalCommandDelay?: number | undefined
- terminalPowershellCounter?: boolean | undefined
- terminalZshClearEolMark?: boolean | undefined
- terminalZshOhMy?: boolean | undefined
- terminalZshP10k?: boolean | undefined
- terminalZdotdir?: boolean | undefined
- terminalCompressProgressBar?: boolean | undefined
- rateLimitSeconds?: number | undefined
- diffEnabled?: boolean | undefined
- fuzzyMatchThreshold?: number | undefined
- experiments?:
- | {
- powerSteering: boolean
- }
- | undefined
- language?:
+type ProviderSettingsEntry = {
+ id: string
+ name: string
+ apiProvider?:
| (
- | "ca"
- | "de"
- | "en"
- | "es"
- | "fr"
- | "hi"
- | "it"
- | "ja"
- | "ko"
- | "pl"
- | "pt-BR"
- | "ru"
- | "tr"
- | "vi"
- | "zh-CN"
- | "zh-TW"
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
)
| undefined
- telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
- mcpEnabled?: boolean | undefined
- enableMcpServerCreation?: boolean | undefined
- mode?: string | undefined
- modeApiConfigs?:
- | {
- [x: string]: string
- }
- | undefined
- customModes?:
- | {
- slug: string
- name: string
- roleDefinition: string
- customInstructions?: string | undefined
- groups: (
- | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
- | [
- "read" | "edit" | "browser" | "command" | "mcp" | "modes",
- {
- fileRegex?: string | undefined
- description?: string | undefined
- },
- ]
- )[]
- source?: ("global" | "project") | undefined
- backendOnly?: boolean | undefined
- }[]
- | undefined
- customModePrompts?:
- | {
- [x: string]:
- | {
- roleDefinition?: string | undefined
- customInstructions?: string | undefined
- }
- | undefined
- }
- | undefined
- customSupportPrompts?:
- | {
- [x: string]: string | undefined
- }
- | undefined
- enhancementApiConfigId?: string | undefined
- historyPreviewCollapsed?: boolean | undefined
}
type ClineMessage = {
@@ -441,7 +483,6 @@ type ClineMessage = {
| undefined
progressStatus?:
| {
- id?: string | undefined
icon?: string | undefined
text?: string | undefined
}
@@ -517,7 +558,6 @@ type RooCodeEvents = {
| undefined
progressStatus?:
| {
- id?: string | undefined
icon?: string | undefined
text?: string | undefined
}
@@ -586,6 +626,1113 @@ type RooCodeEvents = {
]
}
+type IpcMessage =
+ | {
+ type: "Ack"
+ origin: "server"
+ data: {
+ clientId: string
+ pid: number
+ ppid: number
+ }
+ }
+ | {
+ type: "TaskCommand"
+ origin: "client"
+ clientId: string
+ data:
+ | {
+ commandName: "StartNewTask"
+ data: {
+ configuration: {
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
+ apiModelId?: string | undefined
+ apiKey?: string | undefined
+ anthropicBaseUrl?: string | undefined
+ anthropicUseAuthToken?: boolean | undefined
+ glamaModelId?: string | undefined
+ glamaApiKey?: string | undefined
+ openRouterApiKey?: string | undefined
+ openRouterModelId?: string | undefined
+ openRouterBaseUrl?: string | undefined
+ openRouterSpecificProvider?: string | undefined
+ openRouterUseMiddleOutTransform?: boolean | undefined
+ awsAccessKey?: string | undefined
+ awsSecretKey?: string | undefined
+ awsSessionToken?: string | undefined
+ awsRegion?: string | undefined
+ awsUseCrossRegionInference?: boolean | undefined
+ awsUsePromptCache?: boolean | undefined
+ awsProfile?: string | undefined
+ awsUseProfile?: boolean | undefined
+ awsCustomArn?: string | undefined
+ vertexKeyFile?: string | undefined
+ vertexJsonCredentials?: string | undefined
+ vertexProjectId?: string | undefined
+ vertexRegion?: string | undefined
+ openAiBaseUrl?: string | undefined
+ openAiApiKey?: string | undefined
+ openAiLegacyFormat?: boolean | undefined
+ openAiR1FormatEnabled?: boolean | undefined
+ openAiModelId?: string | undefined
+ openAiCustomModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ openAiUseAzure?: boolean | undefined
+ azureApiVersion?: string | undefined
+ openAiStreamingEnabled?: boolean | undefined
+ enableReasoningEffort?: boolean | undefined
+ openAiHostHeader?: string | undefined
+ openAiHeaders?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ ollamaModelId?: string | undefined
+ ollamaBaseUrl?: string | undefined
+ vsCodeLmModelSelector?:
+ | {
+ vendor?: string | undefined
+ family?: string | undefined
+ version?: string | undefined
+ id?: string | undefined
+ }
+ | undefined
+ lmStudioModelId?: string | undefined
+ lmStudioBaseUrl?: string | undefined
+ lmStudioDraftModelId?: string | undefined
+ lmStudioSpeculativeDecodingEnabled?: boolean | undefined
+ geminiApiKey?: string | undefined
+ googleGeminiBaseUrl?: string | undefined
+ openAiNativeApiKey?: string | undefined
+ openAiNativeBaseUrl?: string | undefined
+ mistralApiKey?: string | undefined
+ mistralCodestralUrl?: string | undefined
+ deepSeekBaseUrl?: string | undefined
+ deepSeekApiKey?: string | undefined
+ unboundApiKey?: string | undefined
+ unboundModelId?: string | undefined
+ requestyApiKey?: string | undefined
+ requestyModelId?: string | undefined
+ fakeAi?: unknown | undefined
+ pearaiBaseUrl?: string | undefined
+ pearaiModelId?: string | undefined
+ pearaiApiKey?: string | undefined
+ pearaiModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ pearaiAgentModels?:
+ | {
+ models: {
+ [x: string]: {
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ }
+ }
+ defaultModelId?: string | undefined
+ }
+ | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+ }
+ text: string
+ images?: string[] | undefined
+ newTab?: boolean | undefined
+ }
+ }
+ | {
+ commandName: "CancelTask"
+ data: string
+ }
+ | {
+ commandName: "CloseTask"
+ data: string
+ }
+ }
+ | {
+ type: "TaskEvent"
+ origin: "server"
+ relayClientId?: string | undefined
+ data:
+ | {
+ eventName: "message"
+ payload: [
+ {
+ taskId: string
+ action: "created" | "updated"
+ message: {
+ ts: number
+ type: "ask" | "say"
+ ask?:
+ | (
+ | "followup"
+ | "command"
+ | "command_output"
+ | "completion_result"
+ | "tool"
+ | "api_req_failed"
+ | "resume_task"
+ | "resume_completed_task"
+ | "mistake_limit_reached"
+ | "browser_action_launch"
+ | "use_mcp_server"
+ )
+ | undefined
+ say?:
+ | (
+ | "error"
+ | "api_req_started"
+ | "api_req_finished"
+ | "api_req_retried"
+ | "api_req_retry_delayed"
+ | "api_req_deleted"
+ | "text"
+ | "reasoning"
+ | "completion_result"
+ | "user_feedback"
+ | "user_feedback_diff"
+ | "command_output"
+ | "shell_integration_warning"
+ | "browser_action"
+ | "browser_action_result"
+ | "mcp_server_request_started"
+ | "mcp_server_response"
+ | "subtask_result"
+ | "checkpoint_saved"
+ | "rooignore_error"
+ | "diff_error"
+ )
+ | undefined
+ text?: string | undefined
+ images?: string[] | undefined
+ partial?: boolean | undefined
+ reasoning?: string | undefined
+ conversationHistoryIndex?: number | undefined
+ checkpoint?:
+ | {
+ [x: string]: unknown
+ }
+ | undefined
+ progressStatus?:
+ | {
+ icon?: string | undefined
+ text?: string | undefined
+ }
+ | undefined
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskCreated"
+ payload: [string]
+ }
+ | {
+ eventName: "taskStarted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskModeSwitched"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskPaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskUnpaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAskResponded"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAborted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskSpawned"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskCompleted"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ {
+ [x: string]: {
+ attempts: number
+ failures: number
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskTokenUsageUpdated"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ ]
+ }
+ }
+
+type TaskCommand =
+ | {
+ commandName: "StartNewTask"
+ data: {
+ configuration: {
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
+ apiModelId?: string | undefined
+ apiKey?: string | undefined
+ anthropicBaseUrl?: string | undefined
+ anthropicUseAuthToken?: boolean | undefined
+ glamaModelId?: string | undefined
+ glamaApiKey?: string | undefined
+ openRouterApiKey?: string | undefined
+ openRouterModelId?: string | undefined
+ openRouterBaseUrl?: string | undefined
+ openRouterSpecificProvider?: string | undefined
+ openRouterUseMiddleOutTransform?: boolean | undefined
+ awsAccessKey?: string | undefined
+ awsSecretKey?: string | undefined
+ awsSessionToken?: string | undefined
+ awsRegion?: string | undefined
+ awsUseCrossRegionInference?: boolean | undefined
+ awsUsePromptCache?: boolean | undefined
+ awsProfile?: string | undefined
+ awsUseProfile?: boolean | undefined
+ awsCustomArn?: string | undefined
+ vertexKeyFile?: string | undefined
+ vertexJsonCredentials?: string | undefined
+ vertexProjectId?: string | undefined
+ vertexRegion?: string | undefined
+ openAiBaseUrl?: string | undefined
+ openAiApiKey?: string | undefined
+ openAiLegacyFormat?: boolean | undefined
+ openAiR1FormatEnabled?: boolean | undefined
+ openAiModelId?: string | undefined
+ openAiCustomModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ openAiUseAzure?: boolean | undefined
+ azureApiVersion?: string | undefined
+ openAiStreamingEnabled?: boolean | undefined
+ enableReasoningEffort?: boolean | undefined
+ openAiHostHeader?: string | undefined
+ openAiHeaders?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ ollamaModelId?: string | undefined
+ ollamaBaseUrl?: string | undefined
+ vsCodeLmModelSelector?:
+ | {
+ vendor?: string | undefined
+ family?: string | undefined
+ version?: string | undefined
+ id?: string | undefined
+ }
+ | undefined
+ lmStudioModelId?: string | undefined
+ lmStudioBaseUrl?: string | undefined
+ lmStudioDraftModelId?: string | undefined
+ lmStudioSpeculativeDecodingEnabled?: boolean | undefined
+ geminiApiKey?: string | undefined
+ googleGeminiBaseUrl?: string | undefined
+ openAiNativeApiKey?: string | undefined
+ openAiNativeBaseUrl?: string | undefined
+ mistralApiKey?: string | undefined
+ mistralCodestralUrl?: string | undefined
+ deepSeekBaseUrl?: string | undefined
+ deepSeekApiKey?: string | undefined
+ unboundApiKey?: string | undefined
+ unboundModelId?: string | undefined
+ requestyApiKey?: string | undefined
+ requestyModelId?: string | undefined
+ fakeAi?: unknown | undefined
+ pearaiBaseUrl?: string | undefined
+ pearaiModelId?: string | undefined
+ pearaiApiKey?: string | undefined
+ pearaiModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ pearaiAgentModels?:
+ | {
+ models: {
+ [x: string]: {
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ }
+ }
+ defaultModelId?: string | undefined
+ }
+ | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+ }
+ text: string
+ images?: string[] | undefined
+ newTab?: boolean | undefined
+ }
+ }
+ | {
+ commandName: "CancelTask"
+ data: string
+ }
+ | {
+ commandName: "CloseTask"
+ data: string
+ }
+
+type TaskEvent =
+ | {
+ eventName: "message"
+ payload: [
+ {
+ taskId: string
+ action: "created" | "updated"
+ message: {
+ ts: number
+ type: "ask" | "say"
+ ask?:
+ | (
+ | "followup"
+ | "command"
+ | "command_output"
+ | "completion_result"
+ | "tool"
+ | "api_req_failed"
+ | "resume_task"
+ | "resume_completed_task"
+ | "mistake_limit_reached"
+ | "browser_action_launch"
+ | "use_mcp_server"
+ )
+ | undefined
+ say?:
+ | (
+ | "error"
+ | "api_req_started"
+ | "api_req_finished"
+ | "api_req_retried"
+ | "api_req_retry_delayed"
+ | "api_req_deleted"
+ | "text"
+ | "reasoning"
+ | "completion_result"
+ | "user_feedback"
+ | "user_feedback_diff"
+ | "command_output"
+ | "shell_integration_warning"
+ | "browser_action"
+ | "browser_action_result"
+ | "mcp_server_request_started"
+ | "mcp_server_response"
+ | "subtask_result"
+ | "checkpoint_saved"
+ | "rooignore_error"
+ | "diff_error"
+ )
+ | undefined
+ text?: string | undefined
+ images?: string[] | undefined
+ partial?: boolean | undefined
+ reasoning?: string | undefined
+ conversationHistoryIndex?: number | undefined
+ checkpoint?:
+ | {
+ [x: string]: unknown
+ }
+ | undefined
+ progressStatus?:
+ | {
+ icon?: string | undefined
+ text?: string | undefined
+ }
+ | undefined
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskCreated"
+ payload: [string]
+ }
+ | {
+ eventName: "taskStarted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskModeSwitched"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskPaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskUnpaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAskResponded"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAborted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskSpawned"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskCompleted"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ {
+ [x: string]: {
+ attempts: number
+ failures: number
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskTokenUsageUpdated"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ ]
+ }
+
/**
* RooCodeEvent
*/
@@ -603,7 +1750,24 @@ declare enum RooCodeEventName {
TaskTokenUsageUpdated = "taskTokenUsageUpdated",
TaskToolFailed = "taskToolFailed",
}
+/**
+ * IpcMessage
+ */
+declare enum IpcMessageType {
+ Connect = "Connect",
+ Disconnect = "Disconnect",
+ Ack = "Ack",
+ TaskCommand = "TaskCommand",
+ TaskEvent = "TaskEvent",
+}
+declare enum IpcOrigin {
+ Client = "client",
+ Server = "server",
+}
+/**
+ * RooCodeAPI
+ */
type RooCodeSettings = GlobalSettings & ProviderSettings
interface RooCodeAPI extends EventEmitter {
/**
@@ -662,6 +1826,10 @@ interface RooCodeAPI extends EventEmitter {
* Simulates pressing the secondary button in the chat interface.
*/
pressSecondaryButton(): Promise
+ /**
+ * Returns true if the API is ready to use.
+ */
+ isReady(): boolean
/**
* Returns the current configuration.
* @returns The current configuration.
@@ -672,28 +1840,43 @@ interface RooCodeAPI extends EventEmitter {
* @param values An object containing key-value pairs to set.
*/
setConfiguration(values: RooCodeSettings): Promise
- /**
- * Creates a new API configuration profile
- * @param name The name of the profile
- * @returns The ID of the created profile
- */
- createProfile(name: string): Promise
/**
* Returns a list of all configured profile names
* @returns Array of profile names
*/
getProfiles(): string[]
/**
- * Changes the active API configuration profile
- * @param name The name of the profile to activate
+ * Returns the profile entry for a given name
+ * @param name The name of the profile
+ * @returns The profile entry, or undefined if the profile does not exist
+ */
+ getProfileEntry(name: string): ProviderSettingsEntry | undefined
+ /**
+ * Creates a new API configuration profile
+ * @param name The name of the profile
+ * @param profile The profile to create; defaults to an empty object
+ * @param activate Whether to activate the profile after creation; defaults to true
+ * @returns The ID of the created profile
+ * @throws Error if the profile already exists
+ */
+ createProfile(name: string, profile?: ProviderSettings, activate?: boolean): Promise
+ /**
+ * Updates an existing API configuration profile
+ * @param name The name of the profile
+ * @param profile The profile to update
+ * @param activate Whether to activate the profile after update; defaults to true
+ * @returns The ID of the updated profile
* @throws Error if the profile does not exist
*/
- setActiveProfile(name: string): Promise
+ updateProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise
/**
- * Returns the name of the currently active profile
- * @returns The profile name, or undefined if no profile is active
+ * Creates a new API configuration profile or updates an existing one
+ * @param name The name of the profile
+ * @param profile The profile to create or update; defaults to an empty object
+ * @param activate Whether to activate the profile after upsert; defaults to true
+ * @returns The ID of the upserted profile
*/
- getActiveProfile(): string | undefined
+ upsertProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise
/**
* Deletes a profile by name
* @param name The name of the profile to delete
@@ -701,18 +1884,49 @@ interface RooCodeAPI extends EventEmitter {
*/
deleteProfile(name: string): Promise
/**
- * Returns true if the API is ready to use.
+ * Returns the name of the currently active profile
+ * @returns The profile name, or undefined if no profile is active
*/
- isReady(): boolean
+ getActiveProfile(): string | undefined
+ /**
+ * Changes the active API configuration profile
+ * @param name The name of the profile to activate
+ * @throws Error if the profile does not exist
+ */
+ setActiveProfile(name: string): Promise
+}
+/**
+ * RooCodeIpcServer
+ */
+type IpcServerEvents = {
+ [IpcMessageType.Connect]: [clientId: string]
+ [IpcMessageType.Disconnect]: [clientId: string]
+ [IpcMessageType.TaskCommand]: [clientId: string, data: TaskCommand]
+ [IpcMessageType.TaskEvent]: [relayClientId: string | undefined, data: TaskEvent]
+}
+interface RooCodeIpcServer extends EventEmitter {
+ listen(): void
+ broadcast(message: IpcMessage): void
+ send(client: string | Socket, message: IpcMessage): void
+ get socketPath(): string
+ get isListening(): boolean
}
export {
type ClineMessage,
type GlobalSettings,
+ type IpcMessage,
+ IpcMessageType,
+ IpcOrigin,
+ type IpcServerEvents,
type ProviderSettings,
+ type ProviderSettingsEntry,
type RooCodeAPI,
RooCodeEventName,
type RooCodeEvents,
+ type RooCodeIpcServer,
type RooCodeSettings,
+ type TaskCommand,
+ type TaskEvent,
type TokenUsage,
}
diff --git a/src/exports/types.ts b/src/exports/types.ts
index e964fdbe46c..9d8aad755ec 100644
--- a/src/exports/types.ts
+++ b/src/exports/types.ts
@@ -1,6 +1,190 @@
// This file is automatically generated by running `npm run generate-types`
// Do not edit it directly.
+type GlobalSettings = {
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ rateLimitSeconds?: number | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+}
+
+export type { GlobalSettings }
+
type ProviderSettings = {
apiProvider?:
| (
@@ -23,8 +207,19 @@ type ProviderSettings = {
| "fake-ai"
| "pearai"
| "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
)
| undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
apiModelId?: string | undefined
apiKey?: string | undefined
anthropicBaseUrl?: string | undefined
@@ -42,7 +237,6 @@ type ProviderSettings = {
awsRegion?: string | undefined
awsUseCrossRegionInference?: boolean | undefined
awsUsePromptCache?: boolean | undefined
- awspromptCacheId?: string | undefined
awsProfile?: string | undefined
awsUseProfile?: boolean | undefined
awsCustomArn?: string | undefined
@@ -63,7 +257,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -122,16 +315,6 @@ type ProviderSettings = {
unboundModelId?: string | undefined
requestyApiKey?: string | undefined
requestyModelId?: string | undefined
- xaiApiKey?: string | undefined
- modelMaxTokens?: number | undefined
- modelMaxThinkingTokens?: number | undefined
- includeMaxTokens?: boolean | undefined
- reasoningEffort?: ("low" | "medium" | "high") | undefined
- promptCachingEnabled?: boolean | undefined
- diffEnabled?: boolean | undefined
- fuzzyMatchThreshold?: number | undefined
- modelTemperature?: (number | null) | undefined
- rateLimitSeconds?: number | undefined
fakeAi?: unknown | undefined
pearaiBaseUrl?: string | undefined
pearaiModelId?: string | undefined
@@ -144,7 +327,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -177,7 +359,6 @@ type ProviderSettings = {
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
supportsPromptCache: boolean
- isPromptCacheOptional?: boolean | undefined
inputPrice?: number | undefined
outputPrice?: number | undefined
cacheWritesPrice?: number | undefined
@@ -210,186 +391,48 @@ type ProviderSettings = {
newProjectPath?: string | undefined
}
| undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
}
export type { ProviderSettings }
-type GlobalSettings = {
- currentApiConfigName?: string | undefined
- listApiConfigMeta?:
- | {
- id: string
- name: string
- apiProvider?:
- | (
- | "anthropic"
- | "glama"
- | "openrouter"
- | "bedrock"
- | "vertex"
- | "openai"
- | "ollama"
- | "vscode-lm"
- | "lmstudio"
- | "gemini"
- | "openai-native"
- | "mistral"
- | "deepseek"
- | "unbound"
- | "requesty"
- | "human-relay"
- | "fake-ai"
- | "pearai"
- | "xai"
- )
- | undefined
- }[]
- | undefined
- pinnedApiConfigs?:
- | {
- [x: string]: boolean
- }
- | undefined
- lastShownAnnouncementId?: string | undefined
- customInstructions?: string | undefined
- taskHistory?:
- | {
- id: string
- number: number
- ts: number
- task: string
- tokensIn: number
- tokensOut: number
- cacheWrites?: number | undefined
- cacheReads?: number | undefined
- totalCost: number
- size?: number | undefined
- workspace?: string | undefined
- creatorModeConfig?:
- | {
- creatorMode?: boolean | undefined
- newProjectType?: string | undefined
- newProjectPath?: string | undefined
- }
- | undefined
- }[]
- | undefined
- autoApprovalEnabled?: boolean | undefined
- alwaysAllowReadOnly?: boolean | undefined
- alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
- alwaysAllowWrite?: boolean | undefined
- alwaysAllowWriteOutsideWorkspace?: boolean | undefined
- writeDelayMs?: number | undefined
- alwaysAllowBrowser?: boolean | undefined
- alwaysApproveResubmit?: boolean | undefined
- requestDelaySeconds?: number | undefined
- alwaysAllowMcp?: boolean | undefined
- alwaysAllowModeSwitch?: boolean | undefined
- alwaysAllowSubtasks?: boolean | undefined
- alwaysAllowExecute?: boolean | undefined
- allowedCommands?: string[] | undefined
- browserToolEnabled?: boolean | undefined
- browserViewportSize?: string | undefined
- screenshotQuality?: number | undefined
- remoteBrowserEnabled?: boolean | undefined
- remoteBrowserHost?: string | undefined
- cachedChromeHostUrl?: string | undefined
- enableCheckpoints?: boolean | undefined
- ttsEnabled?: boolean | undefined
- ttsSpeed?: number | undefined
- soundEnabled?: boolean | undefined
- soundVolume?: number | undefined
- maxOpenTabsContext?: number | undefined
- maxWorkspaceFiles?: number | undefined
- showRooIgnoredFiles?: boolean | undefined
- maxReadFileLine?: number | undefined
- terminalOutputLineLimit?: number | undefined
- terminalShellIntegrationTimeout?: number | undefined
- terminalShellIntegrationDisabled?: boolean | undefined
- terminalCommandDelay?: number | undefined
- terminalPowershellCounter?: boolean | undefined
- terminalZshClearEolMark?: boolean | undefined
- terminalZshOhMy?: boolean | undefined
- terminalZshP10k?: boolean | undefined
- terminalZdotdir?: boolean | undefined
- terminalCompressProgressBar?: boolean | undefined
- rateLimitSeconds?: number | undefined
- diffEnabled?: boolean | undefined
- fuzzyMatchThreshold?: number | undefined
- experiments?:
- | {
- powerSteering: boolean
- }
- | undefined
- language?:
+type ProviderSettingsEntry = {
+ id: string
+ name: string
+ apiProvider?:
| (
- | "ca"
- | "de"
- | "en"
- | "es"
- | "fr"
- | "hi"
- | "it"
- | "ja"
- | "ko"
- | "pl"
- | "pt-BR"
- | "ru"
- | "tr"
- | "vi"
- | "zh-CN"
- | "zh-TW"
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
)
| undefined
- telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
- mcpEnabled?: boolean | undefined
- enableMcpServerCreation?: boolean | undefined
- mode?: string | undefined
- modeApiConfigs?:
- | {
- [x: string]: string
- }
- | undefined
- customModes?:
- | {
- slug: string
- name: string
- roleDefinition: string
- customInstructions?: string | undefined
- groups: (
- | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
- | [
- "read" | "edit" | "browser" | "command" | "mcp" | "modes",
- {
- fileRegex?: string | undefined
- description?: string | undefined
- },
- ]
- )[]
- source?: ("global" | "project") | undefined
- backendOnly?: boolean | undefined
- }[]
- | undefined
- customModePrompts?:
- | {
- [x: string]:
- | {
- roleDefinition?: string | undefined
- customInstructions?: string | undefined
- }
- | undefined
- }
- | undefined
- customSupportPrompts?:
- | {
- [x: string]: string | undefined
- }
- | undefined
- enhancementApiConfigId?: string | undefined
- historyPreviewCollapsed?: boolean | undefined
}
-export type { GlobalSettings }
+export type { ProviderSettingsEntry }
type ClineMessage = {
ts: number
@@ -446,7 +489,6 @@ type ClineMessage = {
| undefined
progressStatus?:
| {
- id?: string | undefined
icon?: string | undefined
text?: string | undefined
}
@@ -526,7 +568,6 @@ type RooCodeEvents = {
| undefined
progressStatus?:
| {
- id?: string | undefined
icon?: string | undefined
text?: string | undefined
}
@@ -596,3 +637,1116 @@ type RooCodeEvents = {
}
export type { RooCodeEvents }
+
+type IpcMessage =
+ | {
+ type: "Ack"
+ origin: "server"
+ data: {
+ clientId: string
+ pid: number
+ ppid: number
+ }
+ }
+ | {
+ type: "TaskCommand"
+ origin: "client"
+ clientId: string
+ data:
+ | {
+ commandName: "StartNewTask"
+ data: {
+ configuration: {
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
+ apiModelId?: string | undefined
+ apiKey?: string | undefined
+ anthropicBaseUrl?: string | undefined
+ anthropicUseAuthToken?: boolean | undefined
+ glamaModelId?: string | undefined
+ glamaApiKey?: string | undefined
+ openRouterApiKey?: string | undefined
+ openRouterModelId?: string | undefined
+ openRouterBaseUrl?: string | undefined
+ openRouterSpecificProvider?: string | undefined
+ openRouterUseMiddleOutTransform?: boolean | undefined
+ awsAccessKey?: string | undefined
+ awsSecretKey?: string | undefined
+ awsSessionToken?: string | undefined
+ awsRegion?: string | undefined
+ awsUseCrossRegionInference?: boolean | undefined
+ awsUsePromptCache?: boolean | undefined
+ awsProfile?: string | undefined
+ awsUseProfile?: boolean | undefined
+ awsCustomArn?: string | undefined
+ vertexKeyFile?: string | undefined
+ vertexJsonCredentials?: string | undefined
+ vertexProjectId?: string | undefined
+ vertexRegion?: string | undefined
+ openAiBaseUrl?: string | undefined
+ openAiApiKey?: string | undefined
+ openAiLegacyFormat?: boolean | undefined
+ openAiR1FormatEnabled?: boolean | undefined
+ openAiModelId?: string | undefined
+ openAiCustomModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ openAiUseAzure?: boolean | undefined
+ azureApiVersion?: string | undefined
+ openAiStreamingEnabled?: boolean | undefined
+ enableReasoningEffort?: boolean | undefined
+ openAiHostHeader?: string | undefined
+ openAiHeaders?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ ollamaModelId?: string | undefined
+ ollamaBaseUrl?: string | undefined
+ vsCodeLmModelSelector?:
+ | {
+ vendor?: string | undefined
+ family?: string | undefined
+ version?: string | undefined
+ id?: string | undefined
+ }
+ | undefined
+ lmStudioModelId?: string | undefined
+ lmStudioBaseUrl?: string | undefined
+ lmStudioDraftModelId?: string | undefined
+ lmStudioSpeculativeDecodingEnabled?: boolean | undefined
+ geminiApiKey?: string | undefined
+ googleGeminiBaseUrl?: string | undefined
+ openAiNativeApiKey?: string | undefined
+ openAiNativeBaseUrl?: string | undefined
+ mistralApiKey?: string | undefined
+ mistralCodestralUrl?: string | undefined
+ deepSeekBaseUrl?: string | undefined
+ deepSeekApiKey?: string | undefined
+ unboundApiKey?: string | undefined
+ unboundModelId?: string | undefined
+ requestyApiKey?: string | undefined
+ requestyModelId?: string | undefined
+ fakeAi?: unknown | undefined
+ pearaiBaseUrl?: string | undefined
+ pearaiModelId?: string | undefined
+ pearaiApiKey?: string | undefined
+ pearaiModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ pearaiAgentModels?:
+ | {
+ models: {
+ [x: string]: {
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ }
+ }
+ defaultModelId?: string | undefined
+ }
+ | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+ }
+ text: string
+ images?: string[] | undefined
+ newTab?: boolean | undefined
+ }
+ }
+ | {
+ commandName: "CancelTask"
+ data: string
+ }
+ | {
+ commandName: "CloseTask"
+ data: string
+ }
+ }
+ | {
+ type: "TaskEvent"
+ origin: "server"
+ relayClientId?: string | undefined
+ data:
+ | {
+ eventName: "message"
+ payload: [
+ {
+ taskId: string
+ action: "created" | "updated"
+ message: {
+ ts: number
+ type: "ask" | "say"
+ ask?:
+ | (
+ | "followup"
+ | "command"
+ | "command_output"
+ | "completion_result"
+ | "tool"
+ | "api_req_failed"
+ | "resume_task"
+ | "resume_completed_task"
+ | "mistake_limit_reached"
+ | "browser_action_launch"
+ | "use_mcp_server"
+ )
+ | undefined
+ say?:
+ | (
+ | "error"
+ | "api_req_started"
+ | "api_req_finished"
+ | "api_req_retried"
+ | "api_req_retry_delayed"
+ | "api_req_deleted"
+ | "text"
+ | "reasoning"
+ | "completion_result"
+ | "user_feedback"
+ | "user_feedback_diff"
+ | "command_output"
+ | "shell_integration_warning"
+ | "browser_action"
+ | "browser_action_result"
+ | "mcp_server_request_started"
+ | "mcp_server_response"
+ | "subtask_result"
+ | "checkpoint_saved"
+ | "rooignore_error"
+ | "diff_error"
+ )
+ | undefined
+ text?: string | undefined
+ images?: string[] | undefined
+ partial?: boolean | undefined
+ reasoning?: string | undefined
+ conversationHistoryIndex?: number | undefined
+ checkpoint?:
+ | {
+ [x: string]: unknown
+ }
+ | undefined
+ progressStatus?:
+ | {
+ icon?: string | undefined
+ text?: string | undefined
+ }
+ | undefined
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskCreated"
+ payload: [string]
+ }
+ | {
+ eventName: "taskStarted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskModeSwitched"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskPaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskUnpaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAskResponded"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAborted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskSpawned"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskCompleted"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ {
+ [x: string]: {
+ attempts: number
+ failures: number
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskTokenUsageUpdated"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ ]
+ }
+ }
+
+export type { IpcMessage }
+
+type TaskCommand =
+ | {
+ commandName: "StartNewTask"
+ data: {
+ configuration: {
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ includeMaxTokens?: boolean | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ diffEnabled?: boolean | undefined
+ fuzzyMatchThreshold?: number | undefined
+ modelTemperature?: (number | null) | undefined
+ rateLimitSeconds?: number | undefined
+ modelMaxTokens?: number | undefined
+ modelMaxThinkingTokens?: number | undefined
+ apiModelId?: string | undefined
+ apiKey?: string | undefined
+ anthropicBaseUrl?: string | undefined
+ anthropicUseAuthToken?: boolean | undefined
+ glamaModelId?: string | undefined
+ glamaApiKey?: string | undefined
+ openRouterApiKey?: string | undefined
+ openRouterModelId?: string | undefined
+ openRouterBaseUrl?: string | undefined
+ openRouterSpecificProvider?: string | undefined
+ openRouterUseMiddleOutTransform?: boolean | undefined
+ awsAccessKey?: string | undefined
+ awsSecretKey?: string | undefined
+ awsSessionToken?: string | undefined
+ awsRegion?: string | undefined
+ awsUseCrossRegionInference?: boolean | undefined
+ awsUsePromptCache?: boolean | undefined
+ awsProfile?: string | undefined
+ awsUseProfile?: boolean | undefined
+ awsCustomArn?: string | undefined
+ vertexKeyFile?: string | undefined
+ vertexJsonCredentials?: string | undefined
+ vertexProjectId?: string | undefined
+ vertexRegion?: string | undefined
+ openAiBaseUrl?: string | undefined
+ openAiApiKey?: string | undefined
+ openAiLegacyFormat?: boolean | undefined
+ openAiR1FormatEnabled?: boolean | undefined
+ openAiModelId?: string | undefined
+ openAiCustomModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ openAiUseAzure?: boolean | undefined
+ azureApiVersion?: string | undefined
+ openAiStreamingEnabled?: boolean | undefined
+ enableReasoningEffort?: boolean | undefined
+ openAiHostHeader?: string | undefined
+ openAiHeaders?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ ollamaModelId?: string | undefined
+ ollamaBaseUrl?: string | undefined
+ vsCodeLmModelSelector?:
+ | {
+ vendor?: string | undefined
+ family?: string | undefined
+ version?: string | undefined
+ id?: string | undefined
+ }
+ | undefined
+ lmStudioModelId?: string | undefined
+ lmStudioBaseUrl?: string | undefined
+ lmStudioDraftModelId?: string | undefined
+ lmStudioSpeculativeDecodingEnabled?: boolean | undefined
+ geminiApiKey?: string | undefined
+ googleGeminiBaseUrl?: string | undefined
+ openAiNativeApiKey?: string | undefined
+ openAiNativeBaseUrl?: string | undefined
+ mistralApiKey?: string | undefined
+ mistralCodestralUrl?: string | undefined
+ deepSeekBaseUrl?: string | undefined
+ deepSeekApiKey?: string | undefined
+ unboundApiKey?: string | undefined
+ unboundModelId?: string | undefined
+ requestyApiKey?: string | undefined
+ requestyModelId?: string | undefined
+ fakeAi?: unknown | undefined
+ pearaiBaseUrl?: string | undefined
+ pearaiModelId?: string | undefined
+ pearaiApiKey?: string | undefined
+ pearaiModelInfo?:
+ | ({
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ } | null)
+ | undefined
+ pearaiAgentModels?:
+ | {
+ models: {
+ [x: string]: {
+ maxTokens?: (number | null) | undefined
+ maxThinkingTokens?: (number | null) | undefined
+ contextWindow: number
+ supportsImages?: boolean | undefined
+ supportsComputerUse?: boolean | undefined
+ supportsPromptCache: boolean
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ description?: string | undefined
+ reasoningEffort?: ("low" | "medium" | "high") | undefined
+ thinking?: boolean | undefined
+ minTokensPerCachePoint?: number | undefined
+ maxCachePoints?: number | undefined
+ cachableFields?: string[] | undefined
+ underlyingModel?: string | undefined
+ tiers?:
+ | {
+ contextWindow: number
+ inputPrice?: number | undefined
+ outputPrice?: number | undefined
+ cacheWritesPrice?: number | undefined
+ cacheReadsPrice?: number | undefined
+ }[]
+ | undefined
+ }
+ }
+ defaultModelId?: string | undefined
+ }
+ | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ xaiApiKey?: string | undefined
+ groqApiKey?: string | undefined
+ chutesApiKey?: string | undefined
+ litellmBaseUrl?: string | undefined
+ litellmApiKey?: string | undefined
+ litellmModelId?: string | undefined
+ currentApiConfigName?: string | undefined
+ listApiConfigMeta?:
+ | {
+ id: string
+ name: string
+ apiProvider?:
+ | (
+ | "anthropic"
+ | "glama"
+ | "openrouter"
+ | "bedrock"
+ | "vertex"
+ | "openai"
+ | "ollama"
+ | "vscode-lm"
+ | "lmstudio"
+ | "gemini"
+ | "openai-native"
+ | "mistral"
+ | "deepseek"
+ | "unbound"
+ | "requesty"
+ | "human-relay"
+ | "fake-ai"
+ | "pearai"
+ | "xai"
+ | "groq"
+ | "chutes"
+ | "litellm"
+ )
+ | undefined
+ }[]
+ | undefined
+ pinnedApiConfigs?:
+ | {
+ [x: string]: boolean
+ }
+ | undefined
+ lastShownAnnouncementId?: string | undefined
+ customInstructions?: string | undefined
+ taskHistory?:
+ | {
+ id: string
+ number: number
+ ts: number
+ task: string
+ tokensIn: number
+ tokensOut: number
+ cacheWrites?: number | undefined
+ cacheReads?: number | undefined
+ totalCost: number
+ size?: number | undefined
+ workspace?: string | undefined
+ creatorModeConfig?:
+ | {
+ creatorMode?: boolean | undefined
+ newProjectType?: string | undefined
+ newProjectPath?: string | undefined
+ }
+ | undefined
+ }[]
+ | undefined
+ autoApprovalEnabled?: boolean | undefined
+ alwaysAllowReadOnly?: boolean | undefined
+ alwaysAllowReadOnlyOutsideWorkspace?: boolean | undefined
+ alwaysAllowWrite?: boolean | undefined
+ alwaysAllowWriteOutsideWorkspace?: boolean | undefined
+ writeDelayMs?: number | undefined
+ alwaysAllowBrowser?: boolean | undefined
+ alwaysApproveResubmit?: boolean | undefined
+ requestDelaySeconds?: number | undefined
+ alwaysAllowMcp?: boolean | undefined
+ alwaysAllowModeSwitch?: boolean | undefined
+ alwaysAllowSubtasks?: boolean | undefined
+ alwaysAllowExecute?: boolean | undefined
+ allowedCommands?: string[] | undefined
+ browserToolEnabled?: boolean | undefined
+ browserViewportSize?: string | undefined
+ screenshotQuality?: number | undefined
+ remoteBrowserEnabled?: boolean | undefined
+ remoteBrowserHost?: string | undefined
+ cachedChromeHostUrl?: string | undefined
+ enableCheckpoints?: boolean | undefined
+ ttsEnabled?: boolean | undefined
+ ttsSpeed?: number | undefined
+ soundEnabled?: boolean | undefined
+ soundVolume?: number | undefined
+ maxOpenTabsContext?: number | undefined
+ maxWorkspaceFiles?: number | undefined
+ showRooIgnoredFiles?: boolean | undefined
+ maxReadFileLine?: number | undefined
+ terminalOutputLineLimit?: number | undefined
+ terminalShellIntegrationTimeout?: number | undefined
+ terminalShellIntegrationDisabled?: boolean | undefined
+ terminalCommandDelay?: number | undefined
+ terminalPowershellCounter?: boolean | undefined
+ terminalZshClearEolMark?: boolean | undefined
+ terminalZshOhMy?: boolean | undefined
+ terminalZshP10k?: boolean | undefined
+ terminalZdotdir?: boolean | undefined
+ terminalCompressProgressBar?: boolean | undefined
+ experiments?:
+ | {
+ autoCondenseContext: boolean
+ powerSteering: boolean
+ }
+ | undefined
+ language?:
+ | (
+ | "ca"
+ | "de"
+ | "en"
+ | "es"
+ | "fr"
+ | "hi"
+ | "it"
+ | "ja"
+ | "ko"
+ | "nl"
+ | "pl"
+ | "pt-BR"
+ | "ru"
+ | "tr"
+ | "vi"
+ | "zh-CN"
+ | "zh-TW"
+ )
+ | undefined
+ telemetrySetting?: ("unset" | "enabled" | "disabled") | undefined
+ mcpEnabled?: boolean | undefined
+ enableMcpServerCreation?: boolean | undefined
+ mode?: string | undefined
+ modeApiConfigs?:
+ | {
+ [x: string]: string
+ }
+ | undefined
+ customModes?:
+ | {
+ slug: string
+ name: string
+ roleDefinition: string
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ groups: (
+ | ("read" | "edit" | "browser" | "command" | "mcp" | "modes")
+ | [
+ "read" | "edit" | "browser" | "command" | "mcp" | "modes",
+ {
+ fileRegex?: string | undefined
+ description?: string | undefined
+ },
+ ]
+ )[]
+ source?: ("global" | "project") | undefined
+ backendOnly?: boolean | undefined
+ }[]
+ | undefined
+ customModePrompts?:
+ | {
+ [x: string]:
+ | {
+ roleDefinition?: string | undefined
+ whenToUse?: string | undefined
+ customInstructions?: string | undefined
+ }
+ | undefined
+ }
+ | undefined
+ customSupportPrompts?:
+ | {
+ [x: string]: string | undefined
+ }
+ | undefined
+ enhancementApiConfigId?: string | undefined
+ historyPreviewCollapsed?: boolean | undefined
+ }
+ text: string
+ images?: string[] | undefined
+ newTab?: boolean | undefined
+ }
+ }
+ | {
+ commandName: "CancelTask"
+ data: string
+ }
+ | {
+ commandName: "CloseTask"
+ data: string
+ }
+
+export type { TaskCommand }
+
+type TaskEvent =
+ | {
+ eventName: "message"
+ payload: [
+ {
+ taskId: string
+ action: "created" | "updated"
+ message: {
+ ts: number
+ type: "ask" | "say"
+ ask?:
+ | (
+ | "followup"
+ | "command"
+ | "command_output"
+ | "completion_result"
+ | "tool"
+ | "api_req_failed"
+ | "resume_task"
+ | "resume_completed_task"
+ | "mistake_limit_reached"
+ | "browser_action_launch"
+ | "use_mcp_server"
+ )
+ | undefined
+ say?:
+ | (
+ | "error"
+ | "api_req_started"
+ | "api_req_finished"
+ | "api_req_retried"
+ | "api_req_retry_delayed"
+ | "api_req_deleted"
+ | "text"
+ | "reasoning"
+ | "completion_result"
+ | "user_feedback"
+ | "user_feedback_diff"
+ | "command_output"
+ | "shell_integration_warning"
+ | "browser_action"
+ | "browser_action_result"
+ | "mcp_server_request_started"
+ | "mcp_server_response"
+ | "subtask_result"
+ | "checkpoint_saved"
+ | "rooignore_error"
+ | "diff_error"
+ )
+ | undefined
+ text?: string | undefined
+ images?: string[] | undefined
+ partial?: boolean | undefined
+ reasoning?: string | undefined
+ conversationHistoryIndex?: number | undefined
+ checkpoint?:
+ | {
+ [x: string]: unknown
+ }
+ | undefined
+ progressStatus?:
+ | {
+ icon?: string | undefined
+ text?: string | undefined
+ }
+ | undefined
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskCreated"
+ payload: [string]
+ }
+ | {
+ eventName: "taskStarted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskModeSwitched"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskPaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskUnpaused"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAskResponded"
+ payload: [string]
+ }
+ | {
+ eventName: "taskAborted"
+ payload: [string]
+ }
+ | {
+ eventName: "taskSpawned"
+ payload: [string, string]
+ }
+ | {
+ eventName: "taskCompleted"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ {
+ [x: string]: {
+ attempts: number
+ failures: number
+ }
+ },
+ ]
+ }
+ | {
+ eventName: "taskTokenUsageUpdated"
+ payload: [
+ string,
+ {
+ totalTokensIn: number
+ totalTokensOut: number
+ totalCacheWrites?: number | undefined
+ totalCacheReads?: number | undefined
+ totalCost: number
+ contextTokens: number
+ },
+ ]
+ }
+
+export type { TaskEvent }
diff --git a/src/extension.ts b/src/extension.ts
index 94085091801..7ed49577b22 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -15,25 +15,25 @@ try {
import "./utils/path" // Necessary to have access to String.prototype.toPosix.
-import { initializeI18n } from "./i18n"
import { ContextProxy } from "./core/config/ContextProxy"
import { ClineProvider } from "./core/webview/ClineProvider"
-import { CodeActionProvider } from "./core/CodeActionProvider"
import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
+import { TerminalRegistry } from "./integrations/terminal/TerminalRegistry"
import { McpServerManager } from "./services/mcp/McpServerManager"
import { telemetryService } from "./services/telemetry/TelemetryService"
-import { TerminalRegistry } from "./integrations/terminal/TerminalRegistry"
import { API } from "./exports/api"
import { migrateSettings } from "./utils/migrateSettings"
+import { formatLanguage } from "./shared/language"
import {
handleUri,
registerCommands,
registerCodeActions,
registerTerminalActions,
+ CodeActionProvider,
registerPearListener,
} from "./activate"
-import { formatLanguage } from "./shared/language"
+import { initializeI18n } from "./i18n"
/**
* Built using https://github.com/microsoft/vscode-webview-ui-toolkit
diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json
index 3f9cd4bdb83..af6aed5aa2b 100644
--- a/src/i18n/locales/ca/common.json
+++ b/src/i18n/locales/ca/common.json
@@ -89,5 +89,11 @@
"path_placeholder": "D:\\RooCodeStorage",
"enter_absolute_path": "Introdueix una ruta completa (p. ex. D:\\RooCodeStorage o /home/user/storage)",
"enter_valid_path": "Introdueix una ruta vàlida"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Clau API de Groq",
+ "getGroqApiKey": "Obté la clau API de Groq"
+ }
}
}
diff --git a/src/i18n/locales/ca/tools.json b/src/i18n/locales/ca/tools.json
index 14e7e438808..c0d8ac20afd 100644
--- a/src/i18n/locales/ca/tools.json
+++ b/src/i18n/locales/ca/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (línies 1-{{end}})",
"definitionsOnly": " (només definicions)",
"maxLines": " (màxim {{max}} línies)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo sembla estar atrapat en un bucle, intentant la mateixa acció ({{toolName}}) repetidament. Això podria indicar un problema amb la seva estratègia actual. Considera reformular la tasca, proporcionar instruccions més específiques o guiar-lo cap a un enfocament diferent."
}
diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json
index efee4e28623..b3d7abb18a3 100644
--- a/src/i18n/locales/de/common.json
+++ b/src/i18n/locales/de/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Was soll Roo tun?",
"task_placeholder": "Gib deine Aufgabe hier ein"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq API-Schlüssel",
+ "getGroqApiKey": "Groq API-Schlüssel erhalten"
+ }
}
}
diff --git a/src/i18n/locales/de/tools.json b/src/i18n/locales/de/tools.json
index f1b7d850325..e4cb085141d 100644
--- a/src/i18n/locales/de/tools.json
+++ b/src/i18n/locales/de/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (Zeilen 1-{{end}})",
"definitionsOnly": " (nur Definitionen)",
"maxLines": " (maximal {{max}} Zeilen)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo scheint in einer Schleife festzustecken und versucht wiederholt dieselbe Aktion ({{toolName}}). Dies könnte auf ein Problem mit der aktuellen Strategie hindeuten. Überlege dir, die Aufgabe umzuformulieren, genauere Anweisungen zu geben oder Roo zu einem anderen Ansatz zu führen."
}
diff --git a/src/i18n/locales/en/tools.json b/src/i18n/locales/en/tools.json
index bb258961ba9..70b0e8d9643 100644
--- a/src/i18n/locales/en/tools.json
+++ b/src/i18n/locales/en/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (lines 1-{{end}})",
"definitionsOnly": " (definitions only)",
"maxLines": " (max {{max}} lines)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo appears to be stuck in a loop, attempting the same action ({{toolName}}) repeatedly. This might indicate a problem with its current strategy. Consider rephrasing the task, providing more specific instructions, or guiding it towards a different approach."
}
diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json
index 4a9b82e0be9..005524b0771 100644
--- a/src/i18n/locales/es/common.json
+++ b/src/i18n/locales/es/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "¿Qué debe hacer Roo?",
"task_placeholder": "Escribe tu tarea aquí"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Clave API de Groq",
+ "getGroqApiKey": "Obtener clave API de Groq"
+ }
}
}
diff --git a/src/i18n/locales/es/tools.json b/src/i18n/locales/es/tools.json
index f6e4389206d..e5e7b86627f 100644
--- a/src/i18n/locales/es/tools.json
+++ b/src/i18n/locales/es/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (líneas 1-{{end}})",
"definitionsOnly": " (solo definiciones)",
"maxLines": " (máximo {{max}} líneas)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo parece estar atrapado en un bucle, intentando la misma acción ({{toolName}}) repetidamente. Esto podría indicar un problema con su estrategia actual. Considera reformular la tarea, proporcionar instrucciones más específicas o guiarlo hacia un enfoque diferente."
}
diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json
index 55e172100ee..c20650fd789 100644
--- a/src/i18n/locales/fr/common.json
+++ b/src/i18n/locales/fr/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Que doit faire Roo ?",
"task_placeholder": "Écris ta tâche ici"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Clé API Groq",
+ "getGroqApiKey": "Obtenir la clé API Groq"
+ }
}
}
diff --git a/src/i18n/locales/fr/tools.json b/src/i18n/locales/fr/tools.json
index 97a640a18f9..777727c34e1 100644
--- a/src/i18n/locales/fr/tools.json
+++ b/src/i18n/locales/fr/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (lignes 1-{{end}})",
"definitionsOnly": " (définitions uniquement)",
"maxLines": " (max {{max}} lignes)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo semble être bloqué dans une boucle, tentant la même action ({{toolName}}) de façon répétée. Cela pourrait indiquer un problème avec sa stratégie actuelle. Envisage de reformuler la tâche, de fournir des instructions plus spécifiques ou de le guider vers une approche différente."
}
diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json
index e4f3a51ebb8..cba7456dd52 100644
--- a/src/i18n/locales/hi/common.json
+++ b/src/i18n/locales/hi/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Agent को क्या करना है?",
"task_placeholder": "अपना कार्य यहाँ लिखें"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "ग्रोक एपीआई कुंजी",
+ "getGroqApiKey": "ग्रोक एपीआई कुंजी प्राप्त करें"
+ }
}
}
diff --git a/src/i18n/locales/hi/tools.json b/src/i18n/locales/hi/tools.json
index 7f682391f49..7784f70480f 100644
--- a/src/i18n/locales/hi/tools.json
+++ b/src/i18n/locales/hi/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (पंक्तियाँ 1-{{end}})",
"definitionsOnly": " (केवल परिभाषाएँ)",
"maxLines": " (अधिकतम {{max}} पंक्तियाँ)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo एक लूप में फंसा हुआ लगता है, बार-बार एक ही क्रिया ({{toolName}}) को दोहरा रहा है। यह उसकी वर्तमान रणनीति में किसी समस्या का संकेत हो सकता है। कार्य को पुनः परिभाषित करने, अधिक विशिष्ट निर्देश देने, या उसे एक अलग दृष्टिकोण की ओर मार्गदर्शित करने पर विचार करें।"
}
diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json
index 94dda7ea3f1..c5335a1bbef 100644
--- a/src/i18n/locales/it/common.json
+++ b/src/i18n/locales/it/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Cosa deve fare Roo?",
"task_placeholder": "Scrivi il tuo compito qui"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Chiave API Groq",
+ "getGroqApiKey": "Ottieni chiave API Groq"
+ }
}
}
diff --git a/src/i18n/locales/it/tools.json b/src/i18n/locales/it/tools.json
index a9ad538e9de..a639137eb81 100644
--- a/src/i18n/locales/it/tools.json
+++ b/src/i18n/locales/it/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (righe 1-{{end}})",
"definitionsOnly": " (solo definizioni)",
"maxLines": " (max {{max}} righe)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo sembra essere bloccato in un ciclo, tentando ripetutamente la stessa azione ({{toolName}}). Questo potrebbe indicare un problema con la sua strategia attuale. Considera di riformulare l'attività, fornire istruzioni più specifiche o guidarlo verso un approccio diverso."
}
diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json
index dc6a9da9299..0aa3615e7df 100644
--- a/src/i18n/locales/ja/common.json
+++ b/src/i18n/locales/ja/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Rooにどんなことをさせますか?",
"task_placeholder": "タスクをここに入力してください"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq APIキー",
+ "getGroqApiKey": "Groq APIキーを取得"
+ }
}
}
diff --git a/src/i18n/locales/ja/tools.json b/src/i18n/locales/ja/tools.json
index 6daed74793f..fda79adb249 100644
--- a/src/i18n/locales/ja/tools.json
+++ b/src/i18n/locales/ja/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (1-{{end}}行目)",
"definitionsOnly": " (定義のみ)",
"maxLines": " (最大{{max}}行)"
- }
+ },
+ "toolRepetitionLimitReached": "Rooが同じ操作({{toolName}})を繰り返し試みるループに陥っているようです。これは現在の方法に問題がある可能性を示しています。タスクの言い換え、より具体的な指示の提供、または別のアプローチへの誘導を検討してください。"
}
diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json
index 8e1ba132f44..6ef9b897269 100644
--- a/src/i18n/locales/ko/common.json
+++ b/src/i18n/locales/ko/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Roo에게 무엇을 시킬까요?",
"task_placeholder": "여기에 작업을 입력하세요"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq API 키",
+ "getGroqApiKey": "Groq API 키 받기"
+ }
}
}
diff --git a/src/i18n/locales/ko/tools.json b/src/i18n/locales/ko/tools.json
index f4583d2d065..cd4679b2eb5 100644
--- a/src/i18n/locales/ko/tools.json
+++ b/src/i18n/locales/ko/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (1-{{end}}행)",
"definitionsOnly": " (정의만)",
"maxLines": " (최대 {{max}}행)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo가 같은 동작({{toolName}})을 반복적으로 시도하면서 루프에 갇힌 것 같습니다. 이는 현재 전략에 문제가 있을 수 있음을 나타냅니다. 작업을 다시 표현하거나, 더 구체적인 지침을 제공하거나, 다른 접근 방식으로 안내해 보세요."
}
diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json
new file mode 100644
index 00000000000..e676235dc2c
--- /dev/null
+++ b/src/i18n/locales/nl/common.json
@@ -0,0 +1,93 @@
+{
+ "extension": {
+ "name": "Roo Code",
+ "description": "Een compleet ontwikkelteam van AI-agenten in je editor."
+ },
+ "number_format": {
+ "thousand_suffix": "k",
+ "million_suffix": "m",
+ "billion_suffix": "mrd"
+ },
+ "welcome": "Welkom, {{name}}! Je hebt {{count}} meldingen.",
+ "items": {
+ "zero": "Geen items",
+ "one": "Eén item",
+ "other": "{{count}} items"
+ },
+ "confirmation": {
+ "reset_state": "Weet je zeker dat je alle status en geheime opslag in de extensie wilt resetten? Dit kan niet ongedaan worden gemaakt.",
+ "delete_config_profile": "Weet je zeker dat je dit configuratieprofiel wilt verwijderen?",
+ "delete_custom_mode": "Weet je zeker dat je deze aangepaste modus wilt verwijderen?",
+ "delete_message": "Wat wil je verwijderen?",
+ "just_this_message": "Alleen dit bericht",
+ "this_and_subsequent": "Dit en alle volgende berichten"
+ },
+ "errors": {
+ "invalid_mcp_config": "Ongeldig project MCP-configuratieformaat",
+ "invalid_mcp_settings_format": "Ongeldig MCP-instellingen JSON-formaat. Zorg ervoor dat je instellingen het juiste JSON-formaat volgen.",
+ "invalid_mcp_settings_syntax": "Ongeldig MCP-instellingen JSON-formaat. Controleer je instellingenbestand op syntaxfouten.",
+ "invalid_mcp_settings_validation": "Ongeldig MCP-instellingenformaat: {{errorMessages}}",
+ "failed_initialize_project_mcp": "Initialiseren van project MCP-server mislukt: {{error}}",
+ "invalid_data_uri": "Ongeldig data-URI-formaat",
+ "checkpoint_timeout": "Time-out bij het herstellen van checkpoint.",
+ "checkpoint_failed": "Herstellen van checkpoint mislukt.",
+ "no_workspace": "Open eerst een projectmap",
+ "update_support_prompt": "Bijwerken van ondersteuningsprompt mislukt",
+ "reset_support_prompt": "Resetten van ondersteuningsprompt mislukt",
+ "enhance_prompt": "Verbeteren van prompt mislukt",
+ "get_system_prompt": "Ophalen van systeemprompt mislukt",
+ "search_commits": "Zoeken naar commits mislukt",
+ "save_api_config": "Opslaan van API-configuratie mislukt",
+ "create_api_config": "Aanmaken van API-configuratie mislukt",
+ "rename_api_config": "Hernoemen van API-configuratie mislukt",
+ "load_api_config": "Laden van API-configuratie mislukt",
+ "delete_api_config": "Verwijderen van API-configuratie mislukt",
+ "list_api_config": "Ophalen van lijst met API-configuraties mislukt",
+ "update_server_timeout": "Bijwerken van server-timeout mislukt",
+ "create_mcp_json": "Aanmaken of openen van .roo/mcp.json mislukt: {{error}}",
+ "hmr_not_running": "Lokale ontwikkelserver draait niet, HMR werkt niet. Voer 'npm run dev' uit voordat je de extensie start om HMR in te schakelen.",
+ "retrieve_current_mode": "Fout: ophalen van huidige modus uit status mislukt.",
+ "failed_delete_repo": "Verwijderen van gekoppelde schaduwrepository of branch mislukt: {{error}}",
+ "failed_remove_directory": "Verwijderen van taakmap mislukt: {{error}}",
+ "custom_storage_path_unusable": "Aangepast opslagpad \"{{path}}\" is onbruikbaar, standaardpad wordt gebruikt",
+ "cannot_access_path": "Kan pad {{path}} niet openen: {{error}}",
+ "failed_update_project_mcp": "Bijwerken van project MCP-servers mislukt"
+ },
+ "warnings": {
+ "no_terminal_content": "Geen terminalinhoud geselecteerd",
+ "missing_task_files": "De bestanden van deze taak ontbreken. Wil je deze uit de takenlijst verwijderen?"
+ },
+ "info": {
+ "no_changes": "Geen wijzigingen gevonden.",
+ "clipboard_copy": "Systeemprompt succesvol gekopieerd naar klembord",
+ "history_cleanup": "{{count}} taak/taken met ontbrekende bestanden uit geschiedenis verwijderd.",
+ "mcp_server_restarting": "{{serverName}} MCP-server wordt opnieuw gestart...",
+ "mcp_server_connected": "{{serverName}} MCP-server verbonden",
+ "mcp_server_deleted": "MCP-server verwijderd: {{serverName}}",
+ "mcp_server_not_found": "Server \"{{serverName}}\" niet gevonden in configuratie",
+ "custom_storage_path_set": "Aangepast opslagpad ingesteld: {{path}}",
+ "default_storage_path": "Terug naar standaard opslagpad",
+ "settings_imported": "Instellingen succesvol geïmporteerd."
+ },
+ "answers": {
+ "yes": "Ja",
+ "no": "Nee",
+ "cancel": "Annuleren",
+ "remove": "Verwijderen",
+ "keep": "Behouden"
+ },
+ "tasks": {
+ "canceled": "Taakfout: gestopt en geannuleerd door gebruiker.",
+ "deleted": "Taakfout: gestopt en verwijderd door gebruiker."
+ },
+ "storage": {
+ "prompt_custom_path": "Voer een aangepast opslagpad voor gespreksgeschiedenis in, laat leeg voor standaardlocatie",
+ "path_placeholder": "D:\\RooCodeStorage",
+ "enter_absolute_path": "Voer een absoluut pad in (bijv. D:\\RooCodeStorage of /home/user/storage)",
+ "enter_valid_path": "Voer een geldig pad in"
+ },
+ "input": {
+ "task_prompt": "Wat moet Roo doen?",
+ "task_placeholder": "Typ hier je taak"
+ }
+}
diff --git a/src/i18n/locales/nl/tools.json b/src/i18n/locales/nl/tools.json
new file mode 100644
index 00000000000..a3f85a911e2
--- /dev/null
+++ b/src/i18n/locales/nl/tools.json
@@ -0,0 +1,10 @@
+{
+ "readFile": {
+ "linesRange": " (regels {{start}}-{{end}})",
+ "linesFromToEnd": " (regels {{start}}-einde)",
+ "linesFromStartTo": " (regels 1-{{end}})",
+ "definitionsOnly": " (alleen definities)",
+ "maxLines": " (max {{max}} regels)"
+ },
+ "toolRepetitionLimitReached": "Roo lijkt vast te zitten in een lus, waarbij hij herhaaldelijk dezelfde actie ({{toolName}}) probeert. Dit kan duiden op een probleem met de huidige strategie. Overweeg de taak te herformuleren, specifiekere instructies te geven of Roo naar een andere aanpak te leiden."
+}
diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json
index dbc459ad581..5cfb640da15 100644
--- a/src/i18n/locales/pl/common.json
+++ b/src/i18n/locales/pl/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Co ma zrobić Roo?",
"task_placeholder": "Wpisz swoje zadanie tutaj"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Klucz API Groq",
+ "getGroqApiKey": "Uzyskaj klucz API Groq"
+ }
}
}
diff --git a/src/i18n/locales/pl/tools.json b/src/i18n/locales/pl/tools.json
index 33edb77cfae..6de5cc8f789 100644
--- a/src/i18n/locales/pl/tools.json
+++ b/src/i18n/locales/pl/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (linie 1-{{end}})",
"definitionsOnly": " (tylko definicje)",
"maxLines": " (maks. {{max}} linii)"
- }
+ },
+ "toolRepetitionLimitReached": "Wygląda na to, że Roo utknął w pętli, wielokrotnie próbując wykonać tę samą akcję ({{toolName}}). Może to wskazywać na problem z jego obecną strategią. Rozważ przeformułowanie zadania, podanie bardziej szczegółowych instrukcji lub nakierowanie go na inne podejście."
}
diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json
index 0de62c10a54..386902feb47 100644
--- a/src/i18n/locales/pt-BR/common.json
+++ b/src/i18n/locales/pt-BR/common.json
@@ -89,5 +89,11 @@
"path_placeholder": "D:\\RooCodeStorage",
"enter_absolute_path": "Por favor, digite um caminho absoluto (ex: D:\\RooCodeStorage ou /home/user/storage)",
"enter_valid_path": "Por favor, digite um caminho válido"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Chave de API Groq",
+ "getGroqApiKey": "Obter chave de API Groq"
+ }
}
}
diff --git a/src/i18n/locales/pt-BR/tools.json b/src/i18n/locales/pt-BR/tools.json
index 0992809bdd0..096aadad200 100644
--- a/src/i18n/locales/pt-BR/tools.json
+++ b/src/i18n/locales/pt-BR/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (linhas 1-{{end}})",
"definitionsOnly": " (apenas definições)",
"maxLines": " (máx. {{max}} linhas)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo parece estar preso em um loop, tentando a mesma ação ({{toolName}}) repetidamente. Isso pode indicar um problema com sua estratégia atual. Considere reformular a tarefa, fornecer instruções mais específicas ou guiá-lo para uma abordagem diferente."
}
diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json
index f9f3a87b2d0..73f20cc0c09 100644
--- a/src/i18n/locales/ru/common.json
+++ b/src/i18n/locales/ru/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Что должен сделать Roo?",
"task_placeholder": "Введите вашу задачу здесь"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Ключ API Groq",
+ "getGroqApiKey": "Получить ключ API Groq"
+ }
}
}
diff --git a/src/i18n/locales/ru/tools.json b/src/i18n/locales/ru/tools.json
index 4f4aaed97ca..2968c08935b 100644
--- a/src/i18n/locales/ru/tools.json
+++ b/src/i18n/locales/ru/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (строки 1-{{end}})",
"definitionsOnly": " (только определения)",
"maxLines": " (макс. {{max}} строк)"
- }
+ },
+ "toolRepetitionLimitReached": "Похоже, что Roo застрял в цикле, многократно пытаясь выполнить одно и то же действие ({{toolName}}). Это может указывать на проблему с его текущей стратегией. Попробуйте переформулировать задачу, предоставить более конкретные инструкции или направить его к другому подходу."
}
diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json
index 0b3045166c5..eef0901e0de 100644
--- a/src/i18n/locales/tr/common.json
+++ b/src/i18n/locales/tr/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Agent ne yapsın?",
"task_placeholder": "Görevini buraya yaz"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq API Anahtarı",
+ "getGroqApiKey": "Groq API Anahtarı Al"
+ }
}
}
diff --git a/src/i18n/locales/tr/tools.json b/src/i18n/locales/tr/tools.json
index 19b0158d139..86fcada627d 100644
--- a/src/i18n/locales/tr/tools.json
+++ b/src/i18n/locales/tr/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (satır 1-{{end}})",
"definitionsOnly": " (sadece tanımlar)",
"maxLines": " (maks. {{max}} satır)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo bir döngüye takılmış gibi görünüyor, aynı eylemi ({{toolName}}) tekrar tekrar deniyor. Bu, mevcut stratejisinde bir sorun olduğunu gösterebilir. Görevi yeniden ifade etmeyi, daha spesifik talimatlar vermeyi veya onu farklı bir yaklaşıma yönlendirmeyi düşünün."
}
diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json
index 1375111ed95..c6d52b559c6 100644
--- a/src/i18n/locales/vi/common.json
+++ b/src/i18n/locales/vi/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "Bạn muốn Roo làm gì?",
"task_placeholder": "Nhập nhiệm vụ của bạn ở đây"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Khóa API Groq",
+ "getGroqApiKey": "Lấy khóa API Groq"
+ }
}
}
diff --git a/src/i18n/locales/vi/tools.json b/src/i18n/locales/vi/tools.json
index 76af39abe1f..d77fd34f1d0 100644
--- a/src/i18n/locales/vi/tools.json
+++ b/src/i18n/locales/vi/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (dòng 1-{{end}})",
"definitionsOnly": " (chỉ định nghĩa)",
"maxLines": " (tối đa {{max}} dòng)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo dường như đang bị mắc kẹt trong một vòng lặp, liên tục cố gắng thực hiện cùng một hành động ({{toolName}}). Điều này có thể cho thấy vấn đề với chiến lược hiện tại. Hãy cân nhắc việc diễn đạt lại nhiệm vụ, cung cấp hướng dẫn cụ thể hơn, hoặc hướng Roo theo một cách tiếp cận khác."
}
diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json
index 66e84d55e07..e046d15950e 100644
--- a/src/i18n/locales/zh-CN/common.json
+++ b/src/i18n/locales/zh-CN/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "让Roo做什么?",
"task_placeholder": "在这里输入任务"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq API 密钥",
+ "getGroqApiKey": "获取 Groq API 密钥"
+ }
}
}
diff --git a/src/i18n/locales/zh-CN/tools.json b/src/i18n/locales/zh-CN/tools.json
index 5f9b2ddaf74..30ca1f7ab12 100644
--- a/src/i18n/locales/zh-CN/tools.json
+++ b/src/i18n/locales/zh-CN/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (第 1-{{end}} 行)",
"definitionsOnly": " (仅定义)",
"maxLines": " (最多 {{max}} 行)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo 似乎陷入循环,反复尝试同一操作 ({{toolName}})。这可能表明当前策略存在问题。请考虑重新描述任务、提供更具体的指示或引导其尝试不同的方法。"
}
diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json
index 61f01c30622..4fd084ae681 100644
--- a/src/i18n/locales/zh-TW/common.json
+++ b/src/i18n/locales/zh-TW/common.json
@@ -89,5 +89,11 @@
"input": {
"task_prompt": "讓 Roo 做什麼?",
"task_placeholder": "在這裡輸入工作"
+ },
+ "settings": {
+ "providers": {
+ "groqApiKey": "Groq API 金鑰",
+ "getGroqApiKey": "取得 Groq API 金鑰"
+ }
}
}
diff --git a/src/i18n/locales/zh-TW/tools.json b/src/i18n/locales/zh-TW/tools.json
index d64d1cca479..2416fe57f68 100644
--- a/src/i18n/locales/zh-TW/tools.json
+++ b/src/i18n/locales/zh-TW/tools.json
@@ -5,5 +5,6 @@
"linesFromStartTo": " (第 1-{{end}} 行)",
"definitionsOnly": " (僅定義)",
"maxLines": " (最多 {{max}} 行)"
- }
+ },
+ "toolRepetitionLimitReached": "Roo 似乎陷入循環,反覆嘗試同一操作 ({{toolName}})。這可能表明目前策略存在問題。請考慮重新描述工作、提供更具體的指示或引導其嘗試不同的方法。"
}
diff --git a/src/integrations/diagnostics/__tests__/diagnostics.test.ts b/src/integrations/diagnostics/__tests__/diagnostics.test.ts
new file mode 100644
index 00000000000..3cf9ede4f65
--- /dev/null
+++ b/src/integrations/diagnostics/__tests__/diagnostics.test.ts
@@ -0,0 +1,376 @@
+import * as vscode from "vscode"
+import { diagnosticsToProblemsString } from ".."
+
+// Mock path module
+jest.mock("path", () => ({
+ relative: jest.fn((cwd, fullPath) => {
+ // Handle the specific case already present
+ if (cwd === "/project/root" && fullPath === "/project/root/src/utils/file.ts") {
+ return "src/utils/file.ts"
+ }
+ // Handle the test cases with /path/to as cwd
+ if (cwd === "/path/to") {
+ // Simple relative path calculation for the test cases
+ return fullPath.replace(cwd + "/", "")
+ }
+ // Fallback for other cases (can be adjusted if needed)
+ return fullPath
+ }),
+}))
+
+// Mock vscode module
+jest.mock("vscode", () => ({
+ Uri: {
+ file: jest.fn((path) => ({
+ fsPath: path,
+ toString: jest.fn(() => path),
+ })),
+ },
+ Diagnostic: jest.fn().mockImplementation((range, message, severity) => ({
+ range,
+ message,
+ severity,
+ source: "test",
+ })),
+ Range: jest.fn().mockImplementation((startLine, startChar, endLine, endChar) => ({
+ start: { line: startLine, character: startChar },
+ end: { line: endLine, character: endChar },
+ })),
+ DiagnosticSeverity: {
+ Error: 0,
+ Warning: 1,
+ Information: 2,
+ Hint: 3,
+ },
+ FileType: {
+ Unknown: 0,
+ File: 1,
+ Directory: 2,
+ SymbolicLink: 64,
+ },
+ workspace: {
+ fs: {
+ stat: jest.fn(),
+ },
+ openTextDocument: jest.fn(),
+ },
+}))
+
+describe("diagnosticsToProblemsString", () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it("should filter diagnostics by severity and include correct labels", async () => {
+ // Mock file URI
+ const fileUri = vscode.Uri.file("/path/to/file.ts")
+
+ // Create diagnostics with different severities
+ const diagnostics = [
+ new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error message", vscode.DiagnosticSeverity.Error),
+ new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning message", vscode.DiagnosticSeverity.Warning),
+ new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "Info message", vscode.DiagnosticSeverity.Information),
+ new vscode.Diagnostic(new vscode.Range(3, 0, 3, 10), "Hint message", vscode.DiagnosticSeverity.Hint),
+ ]
+
+ // Mock fs.stat to return file type
+ const mockStat = {
+ type: vscode.FileType.File,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock document content
+ const mockDocument = {
+ lineAt: jest.fn((line) => ({
+ text: `Line ${line + 1} content`,
+ })),
+ }
+ vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
+
+ // Test with Error and Warning severities only
+ const result = await diagnosticsToProblemsString(
+ [[fileUri, diagnostics]],
+ [vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning],
+ "/path/to",
+ )
+
+ // Verify only Error and Warning diagnostics are included
+ expect(result).toContain("Error message")
+ expect(result).toContain("Warning message")
+ expect(result).not.toContain("Info message")
+ expect(result).not.toContain("Hint message")
+
+ // Verify correct severity labels are used
+ expect(result).toContain("[test Error]")
+ expect(result).toContain("[test Warning]")
+ expect(result).not.toContain("[test Information]")
+ expect(result).not.toContain("[test Hint]")
+
+ // Verify line content is included
+ expect(result).toContain("Line 1 content")
+ expect(result).toContain("Line 2 content")
+ })
+
+ it("should handle directory URIs correctly without attempting to open as document", async () => {
+ // Mock directory URI
+ const dirUri = vscode.Uri.file("/path/to/directory/")
+
+ // Mock diagnostic for directory
+ const diagnostic = new vscode.Diagnostic(
+ new vscode.Range(0, 0, 0, 10),
+ "Directory diagnostic message",
+ vscode.DiagnosticSeverity.Error,
+ )
+
+ // Mock fs.stat to return directory type
+ const mockStat = {
+ type: vscode.FileType.Directory,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock openTextDocument to ensure it's not called
+ vscode.workspace.openTextDocument = jest.fn()
+
+ // Call the function
+ const result = await diagnosticsToProblemsString(
+ [[dirUri, [diagnostic]]],
+ [vscode.DiagnosticSeverity.Error],
+ "/path/to",
+ )
+
+ // Verify fs.stat was called with the directory URI
+ expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(dirUri)
+
+ // Verify openTextDocument was not called
+ expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled()
+
+ // Verify the output contains the expected directory indicator
+ expect(result).toContain("(directory)")
+ expect(result).toContain("Directory diagnostic message")
+ expect(result).toMatch(/directory\/\n- \[test Error\] 1 \| \(directory\) : Directory diagnostic message/)
+ })
+
+ it("should correctly handle multiple diagnostics for the same file", async () => {
+ // Mock file URI
+ const fileUri = vscode.Uri.file("/path/to/file.ts")
+
+ // Create multiple diagnostics for the same file
+ const diagnostics = [
+ new vscode.Diagnostic(new vscode.Range(4, 0, 4, 10), "Later line error", vscode.DiagnosticSeverity.Error),
+ new vscode.Diagnostic(
+ new vscode.Range(0, 0, 0, 10),
+ "First line warning",
+ vscode.DiagnosticSeverity.Warning,
+ ),
+ new vscode.Diagnostic(
+ new vscode.Range(2, 0, 2, 10),
+ "Middle line info",
+ vscode.DiagnosticSeverity.Information,
+ ),
+ ]
+
+ // Mock fs.stat to return file type
+ const mockStat = {
+ type: vscode.FileType.File,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock document content with specific line texts for each test case
+ const mockDocument = {
+ lineAt: jest.fn((line: number) => {
+ const lineTexts: Record = {
+ 0: "Line 0 content for warning",
+ 2: "Line 2 content for info",
+ 4: "Line 4 content for error",
+ }
+ return { text: lineTexts[line] }
+ }),
+ }
+ vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
+
+ // Call the function with all severities
+ const result = await diagnosticsToProblemsString(
+ [[fileUri, diagnostics]],
+ [vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning, vscode.DiagnosticSeverity.Information],
+ "/path/to",
+ )
+
+ // Verify all diagnostics are included in the output
+ expect(result).toContain("First line warning")
+ expect(result).toContain("Middle line info")
+ expect(result).toContain("Later line error")
+
+ // Verify line content is included for each diagnostic and matches the test case
+ expect(result).toContain("Line 0 content for warning")
+ expect(result).toContain("Line 2 content for info")
+ expect(result).toContain("Line 4 content for error")
+
+ // Verify the output contains all severity labels
+ expect(result).toContain("[test Warning]")
+ expect(result).toContain("[test Information]")
+ expect(result).toContain("[test Error]")
+
+ // Verify diagnostics appear in line number order (even though input wasn't sorted)
+ // Verify exact output format
+ expect(result).toBe(
+ "file.ts\n" +
+ "- [test Warning] 1 | Line 0 content for warning : First line warning\n" +
+ "- [test Information] 3 | Line 2 content for info : Middle line info\n" +
+ "- [test Error] 5 | Line 4 content for error : Later line error",
+ )
+ })
+
+ it("should correctly handle diagnostics from multiple files", async () => {
+ // Mock URIs for different files
+ const fileUri1 = vscode.Uri.file("/path/to/file1.ts")
+ const fileUri2 = vscode.Uri.file("/path/to/subdir/file2.ts")
+
+ // Create diagnostics for each file
+ const diagnostics1 = [
+ new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "File1 error", vscode.DiagnosticSeverity.Error),
+ ]
+
+ const diagnostics2 = [
+ new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "File2 warning", vscode.DiagnosticSeverity.Warning),
+ new vscode.Diagnostic(new vscode.Range(2, 0, 2, 10), "File2 info", vscode.DiagnosticSeverity.Information),
+ ]
+
+ // Mock fs.stat to return file type for both files
+ const mockStat = {
+ type: vscode.FileType.File,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock document content with specific line texts for each test case
+ const mockDocument1 = {
+ lineAt: jest.fn((_line) => ({
+ text: "Line 1 content for error",
+ })),
+ }
+ const mockDocument2 = {
+ lineAt: jest.fn((line) => {
+ const lineTexts = ["Line 1 content", "Line 2 content for warning", "Line 3 content for info"]
+ return { text: lineTexts[line] }
+ }),
+ }
+ vscode.workspace.openTextDocument = jest
+ .fn()
+ .mockResolvedValueOnce(mockDocument1)
+ .mockResolvedValueOnce(mockDocument2)
+
+ // Call the function with all severities
+ const result = await diagnosticsToProblemsString(
+ [
+ [fileUri1, diagnostics1],
+ [fileUri2, diagnostics2],
+ ],
+ [vscode.DiagnosticSeverity.Error, vscode.DiagnosticSeverity.Warning, vscode.DiagnosticSeverity.Information],
+ "/path/to",
+ )
+
+ // Verify file paths are correctly shown with relative paths
+ expect(result).toContain("file1.ts")
+ expect(result).toContain("subdir/file2.ts")
+
+ // Verify diagnostics are grouped under their respective files
+ const file1Section = result.split("file1.ts")[1]
+ expect(file1Section).toContain("File1 error")
+ expect(file1Section).toContain("Line 1 content for error")
+
+ const file2Section = result.split("subdir/file2.ts")[1]
+ expect(file2Section).toContain("File2 warning")
+ expect(file2Section).toContain("Line 2 content for warning")
+ expect(file2Section).toContain("File2 info")
+ expect(file2Section).toContain("Line 3 content for info")
+
+ // Verify exact output format
+ expect(result).toBe(
+ "file1.ts\n" +
+ "- [test Error] 1 | Line 1 content for error : File1 error\n\n" +
+ "subdir/file2.ts\n" +
+ "- [test Warning] 2 | Line 2 content for warning : File2 warning\n" +
+ "- [test Information] 3 | Line 3 content for info : File2 info",
+ )
+ })
+
+ it("should return empty string when no diagnostics match the severity filter", async () => {
+ // Mock file URI
+ const fileUri = vscode.Uri.file("/path/to/file.ts")
+
+ // Create diagnostics with Error and Warning severities
+ const diagnostics = [
+ new vscode.Diagnostic(new vscode.Range(0, 0, 0, 10), "Error message", vscode.DiagnosticSeverity.Error),
+ new vscode.Diagnostic(new vscode.Range(1, 0, 1, 10), "Warning message", vscode.DiagnosticSeverity.Warning),
+ ]
+
+ // Mock fs.stat to return file type
+ const mockStat = {
+ type: vscode.FileType.File,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock document content (though it shouldn't be accessed in this case)
+ const mockDocument = {
+ lineAt: jest.fn((line) => ({
+ text: `Line ${line + 1} content`,
+ })),
+ }
+ vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
+
+ // Test with Information and Hint severities only (which don't match our diagnostics)
+ const result = await diagnosticsToProblemsString(
+ [[fileUri, diagnostics]],
+ [vscode.DiagnosticSeverity.Information, vscode.DiagnosticSeverity.Hint],
+ "/path/to",
+ )
+
+ // Verify empty string is returned
+ expect(result).toBe("")
+
+ // Verify no unnecessary calls were made
+ expect(vscode.workspace.fs.stat).not.toHaveBeenCalled()
+ expect(vscode.workspace.openTextDocument).not.toHaveBeenCalled()
+ })
+
+ it("should correctly handle cwd parameter for relative file paths", async () => {
+ // Mock file URI in a subdirectory
+ const fileUri = vscode.Uri.file("/project/root/src/utils/file.ts")
+
+ // Create a diagnostic for the file
+ const diagnostic = new vscode.Diagnostic(
+ new vscode.Range(4, 0, 4, 10),
+ "Relative path test error",
+ vscode.DiagnosticSeverity.Error,
+ )
+
+ // Mock fs.stat to return file type
+ const mockStat = {
+ type: vscode.FileType.File,
+ }
+ vscode.workspace.fs.stat = jest.fn().mockResolvedValue(mockStat)
+
+ // Mock document content matching test assertion
+ const mockDocument = {
+ lineAt: jest.fn((line) => ({
+ text: `Line ${line + 1} content for error`,
+ })),
+ }
+ vscode.workspace.openTextDocument = jest.fn().mockResolvedValue(mockDocument)
+
+ // Call the function with cwd set to the project root
+ const result = await diagnosticsToProblemsString(
+ [[fileUri, [diagnostic]]],
+ [vscode.DiagnosticSeverity.Error],
+ "/project/root",
+ )
+
+ // Verify exact output format
+ expect(result).toBe(
+ "src/utils/file.ts\n" + "- [test Error] 5 | Line 5 content for error : Relative path test error",
+ )
+
+ // Verify fs.stat and openTextDocument were called
+ expect(vscode.workspace.fs.stat).toHaveBeenCalledWith(fileUri)
+ expect(vscode.workspace.openTextDocument).toHaveBeenCalledWith(fileUri)
+ })
+})
diff --git a/src/integrations/diagnostics/index.ts b/src/integrations/diagnostics/index.ts
index 2d829f26e76..97b83353534 100644
--- a/src/integrations/diagnostics/index.ts
+++ b/src/integrations/diagnostics/index.ts
@@ -76,9 +76,12 @@ export async function diagnosticsToProblemsString(
cwd: string,
): Promise