diff --git a/.changeset/slimy-years-smell.md b/.changeset/slimy-years-smell.md deleted file mode 100644 index 943c31593af..00000000000 --- a/.changeset/slimy-years-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -new feature allowing users to toggle whether an individual MCP (Model Context Protocol) tool is included in the context provided to the AI model diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6ae2fd2fa53..765c70614c8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -30,19 +30,6 @@ Detail the steps to test your changes. This helps reviewers verify your work. - Include relevant testing environment details if applicable. --> -### Type of Change - - - -- [ ] 🐛 **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. - ### Pre-Submission Checklist @@ -50,17 +37,8 @@ Detail the steps to test your changes. This helps reviewers verify your work. - [ ] **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. +- [ ] **Testing**: New and/or updated tests have been added to cover my changes (if applicable). - [ ] **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). ### Screenshots / Videos diff --git a/.roo/rules-pr-fixer/1_workflow.xml b/.roo/rules-pr-fixer/1_workflow.xml new file mode 100644 index 00000000000..f646a4e245a --- /dev/null +++ b/.roo/rules-pr-fixer/1_workflow.xml @@ -0,0 +1,57 @@ + + + This mode is designed to help resolve issues in existing pull requests. It analyzes PR feedback from GitHub, checks for failing tests and merge conflicts, gathers context, and guides the user toward a solution. + + + + + Understand the user's request +
+ Parse the user's input to identify the pull request URL or number. Extract the repository owner and name. +
+
+ + Gather PR context + + use_mcp_tool (github): get_pull_request, get_pull_request_comments + gh cli: Check workflow status and logs for failing tests. + gh cli: Check for merge conflicts. + + +
+ + + + Analyze the gathered information to identify the core problems. + + Summarize review comments and requested changes. + Identify the root cause of failing tests by analyzing logs. + Determine if merge conflicts exist. + + + + + Synthesize the findings and present them to the user. + + Present a summary of the issues found (reviews, failing tests, conflicts). + Use ask_followup_question to ask the user how they want to proceed with fixing the issues. + + + + + Execute the user's chosen course of action. + + Check out the PR branch locally using 'gh pr checkout'. + Apply code changes based on review feedback. + Fix failing tests. + Resolve conflicts by rebasing the PR branch and force-pushing. + + + + + + All actionable review comments have been addressed. + All tests are passing. + The PR is free of merge conflicts. + +
diff --git a/.roo/rules-pr-fixer/2_best_practices.xml b/.roo/rules-pr-fixer/2_best_practices.xml new file mode 100644 index 00000000000..6b1af4fada9 --- /dev/null +++ b/.roo/rules-pr-fixer/2_best_practices.xml @@ -0,0 +1,56 @@ + + + + Context is Key + Always gather full context before attempting a fix. This includes reading all relevant PR comments, checking CI/CD logs, and understanding the surrounding code. + Without full context, fixes may be incomplete or introduce new issues. + + + Incremental Fixes + Address issues one at a time (e.g., fix tests first, then address comments). This makes the process more manageable and easier to validate. + Tackling all issues at once can be complex and error-prone. + + + + + + How to correctly escape conflict markers when using apply_diff. + + + + + + + Have all review comments been addressed? + Are all CI/CD checks passing? + Is the PR free of merge conflicts? + Have the changes been tested locally? + + + diff --git a/.roo/rules-pr-fixer/3_common_patterns.xml b/.roo/rules-pr-fixer/3_common_patterns.xml new file mode 100644 index 00000000000..848be1482d9 --- /dev/null +++ b/.roo/rules-pr-fixer/3_common_patterns.xml @@ -0,0 +1,48 @@ + + + A set of commands to quickly assess the state of a Pull Request. + + + + Commands to investigate why a specific test is failing. + + + + A sequence of commands to resolve merge conflicts locally using rebase. + + + + Command to check out a pull request branch locally. + + + diff --git a/.roo/rules-pr-fixer/4_tool_usage.xml b/.roo/rules-pr-fixer/4_tool_usage.xml new file mode 100644 index 00000000000..e6d8ae0d116 --- /dev/null +++ b/.roo/rules-pr-fixer/4_tool_usage.xml @@ -0,0 +1,44 @@ + + + + use_mcp_tool (server: github) + Use at the start to get all review comments and PR metadata. + Provides the core context of what needs to be fixed from a human perspective. + + + gh pr checks + After getting comments, to check the technical status. + Quickly identifies if there are failing automated checks that need investigation. + + + + + + + Always fetch details to get the branch name, owner, repo slug, and mergeable state. + + + + + + Parse all comments to create a checklist of required changes. + Ignore comments that are not actionable or have been resolved. + + + + + + Use this command to get the exact error messages from failing tests. + Search the log for keywords like 'error', 'failed', or 'exception' to quickly find the root cause. + + + + + + After analyzing all the problems (reviews, tests, conflicts), present a summary to the user. + Provide clear, actionable next steps as suggestions. + Example suggestions: "Address review comments first.", "Tackle the failing tests.", "Resolve merge conflicts." + + + + diff --git a/.roo/rules-pr-fixer/5_examples.xml b/.roo/rules-pr-fixer/5_examples.xml new file mode 100644 index 00000000000..77905cc3a60 --- /dev/null +++ b/.roo/rules-pr-fixer/5_examples.xml @@ -0,0 +1,91 @@ + + + + A pull request has a failing CI check and a review comment asking for a change. + + + + Fix PR #4365 in RooCodeInc/Roo-Code. + + + + + Get PR details and review comments. + + + github + get_pull_request + + { + "owner": "RooCodeInc", + "repo": "Roo-Code", + "pullNumber": 4365 + } + + + + github + get_pull_request_comments + + { + "owner": "RooCodeInc", + "repo": "Roo-Code", + "pullNumber": 4365 + } + + + + Get the branch name, list of review comments, and check for mergeability. + + + + Check CI status. + + +gh pr checks 4365 + + + Identify which check is failing. + + + + Get logs for the failing check. + + +gh run view --log-failed + + + Find the specific error message causing the test to fail. + + + + Check out the pull request branch. + + + gh pr checkout 4365 + + + The PR branch is now ready for local edits. + + + + Summarize findings and ask the user for the next action. + + +I've checked out the branch. I've found a failing test related to 'XYZ' and a review comment asking to rename a variable. How should we proceed? + +First, apply the change requested in the review comment. +Let's start by fixing the failing test. +Show me the code for the failing test and the file with the requested change. + + + + + + + + Always gather all information before proposing a solution. + Use a combination of the GitHub MCP server and the `gh` CLI to get a complete picture of the PR's status. + + + diff --git a/.roomodes b/.roomodes index 0e3ab975417..236026c7387 100644 --- a/.roomodes +++ b/.roomodes @@ -25,6 +25,8 @@ customModes: - fileRegex: (\.roomodes$|\.roo/.*\.xml$|\.yaml$) description: Mode configuration files and XML instructions - command + - mcp + source: project - slug: test name: 🧪 Test roleDefinition: >- @@ -241,4 +243,20 @@ customModes: description: Temporary documentation extraction files only - command - mcp - + - slug: pr-fixer + name: 🛠️ PR Fixer + roleDefinition: "You are Roo, a pull request resolution specialist. Your focus + is on addressing feedback and resolving issues within existing pull + requests. Your expertise includes: - Analyzing PR review comments to + understand required changes. - Checking CI/CD workflow statuses to + identify failing tests. - Fetching and analyzing test logs to diagnose + failures. - Identifying and resolving merge conflicts. - Guiding the user + through the resolution process." + whenToUse: Use this mode to fix pull requests. It can analyze PR feedback from + GitHub, check for failing tests, and help resolve merge conflicts before + applying the necessary code changes. + groups: + - read + - edit + - command + - mcp diff --git a/CHANGELOG.md b/CHANGELOG.md index 0083c068406..daee785b6da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Roo Code Changelog +## [3.21.3] - 2025-06-21 + +- Add profile-specific context condensing thresholds (thanks @SannidhyaSah!) +- Fix context length for lmstudio and ollama (thanks @thecolorblue!) +- Resolve MCP tool eye icon state and hide in chat context (thanks @daniel-lxs!) + +## [3.21.2] - 2025-06-20 + +- Add LaTeX math equation rendering in chat window +- Add toggle for excluding MCP server tools from the prompt (thanks @Rexarrior!) +- Add symlink support to list_files tool +- Fix marketplace blanking after populating +- Fix recursive directory scanning in @ mention "Add Folder" functionality (thanks @village-way!) +- Resolve phantom subtask display on cancel during API retry +- Correct Gemini 2.5 Flash pricing (thanks @daniel-lxs!) +- Resolve marketplace timeout issues and display installed MCPs (thanks @daniel-lxs!) +- Onboarding tweaks to emphasize modes (thanks @brunobergher!) +- Rename 'Boomerang Tasks' to 'Task Orchestration' for clarity +- Remove command execution from attempt_completion +- Fix markdown for links followed by punctuation (thanks @xyOz-dev!) + ## [3.21.1] - 2025-06-19 - Fix tree-sitter issues that were preventing codebase indexing from working correctly diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..9d72db1cdb3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,385 @@ +# Claude Development Guide for Roo Code + +This document provides a comprehensive guide for Claude instances working on the Roo Code project. It covers the technology stack, architecture, development patterns, and key considerations for contributing effectively. + +## Project Overview + +**Roo Code** (previously Roo Cline) is an AI-powered autonomous coding agent that operates as a VS Code extension. It enables natural language interaction for code generation, debugging, file operations, terminal commands, and browser automation. + +### Key Features + +- Multi-mode AI assistant (Code, Architect, Ask, Debug modes) +- File read/write operations within VS Code workspace +- Terminal command execution +- Browser automation capabilities +- Model Context Protocol (MCP) integration +- Custom modes and instructions +- Multi-language support (18+ locales) +- Marketplace for modes and MCP servers + +## Technology Stack + +### Core Technologies + +- **Runtime**: Node.js 20.19.2 +- **Package Manager**: PNPM 10.8.1 (monorepo with workspaces) +- **Build System**: Turborepo for orchestration +- **Extension Framework**: VS Code Extension API +- **Frontend**: React 18 + TypeScript + Vite +- **UI Library**: Radix UI + Tailwind CSS 4.0 +- **Language**: TypeScript 5.8.3 + +### Build Tools + +- **Extension Bundling**: ESBuild (production) with custom plugins +- **Webview Bundling**: Vite 6.3.5 with React plugin +- **Styling**: Tailwind CSS 4.0 with @tailwindcss/vite +- **Code Analysis**: Tree-sitter for syntax parsing +- **Internationalization**: i18next + +### AI Provider Support + +Supports 15+ AI providers including: + +- Anthropic (Claude) - Primary +- OpenAI (GPT models) +- AWS Bedrock +- Google Vertex AI & Gemini +- Local models (Ollama, LM Studio) +- Open source routers (OpenRouter, LiteLLM) + +### Testing Framework + +- **Unit Tests**: Jest (for Node.js code) +- **Frontend Tests**: Vitest (for React components) +- **E2E Tests**: VSCode Test Framework +- **Platform Support**: Linux, macOS, Windows with platform-specific test filtering + +## Architecture Overview + +### Monorepo Structure + +``` +Roo-Code/ +├── src/ # Main VS Code extension +├── webview-ui/ # React frontend for webview +├── apps/ +│ ├── vscode-e2e/ # E2E tests +│ ├── vscode-nightly/ # Nightly build variant +│ ├── web-docs/ # Documentation site +│ ├── web-evals/ # Evaluation frontend +│ └── web-roo-code/ # Marketing website +├── packages/ +│ ├── types/ # Shared TypeScript types +│ ├── build/ # Build utilities +│ ├── config-eslint/ # ESLint configurations +│ ├── config-typescript/ # TypeScript configurations +│ ├── cloud/ # Cloud service integration +│ ├── telemetry/ # Analytics and telemetry +│ ├── ipc/ # Inter-process communication +│ └── evals/ # Evaluation system +└── locales/ # Internationalization +``` + +### Core Extension Architecture + +#### 1. Entry Point (`src/extension.ts`) + +- Initializes extension context +- Sets up output channel logging +- Loads environment variables +- Registers commands, providers, and services + +#### 2. Core Modules (`src/core/`) + +**ClineProvider** (`core/webview/ClineProvider.ts`) + +- Main orchestrator for the webview interface +- Manages task stack and user interactions +- Handles API provider settings and configuration +- Implements telemetry and cloud service integration + +**Task System** (`core/task/Task.ts`) + +- Manages individual AI conversation sessions +- Handles tool execution and response processing +- Implements context tracking and sliding window +- Manages checkpoint/restore functionality + +**Tool System** (`core/tools/`) + +- Implements all available tools (file operations, commands, browser, MCP) +- Tool repetition detection and validation +- Each tool has its own TypeScript file with consistent interface + +**Prompt System** (`core/prompts/`) + +- Dynamic system prompt generation based on mode and context +- Modular prompt sections (capabilities, rules, objectives, etc.) +- Support for custom instructions and mode-specific behavior + +#### 3. API Abstraction (`src/api/`) + +- **Providers**: Unified interface for 15+ AI providers +- **Transform**: Request/response formatting, streaming, caching +- **Base Provider**: Common functionality across all providers +- **Router Provider**: Load balancing and fallback logic + +#### 4. Integration Layer (`src/integrations/`) + +- **Terminal**: Shell command execution and process management +- **Editor**: Diff views, decorations, code actions +- **Browser**: Puppeteer automation for web interactions +- **Workspace**: File system operations and tracking + +#### 5. Services (`src/services/`) + +- **MCP Hub**: Model Context Protocol server management +- **Code Index**: Semantic code search with embeddings +- **Marketplace**: Mode and MCP server installation +- **Checkpoints**: Git-based state management + +### Frontend Architecture (`webview-ui/`) + +#### React Component Structure + +``` +src/ +├── components/ +│ ├── chat/ # Chat interface components +│ ├── common/ # Reusable UI components +│ ├── history/ # Task history management +│ ├── settings/ # Configuration UI +│ ├── marketplace/ # Marketplace interface +│ ├── mcp/ # MCP server management +│ └── modes/ # Mode selection UI +├── context/ # React context providers +├── hooks/ # Custom React hooks +├── utils/ # Frontend utilities +└── i18n/ # Internationalization setup +``` + +#### State Management + +- React Context for global state +- TanStack Query for server state management +- Local state with React hooks +- VS Code API integration via message passing + +## Development Commands + +### Setup + +```bash +# Install dependencies +pnpm install + +# Development build with watch +pnpm bundle --watch + +# Type checking with watch +pnpm watch:tsc +``` + +### Building & Testing + +```bash +# Run all tests +pnpm test + +# Lint code +pnpm lint + +# Type checking +pnpm check-types + +# Build for production +pnpm build + +# Bundle extension +pnpm bundle + +# Create VSIX package +pnpm vsix +``` + +### Development Workflow + +```bash +# Clean build +pnpm clean + +# Full development cycle +pnpm clean && pnpm lint && pnpm test && pnpm build + +# Install in VS Code +pnpm vsix --out ../bin/roo-code.vsix && code --install-extension bin/roo-code.vsix +``` + +## Key Architectural Patterns + +### 1. Mode System + +The application supports multiple operational modes: + +- **Code Mode**: General-purpose coding with full tool access +- **Architect Mode**: Planning and design with limited file editing +- **Ask Mode**: Question answering with read-only access +- **Debug Mode**: Systematic problem diagnosis +- **Custom Modes**: User-defined with configurable tool groups and prompts + +### 2. Tool Groups + +Tools are organized into logical groups: + +- **Read**: File reading, search, code analysis +- **Edit**: File writing, content modification +- **Command**: Terminal execution +- **Browser**: Web automation +- **MCP**: External tool integration + +### 3. Provider Abstraction + +All AI providers implement a common interface: + +```typescript +interface BaseProvider { + createMessage(messages: ApiMessage[]): AsyncGenerator + validateSettings(settings: ProviderSettings): void + getMaxTokens(): number +} +``` + +### 4. Message Flow + +1. User input → WebView +2. WebView → Extension (via VS Code API) +3. Extension → Task processor +4. Task → Tool execution +5. Tool results → AI provider +6. AI response → WebView rendering + +### 5. Internationalization + +- 18+ supported languages +- JSON-based translation files +- Runtime language switching +- Locale-specific documentation + +## Development Guidelines + +### Code Style + +- TypeScript strict mode enabled +- ESLint with custom rules (see `src/eslint.config.mjs`) +- Prettier for formatting +- Interface-first design patterns + +### Testing Strategy + +- Unit tests for core logic (Jest) +- Component tests for React UI (Vitest) +- Integration tests for VS Code functionality +- Platform-specific test filtering for Windows/Unix + +### Error Handling + +- Comprehensive error serialization +- Telemetry integration for error tracking +- User-friendly error messages +- Graceful degradation for provider failures + +### File Organization + +- Feature-based directory structure +- Consistent naming conventions (`camelCase` for files, `PascalCase` for classes) +- Co-located tests in `__tests__` directories +- Type definitions in dedicated files + +### Performance Considerations + +- Lazy loading for heavy dependencies (Tree-sitter, MCP) +- Webview resource optimization +- Token usage tracking and limits +- Sliding window for conversation context + +## Common Development Tasks + +### Adding a New AI Provider + +1. Create provider class in `src/api/providers/` +2. Implement `BaseProvider` interface +3. Add provider configuration to types +4. Update provider router and settings UI +5. Add comprehensive tests + +### Adding a New Tool + +1. Create tool file in `src/core/tools/` +2. Implement tool interface with validation +3. Add tool to appropriate tool group +4. Update prompt system descriptions +5. Add unit tests and error handling + +### Adding UI Components + +1. Create React component in appropriate directory +2. Use Radix UI primitives for accessibility +3. Apply Tailwind CSS for styling +4. Add internationalization support +5. Write component tests + +### Modifying System Prompts + +1. Update relevant section in `src/core/prompts/sections/` +2. Ensure mode-specific customization +3. Test with different provider models +4. Update documentation if needed + +## Important Considerations + +### Security + +- File access respects `.rooignore` patterns +- Protected directories prevent sensitive file access +- Command execution requires user approval +- Browser automation in sandboxed environment + +### Compatibility + +- VS Code version 1.84.0+ required +- Node.js 20.19.2 specific dependency +- Cross-platform terminal handling +- Provider-specific model limitations + +### Performance + +- Tree-sitter parsing for large codebases +- Streaming responses for better UX +- Efficient context window management +- Lazy loading of heavy dependencies + +### Extensibility + +- MCP protocol for external tools +- Custom mode definitions +- Provider plugin architecture +- Marketplace integration + +## Debugging Tips + +### Common Issues + +1. **Extension not loading**: Check VS Code developer console +2. **Webview not rendering**: Verify Vite build output +3. **Tool execution failures**: Check terminal output and permissions +4. **Provider API errors**: Verify API keys and rate limits + +### Development Tools + +- VS Code Extension Host for debugging +- Chrome DevTools for webview debugging +- Output channel logging for extension logs +- Telemetry dashboard for usage analytics + +This guide should help Claude instances understand the codebase structure, make informed decisions about code changes, and maintain consistency with the project's architecture and patterns. diff --git a/README.md b/README.md index 0fc2dd3d502..e374ea9c3d6 100644 --- a/README.md +++ b/README.md @@ -176,39 +176,40 @@ Thanks to all our contributors who have helped make Roo Code better! -| mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| hannesrudolph
hannesrudolph
| -| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| KJ7LNW
KJ7LNW
| a8trejo
a8trejo
| ColemanRoo
ColemanRoo
| canrobins13
canrobins13
| stea9499
stea9499
| joemanley201
joemanley201
| -| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| NyxJae
NyxJae
| jr
jr
| MuriloFP
MuriloFP
| -| elianiva
elianiva
| d-oit
d-oit
| punkpeye
punkpeye
| wkordalski
wkordalski
| sachasayan
sachasayan
| Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -| monotykamary
monotykamary
| cannuri
cannuri
| feifei325
feifei325
| zhangtony239
zhangtony239
| qdaxb
qdaxb
| xyOz-dev
xyOz-dev
| -| dtrugman
dtrugman
| vigneshsubbiah16
vigneshsubbiah16
| lloydchang
lloydchang
| shariqriazz
shariqriazz
| pugazhendhi-m
pugazhendhi-m
| Szpadel
Szpadel
| -| chrarnoldus
chrarnoldus
| diarmidmackenzie
diarmidmackenzie
| olweraltuve
olweraltuve
| psv2522
psv2522
| Premshay
Premshay
| lupuletic
lupuletic
| -| PeterDaveHello
PeterDaveHello
| aheizi
aheizi
| kiwina
kiwina
| afshawnlotfi
afshawnlotfi
| RaySinner
RaySinner
| nbihan-mediware
nbihan-mediware
| -| ChuKhaLi
ChuKhaLi
| hassoncs
hassoncs
| emshvac
emshvac
| kyle-apex
kyle-apex
| noritaka1166
noritaka1166
| pdecat
pdecat
| -| StevenTCramer
StevenTCramer
| Lunchb0ne
Lunchb0ne
| SmartManoj
SmartManoj
| vagadiya
vagadiya
| slytechnical
slytechnical
| dleffel
dleffel
| -| arthurauffray
arthurauffray
| upamune
upamune
| NamesMT
NamesMT
| taylorwilsdon
taylorwilsdon
| SannidhyaSah
SannidhyaSah
| sammcj
sammcj
| -| Ruakij
Ruakij
| p12tic
p12tic
| gtaylor
gtaylor
| aitoroses
aitoroses
| mr-ryan-james
mr-ryan-james
| heyseth
heyseth
| -| taisukeoe
taisukeoe
| avtc
avtc
| dlab-anton
dlab-anton
| eonghk
eonghk
| kcwhite
kcwhite
| ronyblum
ronyblum
| -| teddyOOXX
teddyOOXX
| vincentsong
vincentsong
| yongjer
yongjer
| zeozeozeo
zeozeozeo
| ashktn
ashktn
| franekp
franekp
| -| yt3trees
yt3trees
| anton-otee
anton-otee
| benzntech
benzntech
| axkirillov
axkirillov
| bramburn
bramburn
| olearycrew
olearycrew
| -| snoyiatk
snoyiatk
| GitlyHallows
GitlyHallows
| ross
ross
| philfung
philfung
| napter
napter
| mdp
mdp
| -| jcbdev
jcbdev
| Chenjiayuan195
Chenjiayuan195
| julionav
julionav
| SplittyDev
SplittyDev
| kohii
kohii
| kinandan
kinandan
| -| jwcraig
jwcraig
| shoopapa
shoopapa
| im47cn
im47cn
| hongzio
hongzio
| hatsu38
hatsu38
| GOODBOY008
GOODBOY008
| -| forestyoo
forestyoo
| dqroid
dqroid
| dairui1
dairui1
| bannzai
bannzai
| tgfjt
tgfjt
| axmo
axmo
| -| asychin
asychin
| amittell
amittell
| tmsjngx0
tmsjngx0
| Yoshino-Yukitaro
Yoshino-Yukitaro
| Yikai-Liao
Yikai-Liao
| zxdvd
zxdvd
| -| vladstudio
vladstudio
| nevermorec
nevermorec
| PretzelVector
PretzelVector
| zetaloop
zetaloop
| cdlliuy
cdlliuy
| user202729
user202729
| -| student20880
student20880
| shohei-ihaya
shohei-ihaya
| shaybc
shaybc
| seedlord
seedlord
| samir-nimbly
samir-nimbly
| roomote
roomote
| -| robertheadley
robertheadley
| refactorthis
refactorthis
| qingyuan1109
qingyuan1109
| pokutuna
pokutuna
| philipnext
philipnext
| oprstchn
oprstchn
| -| nobu007
nobu007
| mosleyit
mosleyit
| moqimoqidea
moqimoqidea
| mlopezr
mlopezr
| mecab
mecab
| olup
olup
| -| lightrabbit
lightrabbit
| linegel
linegel
| edwin-truthsearch-io
edwin-truthsearch-io
| EamonNerbonne
EamonNerbonne
| dbasclpy
dbasclpy
| dflatline
dflatline
| -| Deon588
Deon588
| dleen
dleen
| devxpain
devxpain
| chadgauth
chadgauth
| brunobergher
brunobergher
| bogdan0083
bogdan0083
| -| Atlogit
Atlogit
| atlasgong
atlasgong
| andreastempsch
andreastempsch
| alasano
alasano
| QuinsZouls
QuinsZouls
| HadesArchitect
HadesArchitect
| -| alarno
alarno
| nexon33
nexon33
| adilhafeez
adilhafeez
| adamwlarson
adamwlarson
| adamhill
adamhill
| AMHesch
AMHesch
| -| maekawataiki
maekawataiki
| AlexandruSmirnov
AlexandruSmirnov
| samsilveira
samsilveira
| 01Rian
01Rian
| RSO
RSO
| SECKainersdorfer
SECKainersdorfer
| -| R-omk
R-omk
| Sarke
Sarke
| kvokka
kvokka
| ecmasx
ecmasx
| mollux
mollux
| marvijo-code
marvijo-code
| -| mamertofabian
mamertofabian
| monkeyDluffy6017
monkeyDluffy6017
| libertyteeth
libertyteeth
| shtse8
shtse8
| KanTakahiro
KanTakahiro
| ksze
ksze
| -| Jdo300
Jdo300
| hesara
hesara
| DeXtroTip
DeXtroTip
| pfitz
pfitz
| celestial-vault
celestial-vault
| | +| mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| hannesrudolph
hannesrudolph
| +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| KJ7LNW
KJ7LNW
| a8trejo
a8trejo
| ColemanRoo
ColemanRoo
| canrobins13
canrobins13
| stea9499
stea9499
| joemanley201
joemanley201
| +| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| NyxJae
NyxJae
| jr
jr
| MuriloFP
MuriloFP
| +| elianiva
elianiva
| d-oit
d-oit
| punkpeye
punkpeye
| wkordalski
wkordalski
| sachasayan
sachasayan
| Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +| monotykamary
monotykamary
| cannuri
cannuri
| xyOz-dev
xyOz-dev
| feifei325
feifei325
| zhangtony239
zhangtony239
| qdaxb
qdaxb
| +| shariqriazz
shariqriazz
| pugazhendhi-m
pugazhendhi-m
| vigneshsubbiah16
vigneshsubbiah16
| lloydchang
lloydchang
| dtrugman
dtrugman
| Szpadel
Szpadel
| +| chrarnoldus
chrarnoldus
| diarmidmackenzie
diarmidmackenzie
| olweraltuve
olweraltuve
| psv2522
psv2522
| Premshay
Premshay
| lupuletic
lupuletic
| +| kiwina
kiwina
| aheizi
aheizi
| PeterDaveHello
PeterDaveHello
| afshawnlotfi
afshawnlotfi
| RaySinner
RaySinner
| nbihan-mediware
nbihan-mediware
| +| ChuKhaLi
ChuKhaLi
| hassoncs
hassoncs
| emshvac
emshvac
| kyle-apex
kyle-apex
| noritaka1166
noritaka1166
| pdecat
pdecat
| +| SannidhyaSah
SannidhyaSah
| StevenTCramer
StevenTCramer
| Lunchb0ne
Lunchb0ne
| SmartManoj
SmartManoj
| vagadiya
vagadiya
| slytechnical
slytechnical
| +| dleffel
dleffel
| arthurauffray
arthurauffray
| upamune
upamune
| NamesMT
NamesMT
| taylorwilsdon
taylorwilsdon
| sammcj
sammcj
| +| Ruakij
Ruakij
| p12tic
p12tic
| gtaylor
gtaylor
| aitoroses
aitoroses
| mr-ryan-james
mr-ryan-james
| heyseth
heyseth
| +| taisukeoe
taisukeoe
| avtc
avtc
| dlab-anton
dlab-anton
| eonghk
eonghk
| kcwhite
kcwhite
| ronyblum
ronyblum
| +| teddyOOXX
teddyOOXX
| vincentsong
vincentsong
| yongjer
yongjer
| zeozeozeo
zeozeozeo
| ashktn
ashktn
| franekp
franekp
| +| yt3trees
yt3trees
| benzntech
benzntech
| axkirillov
axkirillov
| anton-otee
anton-otee
| bramburn
bramburn
| olearycrew
olearycrew
| +| snoyiatk
snoyiatk
| GitlyHallows
GitlyHallows
| jcbdev
jcbdev
| Chenjiayuan195
Chenjiayuan195
| julionav
julionav
| SplittyDev
SplittyDev
| +| mdp
mdp
| napter
napter
| ross
ross
| philfung
philfung
| dairui1
dairui1
| dqroid
dqroid
| +| forestyoo
forestyoo
| GOODBOY008
GOODBOY008
| hatsu38
hatsu38
| hongzio
hongzio
| im47cn
im47cn
| shoopapa
shoopapa
| +| jwcraig
jwcraig
| kinandan
kinandan
| nevermorec
nevermorec
| bannzai
bannzai
| axmo
axmo
| asychin
asychin
| +| amittell
amittell
| Yoshino-Yukitaro
Yoshino-Yukitaro
| Yikai-Liao
Yikai-Liao
| zxdvd
zxdvd
| vladstudio
vladstudio
| tmsjngx0
tmsjngx0
| +| tgfjt
tgfjt
| PretzelVector
PretzelVector
| zetaloop
zetaloop
| cdlliuy
cdlliuy
| user202729
user202729
| student20880
student20880
| +| shohei-ihaya
shohei-ihaya
| shaybc
shaybc
| seedlord
seedlord
| samir-nimbly
samir-nimbly
| robertheadley
robertheadley
| refactorthis
refactorthis
| +| qingyuan1109
qingyuan1109
| pokutuna
pokutuna
| philipnext
philipnext
| village-way
village-way
| oprstchn
oprstchn
| nobu007
nobu007
| +| mosleyit
mosleyit
| moqimoqidea
moqimoqidea
| mlopezr
mlopezr
| mecab
mecab
| olup
olup
| lightrabbit
lightrabbit
| +| kohii
kohii
| linegel
linegel
| edwin-truthsearch-io
edwin-truthsearch-io
| EamonNerbonne
EamonNerbonne
| dbasclpy
dbasclpy
| dflatline
dflatline
| +| Deon588
Deon588
| dleen
dleen
| devxpain
devxpain
| chadgauth
chadgauth
| brunobergher
brunobergher
| thecolorblue
thecolorblue
| +| bogdan0083
bogdan0083
| Atlogit
Atlogit
| atlasgong
atlasgong
| andreastempsch
andreastempsch
| alasano
alasano
| QuinsZouls
QuinsZouls
| +| HadesArchitect
HadesArchitect
| alarno
alarno
| nexon33
nexon33
| adilhafeez
adilhafeez
| adamwlarson
adamwlarson
| adamhill
adamhill
| +| AMHesch
AMHesch
| maekawataiki
maekawataiki
| AlexandruSmirnov
AlexandruSmirnov
| samsilveira
samsilveira
| 01Rian
01Rian
| RSO
RSO
| +| SECKainersdorfer
SECKainersdorfer
| R-omk
R-omk
| Sarke
Sarke
| kvokka
kvokka
| ecmasx
ecmasx
| mollux
mollux
| +| marvijo-code
marvijo-code
| mamertofabian
mamertofabian
| monkeyDluffy6017
monkeyDluffy6017
| libertyteeth
libertyteeth
| shtse8
shtse8
| Rexarrior
Rexarrior
| +| KanTakahiro
KanTakahiro
| ksze
ksze
| Jdo300
Jdo300
| hesara
hesara
| DeXtroTip
DeXtroTip
| pfitz
pfitz
| +| celestial-vault
celestial-vault
| | | | | | diff --git a/apps/vscode-e2e/src/suite/extension.test.ts b/apps/vscode-e2e/src/suite/extension.test.ts index 3283dfcc56e..e7a92521cf6 100644 --- a/apps/vscode-e2e/src/suite/extension.test.ts +++ b/apps/vscode-e2e/src/suite/extension.test.ts @@ -1,7 +1,11 @@ import * as assert from "assert" import * as vscode from "vscode" -suite("Roo Code Extension", () => { +import { setDefaultSuiteTimeout } from "./test-utils" + +suite("Roo Code Extension", function () { + setDefaultSuiteTimeout(this) + test("Commands should be registered", async () => { const expectedCommands = [ "SidebarProvider.open", diff --git a/apps/vscode-e2e/src/suite/index.ts b/apps/vscode-e2e/src/suite/index.ts index 04c36a34e1d..ab0be6e5dff 100644 --- a/apps/vscode-e2e/src/suite/index.ts +++ b/apps/vscode-e2e/src/suite/index.ts @@ -27,13 +27,11 @@ export async function run() { globalThis.api = api - // Configure Mocha with grep pattern if provided const mochaOptions: Mocha.MochaOptions = { ui: "tdd", - timeout: 300_000, + timeout: 20 * 60 * 1_000, // 20m } - // Apply grep filter if TEST_GREP is set if (process.env.TEST_GREP) { mochaOptions.grep = process.env.TEST_GREP console.log(`Running tests matching pattern: ${process.env.TEST_GREP}`) @@ -42,17 +40,16 @@ export async function run() { const mocha = new Mocha(mochaOptions) const cwd = path.resolve(__dirname, "..") - // Get test files based on filter let testFiles: string[] + if (process.env.TEST_FILE) { - // Run specific test file const specificFile = process.env.TEST_FILE.endsWith(".js") ? process.env.TEST_FILE : `${process.env.TEST_FILE}.js` + testFiles = await glob(`**/${specificFile}`, { cwd }) console.log(`Running specific test file: ${specificFile}`) } else { - // Run all test files testFiles = await glob("**/**.test.js", { cwd }) } @@ -62,7 +59,6 @@ export async function run() { testFiles.forEach((testFile) => mocha.addFile(path.resolve(cwd, testFile))) - // Let's go! return new Promise((resolve, reject) => mocha.run((failures) => (failures === 0 ? resolve() : reject(new Error(`${failures} tests failed.`)))), ) diff --git a/apps/vscode-e2e/src/suite/modes.test.ts b/apps/vscode-e2e/src/suite/modes.test.ts index 817d5f71cec..81d8a2b7fbf 100644 --- a/apps/vscode-e2e/src/suite/modes.test.ts +++ b/apps/vscode-e2e/src/suite/modes.test.ts @@ -1,8 +1,11 @@ import * as assert from "assert" import { waitUntilCompleted } from "./utils" +import { setDefaultSuiteTimeout } from "./test-utils" + +suite("Roo Code Modes", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code Modes", () => { test("Should handle switching modes correctly", async () => { const modes: string[] = [] diff --git a/apps/vscode-e2e/src/suite/task.test.ts b/apps/vscode-e2e/src/suite/task.test.ts index e97c3b4f1ea..96b1198fd4e 100644 --- a/apps/vscode-e2e/src/suite/task.test.ts +++ b/apps/vscode-e2e/src/suite/task.test.ts @@ -3,8 +3,11 @@ import * as assert from "assert" import type { ClineMessage } from "@roo-code/types" import { waitUntilCompleted } from "./utils" +import { setDefaultSuiteTimeout } from "./test-utils" + +suite("Roo Code Task", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code Task", () => { test("Should handle prompt and response correctly", async () => { const api = globalThis.api diff --git a/apps/vscode-e2e/src/suite/test-utils.ts b/apps/vscode-e2e/src/suite/test-utils.ts new file mode 100644 index 00000000000..1ad33844bad --- /dev/null +++ b/apps/vscode-e2e/src/suite/test-utils.ts @@ -0,0 +1,5 @@ +export const DEFAULT_SUITE_TIMEOUT = 120_000 + +export function setDefaultSuiteTimeout(context: Mocha.Suite) { + context.timeout(DEFAULT_SUITE_TIMEOUT) +} diff --git a/apps/vscode-e2e/src/suite/tools/apply-diff.test.ts b/apps/vscode-e2e/src/suite/tools/apply-diff.test.ts index ac8ffa6f588..64d019aef01 100644 --- a/apps/vscode-e2e/src/suite/tools/apply-diff.test.ts +++ b/apps/vscode-e2e/src/suite/tools/apply-diff.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code apply_diff Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code apply_diff Tool", () => { let workspaceDir: string // Pre-created test files that will be used across tests @@ -491,9 +494,6 @@ ${testFile.content}\nAssume the file exists and you can modify it directly.`, }) test("Should handle apply_diff errors gracefully", async function () { - // Increase timeout for this specific test - this.timeout(90_000) - const api = globalThis.api const messages: ClineMessage[] = [] const testFile = testFiles.errorHandling @@ -605,9 +605,6 @@ Assume the file exists and you can modify it directly.`, }) test("Should apply multiple search/replace blocks to edit two separate functions", async function () { - // Increase timeout for this specific test - this.timeout(60_000) - const api = globalThis.api const messages: ClineMessage[] = [] const testFile = testFiles.multiSearchReplace diff --git a/apps/vscode-e2e/src/suite/tools/execute-command.test.ts b/apps/vscode-e2e/src/suite/tools/execute-command.test.ts index 7bed887e6d0..21933d0879f 100644 --- a/apps/vscode-e2e/src/suite/tools/execute-command.test.ts +++ b/apps/vscode-e2e/src/suite/tools/execute-command.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep, waitUntilCompleted } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code execute_command Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code execute_command Tool", () => { let workspaceDir: string // Pre-created test files that will be used across tests @@ -331,9 +334,6 @@ Avoid at all costs suggesting a command when using the attempt_completion tool`, }) test("Should execute multiple commands sequentially", async function () { - // Increase timeout for this test - this.timeout(90_000) - const api = globalThis.api const testFile = testFiles.multiCommand let taskStarted = false @@ -447,9 +447,6 @@ After both commands are executed, use the attempt_completion tool to complete th }) test("Should handle long-running commands", async function () { - // Increase timeout for this test - this.timeout(60_000) - const api = globalThis.api let taskStarted = false let _taskCompleted = false diff --git a/apps/vscode-e2e/src/suite/tools/insert-content.test.ts b/apps/vscode-e2e/src/suite/tools/insert-content.test.ts index c98c30cb460..c9d65d0d0be 100644 --- a/apps/vscode-e2e/src/suite/tools/insert-content.test.ts +++ b/apps/vscode-e2e/src/suite/tools/insert-content.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code insert_content Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code insert_content Tool", () => { let workspaceDir: string // Pre-created test files that will be used across tests diff --git a/apps/vscode-e2e/src/suite/tools/list-files.test.ts b/apps/vscode-e2e/src/suite/tools/list-files.test.ts index d6dec5f8994..5340a13a161 100644 --- a/apps/vscode-e2e/src/suite/tools/list-files.test.ts +++ b/apps/vscode-e2e/src/suite/tools/list-files.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code list_files Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code list_files Tool", () => { let workspaceDir: string let testFiles: { rootFile1: string diff --git a/apps/vscode-e2e/src/suite/tools/read-file.test.ts b/apps/vscode-e2e/src/suite/tools/read-file.test.ts index 026fbd588d4..007e88b21c8 100644 --- a/apps/vscode-e2e/src/suite/tools/read-file.test.ts +++ b/apps/vscode-e2e/src/suite/tools/read-file.test.ts @@ -7,8 +7,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code read_file Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code read_file Tool", () => { let tempDir: string let testFiles: { simple: string @@ -118,7 +121,6 @@ suite("Roo Code read_file Tool", () => { }) test("Should read a simple text file", async function () { - this.timeout(90_000) // Increase timeout for this test const api = globalThis.api const messages: ClineMessage[] = [] let taskStarted = false @@ -264,7 +266,6 @@ suite("Roo Code read_file Tool", () => { }) test("Should read a multiline file", async function () { - this.timeout(90_000) // Increase timeout const api = globalThis.api const messages: ClineMessage[] = [] let taskCompleted = false @@ -376,7 +377,6 @@ suite("Roo Code read_file Tool", () => { }) test("Should read file with line range", async function () { - this.timeout(90_000) // Increase timeout const api = globalThis.api const messages: ClineMessage[] = [] let taskCompleted = false @@ -562,7 +562,6 @@ suite("Roo Code read_file Tool", () => { }) test("Should read XML content file", async function () { - this.timeout(90_000) // Increase timeout const api = globalThis.api const messages: ClineMessage[] = [] let taskCompleted = false @@ -634,7 +633,6 @@ suite("Roo Code read_file Tool", () => { }) test("Should read multiple files in sequence", async function () { - this.timeout(90_000) // Increase timeout const api = globalThis.api const messages: ClineMessage[] = [] let taskCompleted = false @@ -708,7 +706,6 @@ Assume both files exist and you can read them directly. Read each file and tell }) test("Should read large file efficiently", async function () { - this.timeout(90_000) // Increase timeout const api = globalThis.api const messages: ClineMessage[] = [] let taskCompleted = false diff --git a/apps/vscode-e2e/src/suite/tools/search-and-replace.test.ts b/apps/vscode-e2e/src/suite/tools/search-and-replace.test.ts index 7f404dd4020..459b1093501 100644 --- a/apps/vscode-e2e/src/suite/tools/search-and-replace.test.ts +++ b/apps/vscode-e2e/src/suite/tools/search-and-replace.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code search_and_replace Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code search_and_replace Tool", () => { let workspaceDir: string // Pre-created test files that will be used across tests @@ -253,9 +256,6 @@ Assume the file exists and you can modify it directly.`, }) test("Should perform regex pattern replacement", async function () { - // Increase timeout for this test - this.timeout(90_000) - const api = globalThis.api const messages: ClineMessage[] = [] const testFile = testFiles.regexReplace diff --git a/apps/vscode-e2e/src/suite/tools/search-files.test.ts b/apps/vscode-e2e/src/suite/tools/search-files.test.ts index b0faeeed798..cc28739943e 100644 --- a/apps/vscode-e2e/src/suite/tools/search-files.test.ts +++ b/apps/vscode-e2e/src/suite/tools/search-files.test.ts @@ -6,8 +6,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code search_files Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code search_files Tool", () => { let workspaceDir: string let testFiles: { jsFile: string diff --git a/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts b/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts index 0971ec44e15..df57ae88c62 100644 --- a/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts +++ b/apps/vscode-e2e/src/suite/tools/use-mcp-tool.test.ts @@ -7,8 +7,11 @@ import * as vscode from "vscode" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code use_mcp_tool Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code use_mcp_tool Tool", () => { let tempDir: string let testFiles: { simple: string diff --git a/apps/vscode-e2e/src/suite/tools/write-to-file.test.ts b/apps/vscode-e2e/src/suite/tools/write-to-file.test.ts index c07282bb874..814213b2bc6 100644 --- a/apps/vscode-e2e/src/suite/tools/write-to-file.test.ts +++ b/apps/vscode-e2e/src/suite/tools/write-to-file.test.ts @@ -6,8 +6,11 @@ import * as os from "os" import type { ClineMessage } from "@roo-code/types" import { waitFor, sleep } from "../utils" +import { setDefaultSuiteTimeout } from "../test-utils" + +suite("Roo Code write_to_file Tool", function () { + setDefaultSuiteTimeout(this) -suite("Roo Code write_to_file Tool", () => { let tempDir: string let testFilePath: string diff --git a/apps/web-evals/src/app/layout.tsx b/apps/web-evals/src/app/layout.tsx index 3bb34f7dfb8..32efce7a198 100644 --- a/apps/web-evals/src/app/layout.tsx +++ b/apps/web-evals/src/app/layout.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next" -import { Geist, Geist_Mono } from "next/font/google" +// Avoid downloading fonts in CI import { ThemeProvider, ReactQueryProvider } from "@/components/providers" import { Toaster } from "@/components/ui" @@ -7,8 +7,8 @@ import { Header } from "@/components/layout/header" import "./globals.css" -const fontSans = Geist({ variable: "--font-sans", subsets: ["latin"] }) -const fontMono = Geist_Mono({ variable: "--font-mono", subsets: ["latin"] }) +const fontSans = { variable: "" } +const fontMono = { variable: "" } export const metadata: Metadata = { title: "Roo Code Evals", diff --git a/apps/web-roo-code/src/app/layout.tsx b/apps/web-roo-code/src/app/layout.tsx index 23d67ea48f5..9b928c8ddc0 100644 --- a/apps/web-roo-code/src/app/layout.tsx +++ b/apps/web-roo-code/src/app/layout.tsx @@ -1,6 +1,6 @@ import React from "react" import type { Metadata } from "next" -import { Inter } from "next/font/google" +// Use default system fonts to avoid downloading at build time import { Providers } from "@/components/providers" @@ -8,7 +8,7 @@ import Shell from "./shell" import "./globals.css" -const inter = Inter({ subsets: ["latin"] }) +const inter = { className: "" } export const metadata: Metadata = { title: "Roo Code – Your AI-Powered Dev Team in VS Code", diff --git a/apps/web-roo-code/src/app/shell.tsx b/apps/web-roo-code/src/app/shell.tsx index 84a42bed21b..1e4e4384076 100644 --- a/apps/web-roo-code/src/app/shell.tsx +++ b/apps/web-roo-code/src/app/shell.tsx @@ -4,9 +4,12 @@ import { NavBar, Footer } from "@/components/chromes" // Invalidate cache when a request comes in, at most once every hour. export const revalidate = 3600 +// Skip static generation in CI to avoid network fetch failures +export const dynamic = "force-dynamic" export default async function Shell({ children }: { children: React.ReactNode }) { - const [stars, downloads] = await Promise.all([getGitHubStars(), getVSCodeDownloads()]) + const fetchStats = !process.env.CI + const [stars, downloads] = fetchStats ? await Promise.all([getGitHubStars(), getVSCodeDownloads()]) : [null, null] return (
diff --git a/apps/web-roo-code/src/lib/stats.ts b/apps/web-roo-code/src/lib/stats.ts index 4d43ca6ed68..35bb2190aa2 100644 --- a/apps/web-roo-code/src/lib/stats.ts +++ b/apps/web-roo-code/src/lib/stats.ts @@ -1,4 +1,7 @@ export async function getGitHubStars() { + if (process.env.CI) { + return null + } try { const res = await fetch("https://api.github.com/repos/RooCodeInc/Roo-Code") const data = await res.json() @@ -16,6 +19,9 @@ export async function getGitHubStars() { } export async function getVSCodeReviews() { + if (process.env.CI) { + return [] + } const res = await fetch("https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery", { method: "POST", headers: { @@ -60,6 +66,9 @@ export async function getVSCodeReviews() { } export async function getVSCodeDownloads() { + if (process.env.CI) { + return null + } const res = await fetch("https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery", { method: "POST", headers: { diff --git a/locales/ca/README.md b/locales/ca/README.md index 58bc761ba15..c653f54fbbb 100644 --- a/locales/ca/README.md +++ b/locales/ca/README.md @@ -186,34 +186,35 @@ Gràcies a tots els nostres col·laboradors que han ajudat a millorar Roo Code! |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Llicència diff --git a/locales/de/README.md b/locales/de/README.md index 671bd503b74..24f1e4d69e5 100644 --- a/locales/de/README.md +++ b/locales/de/README.md @@ -186,34 +186,35 @@ Danke an alle unsere Mitwirkenden, die geholfen haben, Roo Code zu verbessern! |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Lizenz diff --git a/locales/es/README.md b/locales/es/README.md index 07635a2f1d5..adeca0a876c 100644 --- a/locales/es/README.md +++ b/locales/es/README.md @@ -186,34 +186,35 @@ Usamos [changesets](https://github.com/changesets/changesets) para versionar y p |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licencia diff --git a/locales/fr/README.md b/locales/fr/README.md index 45ef8c4208c..80140b85fb1 100644 --- a/locales/fr/README.md +++ b/locales/fr/README.md @@ -186,34 +186,35 @@ Merci à tous nos contributeurs qui ont aidé à améliorer Roo Code ! |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licence diff --git a/locales/hi/README.md b/locales/hi/README.md index 24dc9d1d00f..9f20242d899 100644 --- a/locales/hi/README.md +++ b/locales/hi/README.md @@ -186,34 +186,35 @@ Roo Code को बेहतर बनाने में मदद करने |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## लाइसेंस diff --git a/locales/id/README.md b/locales/id/README.md index 0a0fe7bea54..3381b865b01 100644 --- a/locales/id/README.md +++ b/locales/id/README.md @@ -180,34 +180,35 @@ Terima kasih kepada semua kontributor kami yang telah membantu membuat Roo Code |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## License diff --git a/locales/it/README.md b/locales/it/README.md index fbae96f2dd4..964db4ff347 100644 --- a/locales/it/README.md +++ b/locales/it/README.md @@ -186,34 +186,35 @@ Grazie a tutti i nostri contributori che hanno aiutato a migliorare Roo Code! |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licenza diff --git a/locales/ja/README.md b/locales/ja/README.md index 63f0042a8b8..90c32409fcc 100644 --- a/locales/ja/README.md +++ b/locales/ja/README.md @@ -186,34 +186,35 @@ Roo Codeの改善に貢献してくれたすべての貢献者に感謝します |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## ライセンス diff --git a/locales/ko/README.md b/locales/ko/README.md index c218927831d..dce892ffb9e 100644 --- a/locales/ko/README.md +++ b/locales/ko/README.md @@ -186,34 +186,35 @@ Roo Code를 더 좋게 만드는 데 도움을 준 모든 기여자에게 감사 |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## 라이선스 diff --git a/locales/nl/README.md b/locales/nl/README.md index 0945b7ce7bf..7ca8251e73f 100644 --- a/locales/nl/README.md +++ b/locales/nl/README.md @@ -186,34 +186,35 @@ Dank aan alle bijdragers die Roo Code beter hebben gemaakt! |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licentie diff --git a/locales/pl/README.md b/locales/pl/README.md index a68c80ae8d4..351d755a295 100644 --- a/locales/pl/README.md +++ b/locales/pl/README.md @@ -186,34 +186,35 @@ Dziękujemy wszystkim naszym współtwórcom, którzy pomogli ulepszyć Roo Code |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licencja diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md index 0234615ac15..d773d8fcca5 100644 --- a/locales/pt-BR/README.md +++ b/locales/pt-BR/README.md @@ -186,34 +186,35 @@ Obrigado a todos os nossos contribuidores que ajudaram a tornar o Roo Code melho |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Licença diff --git a/locales/ru/README.md b/locales/ru/README.md index b2552de1ea1..368a70a9865 100644 --- a/locales/ru/README.md +++ b/locales/ru/README.md @@ -186,34 +186,35 @@ code --install-extension bin/roo-cline-.vsix |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Лицензия diff --git a/locales/tr/README.md b/locales/tr/README.md index 2c50fbc7f0c..6a039e79b11 100644 --- a/locales/tr/README.md +++ b/locales/tr/README.md @@ -186,34 +186,35 @@ Roo Code'u daha iyi hale getirmeye yardımcı olan tüm katkıda bulunanlara te |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Lisans diff --git a/locales/vi/README.md b/locales/vi/README.md index 4b3ae32f101..2e59bb759f7 100644 --- a/locales/vi/README.md +++ b/locales/vi/README.md @@ -186,34 +186,35 @@ Cảm ơn tất cả những người đóng góp đã giúp cải thiện Roo C |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## Giấy Phép diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md index 0c276b40c80..dc8b3389418 100644 --- a/locales/zh-CN/README.md +++ b/locales/zh-CN/README.md @@ -186,34 +186,35 @@ code --install-extension bin/roo-cline-.vsix |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## 许可证 diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md index db52894d671..85dfce876b5 100644 --- a/locales/zh-TW/README.md +++ b/locales/zh-TW/README.md @@ -187,34 +187,35 @@ code --install-extension bin/roo-cline-.vsix |KJ7LNW
KJ7LNW
|a8trejo
a8trejo
|ColemanRoo
ColemanRoo
|canrobins13
canrobins13
|stea9499
stea9499
|joemanley201
joemanley201
| |System233
System233
|jquanton
jquanton
|nissa-seru
nissa-seru
|NyxJae
NyxJae
|jr
jr
|MuriloFP
MuriloFP
| |elianiva
elianiva
|d-oit
d-oit
|punkpeye
punkpeye
|wkordalski
wkordalski
|sachasayan
sachasayan
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| -|monotykamary
monotykamary
|cannuri
cannuri
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
|xyOz-dev
xyOz-dev
| -|dtrugman
dtrugman
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|Szpadel
Szpadel
| +|monotykamary
monotykamary
|cannuri
cannuri
|xyOz-dev
xyOz-dev
|feifei325
feifei325
|zhangtony239
zhangtony239
|qdaxb
qdaxb
| +|shariqriazz
shariqriazz
|pugazhendhi-m
pugazhendhi-m
|vigneshsubbiah16
vigneshsubbiah16
|lloydchang
lloydchang
|dtrugman
dtrugman
|Szpadel
Szpadel
| |chrarnoldus
chrarnoldus
|diarmidmackenzie
diarmidmackenzie
|olweraltuve
olweraltuve
|psv2522
psv2522
|Premshay
Premshay
|lupuletic
lupuletic
| -|PeterDaveHello
PeterDaveHello
|aheizi
aheizi
|kiwina
kiwina
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| +|kiwina
kiwina
|aheizi
aheizi
|PeterDaveHello
PeterDaveHello
|afshawnlotfi
afshawnlotfi
|RaySinner
RaySinner
|nbihan-mediware
nbihan-mediware
| |ChuKhaLi
ChuKhaLi
|hassoncs
hassoncs
|emshvac
emshvac
|kyle-apex
kyle-apex
|noritaka1166
noritaka1166
|pdecat
pdecat
| -|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
|dleffel
dleffel
| -|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|SannidhyaSah
SannidhyaSah
|sammcj
sammcj
| +|SannidhyaSah
SannidhyaSah
|StevenTCramer
StevenTCramer
|Lunchb0ne
Lunchb0ne
|SmartManoj
SmartManoj
|vagadiya
vagadiya
|slytechnical
slytechnical
| +|dleffel
dleffel
|arthurauffray
arthurauffray
|upamune
upamune
|NamesMT
NamesMT
|taylorwilsdon
taylorwilsdon
|sammcj
sammcj
| |Ruakij
Ruakij
|p12tic
p12tic
|gtaylor
gtaylor
|aitoroses
aitoroses
|mr-ryan-james
mr-ryan-james
|heyseth
heyseth
| |taisukeoe
taisukeoe
|avtc
avtc
|dlab-anton
dlab-anton
|eonghk
eonghk
|kcwhite
kcwhite
|ronyblum
ronyblum
| |teddyOOXX
teddyOOXX
|vincentsong
vincentsong
|yongjer
yongjer
|zeozeozeo
zeozeozeo
|ashktn
ashktn
|franekp
franekp
| -|yt3trees
yt3trees
|anton-otee
anton-otee
|benzntech
benzntech
|axkirillov
axkirillov
|bramburn
bramburn
|olearycrew
olearycrew
| -|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|ross
ross
|philfung
philfung
|napter
napter
|mdp
mdp
| -|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
|kohii
kohii
|kinandan
kinandan
| -|jwcraig
jwcraig
|shoopapa
shoopapa
|im47cn
im47cn
|hongzio
hongzio
|hatsu38
hatsu38
|GOODBOY008
GOODBOY008
| -|forestyoo
forestyoo
|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|tgfjt
tgfjt
|axmo
axmo
| -|asychin
asychin
|amittell
amittell
|tmsjngx0
tmsjngx0
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
| -|vladstudio
vladstudio
|nevermorec
nevermorec
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
| -|student20880
student20880
|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|roomote
roomote
| -|robertheadley
robertheadley
|refactorthis
refactorthis
|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|oprstchn
oprstchn
| -|nobu007
nobu007
|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
| -|lightrabbit
lightrabbit
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| -|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|bogdan0083
bogdan0083
| -|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
|HadesArchitect
HadesArchitect
| -|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
|AMHesch
AMHesch
| -|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
|SECKainersdorfer
SECKainersdorfer
| -|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
|marvijo-code
marvijo-code
| -|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|KanTakahiro
KanTakahiro
|ksze
ksze
| -|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
|celestial-vault
celestial-vault
| | +|yt3trees
yt3trees
|benzntech
benzntech
|axkirillov
axkirillov
|anton-otee
anton-otee
|bramburn
bramburn
|olearycrew
olearycrew
| +|snoyiatk
snoyiatk
|GitlyHallows
GitlyHallows
|jcbdev
jcbdev
|Chenjiayuan195
Chenjiayuan195
|julionav
julionav
|SplittyDev
SplittyDev
| +|mdp
mdp
|napter
napter
|ross
ross
|philfung
philfung
|dairui1
dairui1
|dqroid
dqroid
| +|forestyoo
forestyoo
|GOODBOY008
GOODBOY008
|hatsu38
hatsu38
|hongzio
hongzio
|im47cn
im47cn
|shoopapa
shoopapa
| +|jwcraig
jwcraig
|kinandan
kinandan
|nevermorec
nevermorec
|bannzai
bannzai
|axmo
axmo
|asychin
asychin
| +|amittell
amittell
|Yoshino-Yukitaro
Yoshino-Yukitaro
|Yikai-Liao
Yikai-Liao
|zxdvd
zxdvd
|vladstudio
vladstudio
|tmsjngx0
tmsjngx0
| +|tgfjt
tgfjt
|PretzelVector
PretzelVector
|zetaloop
zetaloop
|cdlliuy
cdlliuy
|user202729
user202729
|student20880
student20880
| +|shohei-ihaya
shohei-ihaya
|shaybc
shaybc
|seedlord
seedlord
|samir-nimbly
samir-nimbly
|robertheadley
robertheadley
|refactorthis
refactorthis
| +|qingyuan1109
qingyuan1109
|pokutuna
pokutuna
|philipnext
philipnext
|village-way
village-way
|oprstchn
oprstchn
|nobu007
nobu007
| +|mosleyit
mosleyit
|moqimoqidea
moqimoqidea
|mlopezr
mlopezr
|mecab
mecab
|olup
olup
|lightrabbit
lightrabbit
| +|kohii
kohii
|linegel
linegel
|edwin-truthsearch-io
edwin-truthsearch-io
|EamonNerbonne
EamonNerbonne
|dbasclpy
dbasclpy
|dflatline
dflatline
| +|Deon588
Deon588
|dleen
dleen
|devxpain
devxpain
|chadgauth
chadgauth
|brunobergher
brunobergher
|thecolorblue
thecolorblue
| +|bogdan0083
bogdan0083
|Atlogit
Atlogit
|atlasgong
atlasgong
|andreastempsch
andreastempsch
|alasano
alasano
|QuinsZouls
QuinsZouls
| +|HadesArchitect
HadesArchitect
|alarno
alarno
|nexon33
nexon33
|adilhafeez
adilhafeez
|adamwlarson
adamwlarson
|adamhill
adamhill
| +|AMHesch
AMHesch
|maekawataiki
maekawataiki
|AlexandruSmirnov
AlexandruSmirnov
|samsilveira
samsilveira
|01Rian
01Rian
|RSO
RSO
| +|SECKainersdorfer
SECKainersdorfer
|R-omk
R-omk
|Sarke
Sarke
|kvokka
kvokka
|ecmasx
ecmasx
|mollux
mollux
| +|marvijo-code
marvijo-code
|mamertofabian
mamertofabian
|monkeyDluffy6017
monkeyDluffy6017
|libertyteeth
libertyteeth
|shtse8
shtse8
|Rexarrior
Rexarrior
| +|KanTakahiro
KanTakahiro
|ksze
ksze
|Jdo300
Jdo300
|hesara
hesara
|DeXtroTip
DeXtroTip
|pfitz
pfitz
| +|celestial-vault
celestial-vault
| | | | | | ## 授權 diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 6fb181b5734..7e58c158024 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -21,6 +21,10 @@ export interface RooCodeAPIEvents { taskCompleted: [taskId: string, tokenUsage: TokenUsage, toolUsage: ToolUsage, isSubtask: IsSubtask] taskTokenUsageUpdated: [taskId: string, tokenUsage: TokenUsage] taskToolFailed: [taskId: string, toolName: ToolName, error: string] + taskTimeoutWarning: [taskId: string, remainingMs: number] + taskTimedOut: [taskId: string] + taskTimeoutExtended: [taskId: string, newTimeoutMs: number] + taskTimeoutCleared: [taskId: string] } export interface RooCodeAPI extends EventEmitter { diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 5b729a125fb..3fe25787d43 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -49,6 +49,11 @@ export const globalSettingsSchema = z.object({ allowedMaxRequests: z.number().nullish(), autoCondenseContext: z.boolean().optional(), autoCondenseContextPercent: z.number().optional(), + + // Subtask timeout settings + defaultSubtaskTimeoutMs: z.number().optional(), + subtaskTimeoutWarningPercent: z.number().optional(), + maxSubtaskTimeoutExtensions: z.number().optional(), maxConcurrentFileReads: z.number().optional(), browserToolEnabled: z.boolean().optional(), @@ -103,6 +108,7 @@ export const globalSettingsSchema = z.object({ customSupportPrompts: customSupportPromptsSchema.optional(), enhancementApiConfigId: z.string().optional(), historyPreviewCollapsed: z.boolean().optional(), + profileThresholds: z.record(z.string(), z.number()).optional(), }) export type GlobalSettings = z.infer diff --git a/packages/types/src/ipc.ts b/packages/types/src/ipc.ts index 28accde9de5..1852ba7a380 100644 --- a/packages/types/src/ipc.ts +++ b/packages/types/src/ipc.ts @@ -29,6 +29,10 @@ export enum RooCodeEventName { TaskCompleted = "taskCompleted", TaskTokenUsageUpdated = "taskTokenUsageUpdated", TaskToolFailed = "taskToolFailed", + TaskTimeoutWarning = "taskTimeoutWarning", + TaskTimedOut = "taskTimedOut", + TaskTimeoutExtended = "taskTimeoutExtended", + TaskTimeoutCleared = "taskTimeoutCleared", EvalPass = "evalPass", EvalFail = "evalFail", } @@ -52,6 +56,10 @@ export const rooCodeEventsSchema = z.object({ [RooCodeEventName.TaskCompleted]: z.tuple([z.string(), tokenUsageSchema, toolUsageSchema, isSubtaskSchema]), [RooCodeEventName.TaskTokenUsageUpdated]: z.tuple([z.string(), tokenUsageSchema]), [RooCodeEventName.TaskToolFailed]: z.tuple([z.string(), toolNamesSchema, z.string()]), + [RooCodeEventName.TaskTimeoutWarning]: z.tuple([z.string(), z.number()]), + [RooCodeEventName.TaskTimedOut]: z.tuple([z.string()]), + [RooCodeEventName.TaskTimeoutExtended]: z.tuple([z.string(), z.number()]), + [RooCodeEventName.TaskTimeoutCleared]: z.tuple([z.string()]), }) export type RooCodeEvents = z.infer @@ -165,6 +173,26 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [ payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskToolFailed], taskId: z.number().optional(), }), + z.object({ + eventName: z.literal(RooCodeEventName.TaskTimeoutWarning), + payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskTimeoutWarning], + taskId: z.number().optional(), + }), + z.object({ + eventName: z.literal(RooCodeEventName.TaskTimedOut), + payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskTimedOut], + taskId: z.number().optional(), + }), + z.object({ + eventName: z.literal(RooCodeEventName.TaskTimeoutExtended), + payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskTimeoutExtended], + taskId: z.number().optional(), + }), + z.object({ + eventName: z.literal(RooCodeEventName.TaskTimeoutCleared), + payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskTimeoutCleared], + taskId: z.number().optional(), + }), z.object({ eventName: z.literal(RooCodeEventName.EvalPass), payload: z.undefined(), diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 5f1c08041f7..8b0624ef2af 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -8,6 +8,7 @@ export * from "./groq.js" export * from "./lite-llm.js" export * from "./lm-studio.js" export * from "./mistral.js" +export * from "./ollama.js" export * from "./openai.js" export * from "./openrouter.js" export * from "./requesty.js" diff --git a/packages/types/src/providers/lm-studio.ts b/packages/types/src/providers/lm-studio.ts index f83bbc10391..9e39ae56081 100644 --- a/packages/types/src/providers/lm-studio.ts +++ b/packages/types/src/providers/lm-studio.ts @@ -1 +1,19 @@ +import type { ModelInfo } from "../model.js" + export const LMSTUDIO_DEFAULT_TEMPERATURE = 0 + +// LM Studio +// https://lmstudio.ai/docs/cli/ls +export const lMStudioDefaultModelId = "mistralai/devstral-small-2505" +export const lMStudioDefaultModelInfo: ModelInfo = { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 0, + outputPrice: 0, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: "LM Studio hosted models", +} diff --git a/packages/types/src/providers/ollama.ts b/packages/types/src/providers/ollama.ts new file mode 100644 index 00000000000..d269da8f4d0 --- /dev/null +++ b/packages/types/src/providers/ollama.ts @@ -0,0 +1,17 @@ +import type { ModelInfo } from "../model.js" + +// Ollama +// https://ollama.com/models +export const ollamaDefaultModelId = "devstral:24b" +export const ollamaDefaultModelInfo: ModelInfo = { + maxTokens: 4096, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 0, + outputPrice: 0, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: "Ollama hosted models", +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 878c571f7a7..7ab6e2821f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -579,6 +579,9 @@ importers: '@google/genai': specifier: ^1.0.0 version: 1.3.0(@modelcontextprotocol/sdk@1.12.0) + '@lmstudio/sdk': + specifier: ^1.1.1 + version: 1.2.0 '@mistralai/mistralai': specifier: ^1.3.6 version: 1.6.1(zod@3.25.61) @@ -697,8 +700,8 @@ importers: specifier: ^5.0.0 version: 5.0.0 pretty-bytes: - specifier: ^6.1.1 - version: 6.1.1 + specifier: ^7.0.0 + version: 7.0.0 ps-tree: specifier: ^1.2.0 version: 1.2.0 @@ -718,8 +721,8 @@ importers: specifier: ^0.16.0 version: 0.16.0 serialize-error: - specifier: ^11.0.3 - version: 11.0.3 + specifier: ^12.0.0 + version: 12.0.0 simple-git: specifier: ^3.27.0 version: 3.27.0 @@ -971,8 +974,8 @@ importers: specifier: ^1.227.2 version: 1.242.1 pretty-bytes: - specifier: ^6.1.1 - version: 6.1.1 + specifier: ^7.0.0 + version: 7.0.0 react: specifier: ^18.3.1 version: 18.3.1 @@ -1025,8 +1028,8 @@ importers: specifier: ^6.1.13 version: 6.1.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwind-merge: - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^3.0.0 + version: 3.3.0 tailwindcss: specifier: ^4.0.0 version: 4.1.6 @@ -2024,6 +2027,12 @@ packages: cpu: [x64] os: [win32] + '@lmstudio/lms-isomorphic@0.4.5': + resolution: {integrity: sha512-Or9KS1Iz3LC7D7WMe4zbqAqKOlDsVcrvMoQFBhmydzzxOg+eYBM5gtfgMMjcwjM0BuUVPhYOjTWEyfXpqfVJzg==} + + '@lmstudio/sdk@1.2.0': + resolution: {integrity: sha512-Eoolmi1cSuGXmLYwtn6pD9eOwjMTb+bQ4iv+i/EYz/hCc+HtbfJamoKfyyw4FogRc03RHsXHe1X18voR40D+2g==} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -3835,8 +3844,8 @@ packages: '@types/node@20.17.57': resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==} - '@types/node@20.19.0': - resolution: {integrity: sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==} + '@types/node@20.19.1': + resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} '@types/node@22.15.29': resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==} @@ -6587,6 +6596,9 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonschema@1.5.0: + resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} + jsonwebtoken@9.0.2: resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} engines: {node: '>=12', npm: '>=6'} @@ -7901,9 +7913,9 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-bytes@6.1.1: - resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} - engines: {node: ^14.13.1 || >=16.0.0} + pretty-bytes@7.0.0: + resolution: {integrity: sha512-U5otLYPR3L0SVjHGrkEUx5mf7MxV2ceXeE7VwWPk+hyzC5drNohsOGNPDZqxCqyX1lkbEN4kl1LiI8QFd7r0ZA==} + engines: {node: '>=20'} pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} @@ -8383,9 +8395,9 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} - serialize-error@11.0.3: - resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} - engines: {node: '>=14.16'} + serialize-error@12.0.0: + resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} + engines: {node: '>=18'} serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -8788,9 +8800,6 @@ packages: tabbable@5.3.3: resolution: {integrity: sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==} - tailwind-merge@2.6.0: - resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} - tailwind-merge@3.3.0: resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==} @@ -9054,9 +9063,9 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} type-is@2.0.1: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} @@ -11054,6 +11063,24 @@ snapshots: '@libsql/win32-x64-msvc@0.5.13': optional: true + '@lmstudio/lms-isomorphic@0.4.5': + dependencies: + ws: 8.18.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@lmstudio/sdk@1.2.0': + dependencies: + '@lmstudio/lms-isomorphic': 0.4.5 + chalk: 4.1.2 + jsonschema: 1.5.0 + zod: 3.25.61 + zod-to-json-schema: 3.24.5(zod@3.25.61) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.27.4 @@ -12995,7 +13022,7 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@20.19.0': + '@types/node@20.19.1': dependencies: undici-types: 6.21.0 optional: true @@ -13044,7 +13071,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 20.19.0 + '@types/node': 20.19.1 optional: true '@types/yargs-parser@21.0.3': {} @@ -13217,7 +13244,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.14 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.57)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.29)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) '@vitest/utils@3.2.4': dependencies: @@ -16106,6 +16133,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonschema@1.5.0: {} + jsonwebtoken@9.0.2: dependencies: jws: 3.2.2 @@ -17698,7 +17727,7 @@ snapshots: prettier@3.5.3: {} - pretty-bytes@6.1.1: {} + pretty-bytes@7.0.0: {} pretty-format@27.5.1: dependencies: @@ -18350,9 +18379,9 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-error@11.0.3: + serialize-error@12.0.0: dependencies: - type-fest: 2.19.0 + type-fest: 4.41.0 serialize-javascript@6.0.2: dependencies: @@ -18812,8 +18841,6 @@ snapshots: tabbable@5.3.3: {} - tailwind-merge@2.6.0: {} - tailwind-merge@3.3.0: {} tailwindcss-animate@1.0.7(tailwindcss@3.4.17): @@ -19090,7 +19117,7 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@2.19.0: {} + type-fest@4.41.0: {} type-is@2.0.1: dependencies: diff --git a/scripts/update-contributors.js b/scripts/update-contributors.js old mode 100755 new mode 100644 index 32fd645f68e..6bd4c35f0ca --- a/scripts/update-contributors.js +++ b/scripts/update-contributors.js @@ -183,9 +183,15 @@ async function readReadme() { * @param {Array} contributors Array of contributor objects from GitHub API * @returns {string} HTML for contributors section */ +const EXCLUDED_LOGIN_SUBSTRINGS = ['[bot]', 'R00-B0T']; +const EXCLUDED_LOGIN_EXACTS = ['cursor', 'roomote']; + function formatContributorsSection(contributors) { - // Filter out GitHub Actions bot - const filteredContributors = contributors.filter((c) => !c.login.includes("[bot]") && !c.login.includes("R00-B0T")) + // Filter out GitHub Actions bot, cursor, and roomote + const filteredContributors = contributors.filter((c) => + !EXCLUDED_LOGIN_SUBSTRINGS.some(sub => c.login.includes(sub)) && + !EXCLUDED_LOGIN_EXACTS.includes(c.login) + ) // Start building with Markdown table format let markdown = `${START_MARKER} diff --git a/src/api/providers/fetchers/__tests__/fixtures/lmstudio-model-details.json b/src/api/providers/fetchers/__tests__/fixtures/lmstudio-model-details.json new file mode 100644 index 00000000000..43f5505710a --- /dev/null +++ b/src/api/providers/fetchers/__tests__/fixtures/lmstudio-model-details.json @@ -0,0 +1,14 @@ +{ + "mistralai/devstral-small-2505": { + "type": "llm", + "modelKey": "mistralai/devstral-small-2505", + "format": "safetensors", + "displayName": "Devstral Small 2505", + "path": "mistralai/devstral-small-2505", + "sizeBytes": 13277565112, + "architecture": "mistral", + "vision": false, + "trainedForToolUse": false, + "maxContextLength": 131072 + } +} diff --git a/src/api/providers/fetchers/__tests__/fixtures/ollama-model-details.json b/src/api/providers/fetchers/__tests__/fixtures/ollama-model-details.json new file mode 100644 index 00000000000..e0b6ac03d9b --- /dev/null +++ b/src/api/providers/fetchers/__tests__/fixtures/ollama-model-details.json @@ -0,0 +1,58 @@ +{ + "qwen3-2to16:latest": { + "license": " Apache License\\n Version 2.0, January 2004\\n...", + "modelfile": "model.modelfile,# To build a new Modelfile based on this, replace FROM with:...", + "parameters": "repeat_penalty 1\\nstop \\\\nstop...", + "template": "{{- if .Messages }}\\n{{- if or .System .Tools }}<|im_start|>system...", + "details": { + "parent_model": "/Users/brad/.ollama/models/blobs/sha256-3291abe70f16ee9682de7bfae08db5373ea9d6497e614aaad63340ad421d6312", + "format": "gguf", + "family": "qwen3", + "families": ["qwen3"], + "parameter_size": "32.8B", + "quantization_level": "Q4_K_M" + }, + "model_info": { + "general.architecture": "qwen3", + "general.basename": "Qwen3", + "general.file_type": 15, + "general.parameter_count": 32762123264, + "general.quantization_version": 2, + "general.size_label": "32B", + "general.type": "model", + "qwen3.attention.head_count": 64, + "qwen3.attention.head_count_kv": 8, + "qwen3.attention.key_length": 128, + "qwen3.attention.layer_norm_rms_epsilon": 0.000001, + "qwen3.attention.value_length": 128, + "qwen3.block_count": 64, + "qwen3.context_length": 40960, + "qwen3.embedding_length": 5120, + "qwen3.feed_forward_length": 25600, + "qwen3.rope.freq_base": 1000000, + "tokenizer.ggml.add_bos_token": false, + "tokenizer.ggml.bos_token_id": 151643, + "tokenizer.ggml.eos_token_id": 151645, + "tokenizer.ggml.merges": null, + "tokenizer.ggml.model": "gpt2", + "tokenizer.ggml.padding_token_id": 151643, + "tokenizer.ggml.pre": "qwen2", + "tokenizer.ggml.token_type": null, + "tokenizer.ggml.tokens": null + }, + "tensors": [ + { + "name": "output.weight", + "type": "Q6_K", + "shape": [5120, 151936] + }, + { + "name": "output_norm.weight", + "type": "F32", + "shape": [5120] + } + ], + "capabilities": ["completion", "tools"], + "modified_at": "2025-06-02T22:16:13.644123606-04:00" + } +} diff --git a/src/api/providers/fetchers/__tests__/lmstudio.test.ts b/src/api/providers/fetchers/__tests__/lmstudio.test.ts new file mode 100644 index 00000000000..59b43887852 --- /dev/null +++ b/src/api/providers/fetchers/__tests__/lmstudio.test.ts @@ -0,0 +1,197 @@ +import axios from "axios" +import { vi, describe, it, expect, beforeEach } from "vitest" +import { LMStudioClient, LLM, LLMInstanceInfo } from "@lmstudio/sdk" // LLMInfo is a type +import { getLMStudioModels, parseLMStudioModel } from "../lmstudio" +import { ModelInfo, lMStudioDefaultModelInfo } from "@roo-code/types" // ModelInfo is a type + +// Mock axios +vi.mock("axios") +const mockedAxios = axios as any + +// Mock @lmstudio/sdk +const mockGetModelInfo = vi.fn() +const mockListLoaded = vi.fn() +vi.mock("@lmstudio/sdk", () => { + return { + LMStudioClient: vi.fn().mockImplementation(() => ({ + llm: { + listLoaded: mockListLoaded, + }, + })), + } +}) +const MockedLMStudioClientConstructor = LMStudioClient as any + +describe("LMStudio Fetcher", () => { + beforeEach(() => { + vi.clearAllMocks() + MockedLMStudioClientConstructor.mockClear() + mockListLoaded.mockClear() + mockGetModelInfo.mockClear() + }) + + describe("parseLMStudioModel", () => { + it("should correctly parse raw LLMInfo to ModelInfo", () => { + const rawModel: LLMInstanceInfo = { + type: "llm", + modelKey: "mistralai/devstral-small-2505", + format: "safetensors", + displayName: "Devstral Small 2505", + path: "mistralai/devstral-small-2505", + sizeBytes: 13277565112, + architecture: "mistral", + identifier: "mistralai/devstral-small-2505", + instanceReference: "RAP5qbeHVjJgBiGFQ6STCuTJ", + vision: false, + trainedForToolUse: false, + maxContextLength: 131072, + contextLength: 7161, + } + + const expectedModelInfo: ModelInfo = { + ...lMStudioDefaultModelInfo, + description: `${rawModel.displayName} - ${rawModel.path}`, + contextWindow: rawModel.contextLength, + supportsPromptCache: true, + supportsImages: rawModel.vision, + supportsComputerUse: false, + maxTokens: rawModel.contextLength, + inputPrice: 0, + outputPrice: 0, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + } + + const result = parseLMStudioModel(rawModel) + expect(result).toEqual(expectedModelInfo) + }) + }) + + describe("getLMStudioModels", () => { + const baseUrl = "http://localhost:1234" + const lmsUrl = "ws://localhost:1234" + + const mockRawModel: LLMInstanceInfo = { + architecture: "test-arch", + identifier: "mistralai/devstral-small-2505", + instanceReference: "RAP5qbeHVjJgBiGFQ6STCuTJ", + modelKey: "test-model-key-1", + path: "/path/to/test-model-1", + type: "llm", + displayName: "Test Model One", + maxContextLength: 2048, + contextLength: 7161, + paramsString: "1B params, 2k context", + vision: true, + format: "gguf", + sizeBytes: 1000000000, + trainedForToolUse: false, // Added + } + + it("should fetch and parse models successfully", async () => { + mockedAxios.get.mockResolvedValueOnce({ data: { status: "ok" } }) + mockListLoaded.mockResolvedValueOnce([{ getModelInfo: mockGetModelInfo }]) + mockGetModelInfo.mockResolvedValueOnce(mockRawModel) + + const result = await getLMStudioModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/v1/models`) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledTimes(1) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledWith({ baseUrl: lmsUrl }) + expect(mockListLoaded).toHaveBeenCalledTimes(1) + + const expectedParsedModel = parseLMStudioModel(mockRawModel) + expect(result).toEqual({ [mockRawModel.modelKey]: expectedParsedModel }) + }) + + it("should use default baseUrl if an empty string is provided", async () => { + const defaultBaseUrl = "http://localhost:1234" + const defaultLmsUrl = "ws://localhost:1234" + mockedAxios.get.mockResolvedValueOnce({ data: {} }) + mockListLoaded.mockResolvedValueOnce([]) + + await getLMStudioModels("") + + expect(mockedAxios.get).toHaveBeenCalledWith(`${defaultBaseUrl}/v1/models`) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledWith({ baseUrl: defaultLmsUrl }) + }) + + it("should transform https baseUrl to wss for LMStudioClient", async () => { + const httpsBaseUrl = "https://securehost:4321" + const wssLmsUrl = "wss://securehost:4321" + mockedAxios.get.mockResolvedValueOnce({ data: {} }) + mockListLoaded.mockResolvedValueOnce([]) + + await getLMStudioModels(httpsBaseUrl) + + expect(mockedAxios.get).toHaveBeenCalledWith(`${httpsBaseUrl}/v1/models`) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledWith({ baseUrl: wssLmsUrl }) + }) + + it("should return an empty object if lmsUrl is unparsable", async () => { + const unparsableBaseUrl = "http://localhost:invalid:port" // Leads to ws://localhost:invalid:port + + const result = await getLMStudioModels(unparsableBaseUrl) + + expect(result).toEqual({}) + expect(mockedAxios.get).not.toHaveBeenCalled() + expect(MockedLMStudioClientConstructor).not.toHaveBeenCalled() + }) + + it("should return an empty object and log error if axios.get fails with a generic error", async () => { + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}) + const networkError = new Error("Network connection failed") + mockedAxios.get.mockRejectedValueOnce(networkError) + + const result = await getLMStudioModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/v1/models`) + expect(MockedLMStudioClientConstructor).not.toHaveBeenCalled() + expect(mockListLoaded).not.toHaveBeenCalled() + expect(consoleErrorSpy).toHaveBeenCalledWith( + `Error fetching LMStudio models: ${JSON.stringify(networkError, Object.getOwnPropertyNames(networkError), 2)}`, + ) + expect(result).toEqual({}) + consoleErrorSpy.mockRestore() + }) + + it("should return an empty object and log info if axios.get fails with ECONNREFUSED", async () => { + const consoleInfoSpy = vi.spyOn(console, "warn").mockImplementation(() => {}) + const econnrefusedError = new Error("Connection refused") + ;(econnrefusedError as any).code = "ECONNREFUSED" + mockedAxios.get.mockRejectedValueOnce(econnrefusedError) + + const result = await getLMStudioModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/v1/models`) + expect(MockedLMStudioClientConstructor).not.toHaveBeenCalled() + expect(mockListLoaded).not.toHaveBeenCalled() + expect(consoleInfoSpy).toHaveBeenCalledWith(`Error connecting to LMStudio at ${baseUrl}`) + expect(result).toEqual({}) + consoleInfoSpy.mockRestore() + }) + + it("should return an empty object and log error if listDownloadedModels fails", async () => { + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}) + const listError = new Error("LMStudio SDK internal error") + + mockedAxios.get.mockResolvedValueOnce({ data: {} }) + mockListLoaded.mockRejectedValueOnce(listError) + + const result = await getLMStudioModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledTimes(1) + expect(MockedLMStudioClientConstructor).toHaveBeenCalledWith({ baseUrl: lmsUrl }) + expect(mockListLoaded).toHaveBeenCalledTimes(1) + expect(consoleErrorSpy).toHaveBeenCalledWith( + `Error fetching LMStudio models: ${JSON.stringify(listError, Object.getOwnPropertyNames(listError), 2)}`, + ) + expect(result).toEqual({}) + consoleErrorSpy.mockRestore() + }) + }) +}) diff --git a/src/api/providers/fetchers/__tests__/ollama.test.ts b/src/api/providers/fetchers/__tests__/ollama.test.ts new file mode 100644 index 00000000000..cada0a4b603 --- /dev/null +++ b/src/api/providers/fetchers/__tests__/ollama.test.ts @@ -0,0 +1,133 @@ +import axios from "axios" +import path from "path" +import { vi, describe, it, expect, beforeEach } from "vitest" +import { getOllamaModels, parseOllamaModel } from "../ollama" +import ollamaModelsData from "./fixtures/ollama-model-details.json" + +// Mock axios +vi.mock("axios") +const mockedAxios = axios as any + +describe("Ollama Fetcher", () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + describe("parseOllamaModel", () => { + it("should correctly parse Ollama model info", () => { + const modelData = ollamaModelsData["qwen3-2to16:latest"] + const parsedModel = parseOllamaModel(modelData) + + expect(parsedModel).toEqual({ + maxTokens: 40960, + contextWindow: 40960, + supportsImages: false, + supportsComputerUse: false, + supportsPromptCache: true, + inputPrice: 0, + outputPrice: 0, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: "Family: qwen3, Context: 40960, Size: 32.8B", + }) + }) + }) + + describe("getOllamaModels", () => { + it("should fetch model list from /api/tags and details for each model from /api/show", async () => { + const baseUrl = "http://localhost:11434" + const modelName = "devstral2to16:latest" + + const mockApiTagsResponse = { + models: [ + { + name: modelName, + model: modelName, + modified_at: "2025-06-03T09:23:22.610222878-04:00", + size: 14333928010, + digest: "6a5f0c01d2c96c687d79e32fdd25b87087feb376bf9838f854d10be8cf3c10a5", + details: { + family: "llama", + families: ["llama"], + format: "gguf", + parameter_size: "23.6B", + parent_model: "", + quantization_level: "Q4_K_M", + }, + }, + ], + } + const mockApiShowResponse = { + license: "Mock License", + modelfile: "FROM /path/to/blob\nTEMPLATE {{ .Prompt }}", + parameters: "num_ctx 4096\nstop_token ", + template: "{{ .System }}USER: {{ .Prompt }}ASSISTANT:", + modified_at: "2025-06-03T09:23:22.610222878-04:00", + details: { + parent_model: "", + format: "gguf", + family: "llama", + families: ["llama"], + parameter_size: "23.6B", + quantization_level: "Q4_K_M", + }, + model_info: { + "ollama.context_length": 4096, + "some.other.info": "value", + }, + capabilities: ["completion"], + } + + mockedAxios.get.mockResolvedValueOnce({ data: mockApiTagsResponse }) + mockedAxios.post.mockResolvedValueOnce({ data: mockApiShowResponse }) + + const result = await getOllamaModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`) + + expect(mockedAxios.post).toHaveBeenCalledTimes(1) + expect(mockedAxios.post).toHaveBeenCalledWith(`${baseUrl}/api/show`, { model: modelName }) + + expect(typeof result).toBe("object") + expect(result).not.toBeInstanceOf(Array) + expect(Object.keys(result).length).toBe(1) + expect(result[modelName]).toBeDefined() + + const expectedParsedDetails = parseOllamaModel(mockApiShowResponse as any) + expect(result[modelName]).toEqual(expectedParsedDetails) + }) + + it("should return an empty list if the initial /api/tags call fails", async () => { + const baseUrl = "http://localhost:11434" + mockedAxios.get.mockRejectedValueOnce(new Error("Network error")) + const consoleInfoSpy = vi.spyOn(console, "error").mockImplementation(() => {}) // Spy and suppress output + + const result = await getOllamaModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`) + expect(mockedAxios.post).not.toHaveBeenCalled() + expect(result).toEqual({}) + }) + + it("should log an info message and return an empty object on ECONNREFUSED", async () => { + const baseUrl = "http://localhost:11434" + const consoleInfoSpy = vi.spyOn(console, "warn").mockImplementation(() => {}) // Spy and suppress output + + const econnrefusedError = new Error("Connection refused") as any + econnrefusedError.code = "ECONNREFUSED" + mockedAxios.get.mockRejectedValueOnce(econnrefusedError) + + const result = await getOllamaModels(baseUrl) + + expect(mockedAxios.get).toHaveBeenCalledTimes(1) + expect(mockedAxios.get).toHaveBeenCalledWith(`${baseUrl}/api/tags`) + expect(mockedAxios.post).not.toHaveBeenCalled() + expect(consoleInfoSpy).toHaveBeenCalledWith(`Failed connecting to Ollama at ${baseUrl}`) + expect(result).toEqual({}) + + consoleInfoSpy.mockRestore() // Restore original console.info + }) + }) +}) diff --git a/src/api/providers/fetchers/lmstudio.ts b/src/api/providers/fetchers/lmstudio.ts new file mode 100644 index 00000000000..ea1a590f1e2 --- /dev/null +++ b/src/api/providers/fetchers/lmstudio.ts @@ -0,0 +1,54 @@ +import { ModelInfo, lMStudioDefaultModelInfo } from "@roo-code/types" +import { LLM, LLMInfo, LLMInstanceInfo, LMStudioClient } from "@lmstudio/sdk" +import axios from "axios" + +export const parseLMStudioModel = (rawModel: LLMInstanceInfo): ModelInfo => { + const modelInfo: ModelInfo = Object.assign({}, lMStudioDefaultModelInfo, { + description: `${rawModel.displayName} - ${rawModel.path}`, + contextWindow: rawModel.contextLength, + supportsPromptCache: true, + supportsImages: rawModel.vision, + supportsComputerUse: false, + maxTokens: rawModel.contextLength, + }) + + return modelInfo +} + +export async function getLMStudioModels(baseUrl = "http://localhost:1234"): Promise> { + // clearing the input can leave an empty string; use the default in that case + baseUrl = baseUrl === "" ? "http://localhost:1234" : baseUrl + + const models: Record = {} + // ws is required to connect using the LMStudio library + const lmsUrl = baseUrl.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://") + + try { + if (!URL.canParse(lmsUrl)) { + return models + } + + // test the connection to LM Studio first + // errors will be caught further down + await axios.get(`${baseUrl}/v1/models`) + + const client = new LMStudioClient({ baseUrl: lmsUrl }) + const response = (await client.llm.listLoaded().then((models: LLM[]) => { + return Promise.all(models.map((m) => m.getModelInfo())) + })) as Array + + for (const lmstudioModel of response) { + models[lmstudioModel.modelKey] = parseLMStudioModel(lmstudioModel) + } + } catch (error) { + if (error.code === "ECONNREFUSED") { + console.warn(`Error connecting to LMStudio at ${baseUrl}`) + } else { + console.error( + `Error fetching LMStudio models: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + } + } + + return models +} diff --git a/src/api/providers/fetchers/modelCache.ts b/src/api/providers/fetchers/modelCache.ts index 12d636bc46c..5956187e417 100644 --- a/src/api/providers/fetchers/modelCache.ts +++ b/src/api/providers/fetchers/modelCache.ts @@ -14,6 +14,9 @@ import { getGlamaModels } from "./glama" import { getUnboundModels } from "./unbound" import { getLiteLLMModels } from "./litellm" import { GetModelsOptions } from "../../../shared/api" +import { getOllamaModels } from "./ollama" +import { getLMStudioModels } from "./lmstudio" + const memoryCache = new NodeCache({ stdTTL: 5 * 60, checkperiod: 5 * 60 }) async function writeModels(router: RouterName, data: ModelRecord) { @@ -68,6 +71,12 @@ export const getModels = async (options: GetModelsOptions): Promise // Type safety ensures apiKey and baseUrl are always provided for litellm models = await getLiteLLMModels(options.apiKey, options.baseUrl) break + case "ollama": + models = await getOllamaModels(options.baseUrl) + break + case "lmstudio": + models = await getLMStudioModels(options.baseUrl) + break default: { // Ensures router is exhaustively checked if RouterName is a strict union const exhaustiveCheck: never = provider diff --git a/src/api/providers/fetchers/ollama.ts b/src/api/providers/fetchers/ollama.ts new file mode 100644 index 00000000000..8de2c1a918c --- /dev/null +++ b/src/api/providers/fetchers/ollama.ts @@ -0,0 +1,100 @@ +import axios from "axios" +import { ModelInfo, ollamaDefaultModelInfo } from "@roo-code/types" +import { z } from "zod" + +const OllamaModelDetailsSchema = z.object({ + family: z.string(), + families: z.array(z.string()), + format: z.string(), + parameter_size: z.string(), + parent_model: z.string(), + quantization_level: z.string(), +}) + +const OllamaModelSchema = z.object({ + details: OllamaModelDetailsSchema, + digest: z.string(), + model: z.string(), + modified_at: z.string(), + name: z.string(), + size: z.number(), +}) + +const OllamaModelInfoResponseSchema = z.object({ + modelfile: z.string(), + parameters: z.string(), + template: z.string(), + details: OllamaModelDetailsSchema, + model_info: z.record(z.string(), z.any()), + capabilities: z.array(z.string()).optional(), +}) + +const OllamaModelsResponseSchema = z.object({ + models: z.array(OllamaModelSchema), +}) + +type OllamaModelsResponse = z.infer + +type OllamaModelInfoResponse = z.infer + +export const parseOllamaModel = (rawModel: OllamaModelInfoResponse): ModelInfo => { + const contextKey = Object.keys(rawModel.model_info).find((k) => k.includes("context_length")) + const contextWindow = + contextKey && typeof rawModel.model_info[contextKey] === "number" ? rawModel.model_info[contextKey] : undefined + + const modelInfo: ModelInfo = Object.assign({}, ollamaDefaultModelInfo, { + description: `Family: ${rawModel.details.family}, Context: ${contextWindow}, Size: ${rawModel.details.parameter_size}`, + contextWindow: contextWindow || ollamaDefaultModelInfo.contextWindow, + supportsPromptCache: true, + supportsImages: rawModel.capabilities?.includes("vision"), + supportsComputerUse: false, + maxTokens: contextWindow || ollamaDefaultModelInfo.contextWindow, + }) + + return modelInfo +} + +export async function getOllamaModels(baseUrl = "http://localhost:11434"): Promise> { + const models: Record = {} + + // clearing the input can leave an empty string; use the default in that case + baseUrl = baseUrl === "" ? "http://localhost:11434" : baseUrl + + try { + if (!URL.canParse(baseUrl)) { + return models + } + + const response = await axios.get(`${baseUrl}/api/tags`) + const parsedResponse = OllamaModelsResponseSchema.safeParse(response.data) + let modelInfoPromises = [] + + if (parsedResponse.success) { + for (const ollamaModel of parsedResponse.data.models) { + modelInfoPromises.push( + axios + .post(`${baseUrl}/api/show`, { + model: ollamaModel.model, + }) + .then((ollamaModelInfo) => { + models[ollamaModel.name] = parseOllamaModel(ollamaModelInfo.data) + }), + ) + } + + await Promise.all(modelInfoPromises) + } else { + console.error(`Error parsing Ollama models response: ${JSON.stringify(parsedResponse.error, null, 2)}`) + } + } catch (error) { + if (error.code === "ECONNREFUSED") { + console.warn(`Failed connecting to Ollama at ${baseUrl}`) + } else { + console.error( + `Error fetching Ollama models: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + } + } + + return models +} diff --git a/src/api/providers/ollama.ts b/src/api/providers/ollama.ts index 7f384e9a989..a7713ba4214 100644 --- a/src/api/providers/ollama.ts +++ b/src/api/providers/ollama.ts @@ -1,6 +1,5 @@ import { Anthropic } from "@anthropic-ai/sdk" import OpenAI from "openai" -import axios from "axios" import { type ModelInfo, openAiModelInfoSaneDefaults, DEEP_SEEK_DEFAULT_TEMPERATURE } from "@roo-code/types" @@ -111,17 +110,3 @@ export class OllamaHandler extends BaseProvider implements SingleCompletionHandl } } } - -export async function getOllamaModels(baseUrl = "http://localhost:11434") { - try { - if (!URL.canParse(baseUrl)) { - return [] - } - - const response = await axios.get(`${baseUrl}/api/tags`) - const modelsArray = response.data?.models?.map((model: any) => model.name) || [] - return [...new Set(modelsArray)] - } catch (error) { - return [] - } -} diff --git a/src/core/condense/index.ts b/src/core/condense/index.ts index 8a8b57bb0ca..3b73b1915c6 100644 --- a/src/core/condense/index.ts +++ b/src/core/condense/index.ts @@ -8,6 +8,8 @@ import { ApiMessage } from "../task-persistence/apiMessages" import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning" export const N_MESSAGES_TO_KEEP = 3 +export const MIN_CONDENSE_THRESHOLD = 5 // Minimum percentage of context window to trigger condensing +export const MAX_CONDENSE_THRESHOLD = 100 // Maximum percentage of context window to trigger condensing 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. diff --git a/src/core/prompts/tools/new-task.ts b/src/core/prompts/tools/new-task.ts index 7301b7b422d..a652f4aa7ce 100644 --- a/src/core/prompts/tools/new-task.ts +++ b/src/core/prompts/tools/new-task.ts @@ -7,17 +7,20 @@ Description: This will let you create a new task instance in the chosen mode usi Parameters: - 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. +- timeout_seconds: (optional) Number of seconds after which the subtask will automatically timeout and be aborted. If not specified, uses default timeout setting. Usage: your-mode-slug-here Your initial instructions here +300 Example: code Implement a new feature for the application. +600 ` } diff --git a/src/core/sliding-window/__tests__/sliding-window.spec.ts b/src/core/sliding-window/__tests__/sliding-window.spec.ts index 0f41942547f..3bda5351d42 100644 --- a/src/core/sliding-window/__tests__/sliding-window.spec.ts +++ b/src/core/sliding-window/__tests__/sliding-window.spec.ts @@ -19,7 +19,14 @@ import { // Create a mock ApiHandler for testing class MockApiHandler extends BaseProvider { createMessage(): any { - throw new Error("Method not implemented.") + // Mock implementation for testing - returns an async iterable stream + const mockStream = { + async *[Symbol.asyncIterator]() { + yield { type: "text", text: "Mock summary content" } + yield { type: "usage", inputTokens: 100, outputTokens: 50 } + }, + } + return mockStream } getModel(): { id: string; info: ModelInfo } { @@ -265,6 +272,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Check the new return type @@ -304,6 +313,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result).toEqual({ @@ -337,6 +348,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) const result2 = await truncateConversationIfNeeded({ @@ -349,6 +362,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result1.messages).toEqual(result2.messages) @@ -368,6 +383,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) const result4 = await truncateConversationIfNeeded({ @@ -380,6 +397,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result3.messages).toEqual(result4.messages) @@ -414,6 +433,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(resultWithSmall).toEqual({ messages: messagesWithSmallContent, @@ -447,6 +468,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(resultWithLarge.messages).not.toEqual(messagesWithLargeContent) // Should truncate expect(resultWithLarge.summary).toBe("") @@ -473,6 +496,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(resultWithVeryLarge.messages).not.toEqual(messagesWithVeryLargeContent) // Should truncate expect(resultWithVeryLarge.summary).toBe("") @@ -509,6 +534,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result).toEqual({ messages: expectedResult, @@ -554,6 +581,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Verify summarizeConversation was called with the right parameters @@ -619,6 +648,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Verify summarizeConversation was called @@ -664,6 +695,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 50, // This shouldn't matter since autoCondenseContext is false systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Verify summarizeConversation was not called @@ -719,6 +752,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 50, // Set threshold to 50% - our tokens are at 60% systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Verify summarizeConversation was called with the right parameters @@ -769,6 +804,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 50, // Set threshold to 50% - our tokens are at 40% systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) // Verify summarizeConversation was not called @@ -787,6 +824,212 @@ describe("Sliding Window", () => { }) }) + /** + * Tests for profile-specific thresholds functionality + */ + describe("profile-specific thresholds", () => { + const createModelInfo = (contextWindow: number, maxTokens?: number): ModelInfo => ({ + contextWindow, + supportsPromptCache: true, + maxTokens, + }) + + const messages: ApiMessage[] = [ + { role: "user", content: "First message" }, + { role: "assistant", content: "Second message" }, + { role: "user", content: "Third message" }, + { role: "assistant", content: "Fourth message" }, + { role: "user", content: "Fifth message" }, + ] + + /** + * Test that a profile's specific threshold is correctly used instead of the global threshold + * when defined in profileThresholds + */ + it("should use profile-specific threshold when enabled and profile has specific threshold", async () => { + const modelInfo = createModelInfo(100000, 30000) + const profileThresholds = { + "test-profile": 60, // Profile-specific threshold of 60% + } + const currentProfileId = "test-profile" + const contextWindow = modelInfo.contextWindow + + // Set tokens to 65% of context window - above profile threshold (60%) but below global default (100%) + const totalTokens = Math.floor(contextWindow * 0.65) // 65000 tokens + + // Create messages with very small content in the last one to avoid token overflow + const messagesWithSmallContent = [ + ...messages.slice(0, -1), + { ...messages[messages.length - 1], content: "" }, + ] + + // Mock the summarizeConversation function + const mockSummary = "Profile-specific threshold summary" + const mockCost = 0.03 + const mockSummarizeResponse: condenseModule.SummarizeResponse = { + messages: [ + { role: "user", content: "First message" }, + { role: "assistant", content: mockSummary, isSummary: true }, + { role: "user", content: "Last message" }, + ], + summary: mockSummary, + cost: mockCost, + newContextTokens: 100, + } + + const summarizeSpy = vi + .spyOn(condenseModule, "summarizeConversation") + .mockResolvedValue(mockSummarizeResponse) + + const result = await truncateConversationIfNeeded({ + messages: messagesWithSmallContent, + totalTokens, + contextWindow, + maxTokens: modelInfo.maxTokens, + apiHandler: mockApiHandler, + autoCondenseContext: true, + autoCondenseContextPercent: 100, // Global threshold of 100% + systemPrompt: "System prompt", + taskId, + profileThresholds, + currentProfileId, + }) + + // Should use summarization because 65% > 60% (profile threshold) + expect(summarizeSpy).toHaveBeenCalled() + expect(result).toMatchObject({ + messages: mockSummarizeResponse.messages, + summary: mockSummary, + cost: mockCost, + prevContextTokens: totalTokens, + }) + + // Clean up + summarizeSpy.mockRestore() + }) + + /** + * Test that when a profile's threshold is set to -1, + * the function correctly falls back to using the global autoCondenseContextPercent + */ + it("should fall back to global threshold when profile threshold is -1", async () => { + const modelInfo = createModelInfo(100000, 30000) + const profileThresholds = { + "test-profile": -1, // Profile threshold set to -1 (use global) + } + const currentProfileId = "test-profile" + const contextWindow = modelInfo.contextWindow + + // Set tokens to 80% of context window - above global threshold (75%) but would be below if profile had its own + const totalTokens = Math.floor(contextWindow * 0.8) // 80000 tokens + + // Create messages with very small content in the last one to avoid token overflow + const messagesWithSmallContent = [ + ...messages.slice(0, -1), + { ...messages[messages.length - 1], content: "" }, + ] + + // Mock the summarizeConversation function + const mockSummary = "Global threshold fallback summary" + const mockCost = 0.04 + const mockSummarizeResponse: condenseModule.SummarizeResponse = { + messages: [ + { role: "user", content: "First message" }, + { role: "assistant", content: mockSummary, isSummary: true }, + { role: "user", content: "Last message" }, + ], + summary: mockSummary, + cost: mockCost, + newContextTokens: 120, + } + + const summarizeSpy = vi + .spyOn(condenseModule, "summarizeConversation") + .mockResolvedValue(mockSummarizeResponse) + + const result = await truncateConversationIfNeeded({ + messages: messagesWithSmallContent, + totalTokens, + contextWindow, + maxTokens: modelInfo.maxTokens, + apiHandler: mockApiHandler, + autoCondenseContext: true, + autoCondenseContextPercent: 75, // Global threshold of 75% + systemPrompt: "System prompt", + taskId, + profileThresholds, + currentProfileId, + }) + + // Should use summarization because 80% > 75% (global threshold, since profile is -1) + expect(summarizeSpy).toHaveBeenCalled() + expect(result).toMatchObject({ + messages: mockSummarizeResponse.messages, + summary: mockSummary, + cost: mockCost, + prevContextTokens: totalTokens, + }) + + // Clean up + summarizeSpy.mockRestore() + }) + + /** + * Test that when a profile does not have a specific threshold defined, + * the function correctly falls back to the global default + */ + it("should fall back to global threshold when profile has no specific threshold", async () => { + const modelInfo = createModelInfo(100000, 30000) + const profileThresholds = { + "other-profile": 50, // Different profile has a threshold + } + const currentProfileId = "test-profile" // This profile is not in profileThresholds + const contextWindow = modelInfo.contextWindow + + // Calculate allowedTokens: contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens + // allowedTokens = 100000 * 0.9 - 30000 = 60000 + // Set tokens to be below both the global threshold (80%) and allowedTokens + const totalTokens = 50000 // 50% of context window, well below 60000 allowedTokens and 80% threshold + + // Create messages with very small content in the last one to avoid token overflow + const messagesWithSmallContent = [ + ...messages.slice(0, -1), + { ...messages[messages.length - 1], content: "" }, + ] + + // Reset any previous mock calls + vi.clearAllMocks() + const summarizeSpy = vi.spyOn(condenseModule, "summarizeConversation") + + const result = await truncateConversationIfNeeded({ + messages: messagesWithSmallContent, + totalTokens, + contextWindow, + maxTokens: modelInfo.maxTokens, + apiHandler: mockApiHandler, + autoCondenseContext: true, + autoCondenseContextPercent: 80, // Global threshold of 80% + systemPrompt: "System prompt", + taskId, + profileThresholds, + currentProfileId, + }) + + // Should NOT use summarization because 50% < 80% (global threshold, since profile has no specific threshold) + // and totalTokens (50000) < allowedTokens (60000) + expect(summarizeSpy).not.toHaveBeenCalled() + expect(result).toEqual({ + messages: messagesWithSmallContent, + summary: "", + cost: 0, + prevContextTokens: totalTokens, + }) + + // Clean up + summarizeSpy.mockRestore() + }) + }) + /** * Tests for the getMaxTokens function (private but tested through truncateConversationIfNeeded) */ @@ -829,6 +1072,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result1).toEqual({ messages: messagesWithSmallContent, @@ -848,6 +1093,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result2.messages).not.toEqual(messagesWithSmallContent) expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction @@ -878,6 +1125,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result1).toEqual({ messages: messagesWithSmallContent, @@ -897,6 +1146,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result2.messages).not.toEqual(messagesWithSmallContent) expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction @@ -926,6 +1177,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result1.messages).toEqual(messagesWithSmallContent) @@ -940,6 +1193,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result2).not.toEqual(messagesWithSmallContent) expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction @@ -967,6 +1222,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result1.messages).toEqual(messagesWithSmallContent) @@ -981,6 +1238,8 @@ describe("Sliding Window", () => { autoCondenseContextPercent: 100, systemPrompt: "System prompt", taskId, + profileThresholds: {}, + currentProfileId: "default", }) expect(result2).not.toEqual(messagesWithSmallContent) expect(result2.messages.length).toBe(3) // Truncated with 0.5 fraction diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index dc9eaf718d5..ae26f51a520 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -3,7 +3,7 @@ import { Anthropic } from "@anthropic-ai/sdk" import { TelemetryService } from "@roo-code/telemetry" import { ApiHandler } from "../../api" -import { summarizeConversation, SummarizeResponse } from "../condense" +import { MAX_CONDENSE_THRESHOLD, MIN_CONDENSE_THRESHOLD, summarizeConversation, SummarizeResponse } from "../condense" import { ApiMessage } from "../task-persistence/apiMessages" /** @@ -74,6 +74,8 @@ type TruncateOptions = { taskId: string customCondensingPrompt?: string condensingApiHandler?: ApiHandler + profileThresholds: Record + currentProfileId: string } type TruncateResponse = SummarizeResponse & { prevContextTokens: number } @@ -97,6 +99,8 @@ export async function truncateConversationIfNeeded({ taskId, customCondensingPrompt, condensingApiHandler, + profileThresholds, + currentProfileId, }: TruncateOptions): Promise { let error: string | undefined let cost = 0 @@ -117,9 +121,29 @@ export async function truncateConversationIfNeeded({ // Truncate if we're within TOKEN_BUFFER_PERCENTAGE of the context window const allowedTokens = contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens + // Determine the effective threshold to use + let effectiveThreshold = autoCondenseContextPercent + const profileThreshold = profileThresholds[currentProfileId] + if (profileThreshold !== undefined) { + if (profileThreshold === -1) { + // Special case: -1 means inherit from global setting + effectiveThreshold = autoCondenseContextPercent + } else if (profileThreshold >= MIN_CONDENSE_THRESHOLD && profileThreshold <= MAX_CONDENSE_THRESHOLD) { + // Valid custom threshold + effectiveThreshold = profileThreshold + } else { + // Invalid threshold value, fall back to global setting + console.warn( + `Invalid profile threshold ${profileThreshold} for profile "${currentProfileId}". Using global default of ${autoCondenseContextPercent}%`, + ) + effectiveThreshold = autoCondenseContextPercent + } + } + // If no specific threshold is found for the profile, fall back to global setting + if (autoCondenseContext) { const contextPercent = (100 * prevContextTokens) / contextWindow - if (contextPercent >= autoCondenseContextPercent || prevContextTokens > allowedTokens) { + if (contextPercent >= effectiveThreshold || prevContextTokens > allowedTokens) { // Attempt to intelligently condense the context const result = await summarizeConversation( messages, diff --git a/src/core/task/SubtaskTimeoutManager.ts b/src/core/task/SubtaskTimeoutManager.ts new file mode 100644 index 00000000000..13e7459afa0 --- /dev/null +++ b/src/core/task/SubtaskTimeoutManager.ts @@ -0,0 +1,157 @@ +export interface TimeoutConfig { + timeoutMs: number + warningMs?: number + onTimeout: (taskId: string) => void + onWarning?: (taskId: string, remainingMs: number) => void + onExtended?: (taskId: string, newTimeoutMs: number) => void + onCleared?: (taskId: string) => void +} + +export interface TimeoutStatus { + taskId: string + startTime: number + timeoutMs: number + warningMs?: number + hasWarned: boolean + isActive: boolean +} + +export class SubtaskTimeoutManager { + private timeouts: Map = new Map() + private warnings: Map = new Map() + private statuses: Map = new Map() + + startTimeout(taskId: string, config: TimeoutConfig): void { + this.clearTimeout(taskId) + + const status: TimeoutStatus = { + taskId, + startTime: Date.now(), + timeoutMs: config.timeoutMs, + warningMs: config.warningMs, + hasWarned: false, + isActive: true, + } + + this.statuses.set(taskId, status) + + if (config.warningMs && config.onWarning) { + const warningTimeout = setTimeout(() => { + const currentStatus = this.statuses.get(taskId) + if (currentStatus && currentStatus.isActive && !currentStatus.hasWarned) { + currentStatus.hasWarned = true + const remainingMs = Math.max(0, config.timeoutMs - config.warningMs!) + config.onWarning!(taskId, remainingMs) + } + }, config.warningMs) + + this.warnings.set(taskId, warningTimeout) + } + + const timeoutHandle = setTimeout(() => { + const currentStatus = this.statuses.get(taskId) + if (currentStatus && currentStatus.isActive) { + currentStatus.isActive = false + this.clearTimeout(taskId) + config.onTimeout(taskId) + } + }, config.timeoutMs) + + this.timeouts.set(taskId, timeoutHandle) + } + + extendTimeout(taskId: string, extensionMs: number, config?: TimeoutConfig): boolean { + const status = this.statuses.get(taskId) + if (!status || !status.isActive) { + return false + } + + this.clearTimeout(taskId) + + const elapsed = Date.now() - status.startTime + const newTimeoutMs = status.timeoutMs + extensionMs + const remainingWarningMs = status.warningMs ? Math.max(0, status.warningMs - elapsed) : undefined + + const newStatus: TimeoutStatus = { + ...status, + timeoutMs: newTimeoutMs, + hasWarned: elapsed >= (status.warningMs || Infinity), + } + + this.statuses.set(taskId, newStatus) + + if (config) { + const adjustedConfig: TimeoutConfig = { + ...config, + timeoutMs: newTimeoutMs - elapsed, + warningMs: remainingWarningMs, + } + + this.startTimeout(taskId, adjustedConfig) + config.onExtended?.(taskId, newTimeoutMs) + } + + return true + } + + clearTimeout(taskId: string): boolean { + const timeoutHandle = this.timeouts.get(taskId) + const warningHandle = this.warnings.get(taskId) + const status = this.statuses.get(taskId) + + if (timeoutHandle) { + clearTimeout(timeoutHandle) + this.timeouts.delete(taskId) + } + + if (warningHandle) { + clearTimeout(warningHandle) + this.warnings.delete(taskId) + } + + if (status) { + status.isActive = false + this.statuses.delete(taskId) + return true + } + + return false + } + + getTimeRemaining(taskId: string): number { + const status = this.statuses.get(taskId) + if (!status || !status.isActive) { + return 0 + } + + const elapsed = Date.now() - status.startTime + return Math.max(0, status.timeoutMs - elapsed) + } + + getStatus(taskId: string): TimeoutStatus | undefined { + return this.statuses.get(taskId) + } + + isActive(taskId: string): boolean { + const status = this.statuses.get(taskId) + return status?.isActive ?? false + } + + getActiveTimeouts(): string[] { + return Array.from(this.statuses.entries()) + .filter(([, status]) => status.isActive) + .map(([taskId]) => taskId) + } + + dispose(): void { + for (const timeoutHandle of this.timeouts.values()) { + clearTimeout(timeoutHandle) + } + for (const warningHandle of this.warnings.values()) { + clearTimeout(warningHandle) + } + this.timeouts.clear() + this.warnings.clear() + this.statuses.clear() + } +} diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 6f6f2d684af..0a0121c5163 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -85,6 +85,7 @@ import { processUserContentMentions } from "../mentions/processUserContentMentio import { ApiMessage } from "../task-persistence/apiMessages" import { getMessagesSinceLastSummary, summarizeConversation } from "../condense" import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning" +import { SubtaskTimeoutManager, type TimeoutConfig, type TimeoutStatus } from "./SubtaskTimeoutManager" export type ClineEvents = { message: [{ action: "created" | "updated"; message: ClineMessage }] @@ -98,6 +99,10 @@ export type ClineEvents = { taskCompleted: [taskId: string, tokenUsage: TokenUsage, toolUsage: ToolUsage] taskTokenUsageUpdated: [taskId: string, tokenUsage: TokenUsage] taskToolFailed: [taskId: string, tool: ToolName, error: string] + taskTimeoutWarning: [taskId: string, remainingMs: number] + taskTimedOut: [taskId: string] + taskTimeoutExtended: [taskId: string, newTimeoutMs: number] + taskTimeoutCleared: [taskId: string] } export type TaskOptions = { @@ -116,6 +121,7 @@ export type TaskOptions = { parentTask?: Task taskNumber?: number onCreated?: (cline: Task) => void + subtaskTimeoutMs?: number } export class Task extends EventEmitter { @@ -137,6 +143,10 @@ export class Task extends EventEmitter { pausedModeSlug: string = defaultModeSlug private pauseInterval: NodeJS.Timeout | undefined + // Timeout Management + private timeoutManager: SubtaskTimeoutManager + private subtaskTimeoutMs?: number + // API readonly apiConfiguration: ProviderSettings api: ApiHandler @@ -217,6 +227,7 @@ export class Task extends EventEmitter { parentTask, taskNumber = -1, onCreated, + subtaskTimeoutMs, }: TaskOptions) { super() @@ -282,6 +293,8 @@ export class Task extends EventEmitter { } this.toolRepetitionDetector = new ToolRepetitionDetector(this.consecutiveMistakeLimit) + this.timeoutManager = new SubtaskTimeoutManager() + this.subtaskTimeoutMs = subtaskTimeoutMs onCreated?.(this) @@ -1017,6 +1030,13 @@ export class Task extends EventEmitter { this.pauseInterval = undefined } + // Clean up timeout manager + try { + this.timeoutManager.dispose() + } catch (error) { + console.error("Error disposing timeout manager:", error) + } + // Release any terminals associated with this task. try { // Release any terminals associated with this task. @@ -1643,6 +1663,7 @@ export class Task extends EventEmitter { mode, autoCondenseContext = true, autoCondenseContextPercent = 100, + profileThresholds = {}, } = state ?? {} // Get condensing configuration for automatic triggers @@ -1719,6 +1740,8 @@ export class Task extends EventEmitter { taskId: this.taskId, customCondensingPrompt, condensingApiHandler, + profileThresholds, + currentProfileId: state?.currentApiConfigName || "default", }) if (truncateResult.messages !== this.apiConversationHistory) { await this.overwriteApiConversationHistory(truncateResult.messages) @@ -1905,6 +1928,82 @@ export class Task extends EventEmitter { } } + // Timeout Management + + public startSubtaskTimeout(subtaskId: string, timeoutMs?: number): void { + const actualTimeoutMs = timeoutMs || this.subtaskTimeoutMs + if (!actualTimeoutMs) { + return + } + + const config: TimeoutConfig = { + timeoutMs: actualTimeoutMs, + warningMs: Math.floor(actualTimeoutMs * 0.8), // Warn at 80% + onTimeout: (taskId: string) => { + this.emit("taskTimedOut", taskId) + const provider = this.providerRef.deref() + if (provider) { + provider.abortSubtask(taskId) + } + }, + onWarning: (taskId: string, remainingMs: number) => { + this.emit("taskTimeoutWarning", taskId, remainingMs) + }, + onExtended: (taskId: string, newTimeoutMs: number) => { + this.emit("taskTimeoutExtended", taskId, newTimeoutMs) + }, + onCleared: (taskId: string) => { + this.emit("taskTimeoutCleared", taskId) + }, + } + + this.timeoutManager.startTimeout(subtaskId, config) + } + + public extendSubtaskTimeout(subtaskId: string, extensionMs: number): boolean { + const config: TimeoutConfig = { + timeoutMs: 0, // Will be calculated by manager + onTimeout: (taskId: string) => { + this.emit("taskTimedOut", taskId) + const provider = this.providerRef.deref() + if (provider) { + provider.abortSubtask(taskId) + } + }, + onWarning: (taskId: string, remainingMs: number) => { + this.emit("taskTimeoutWarning", taskId, remainingMs) + }, + onExtended: (taskId: string, newTimeoutMs: number) => { + this.emit("taskTimeoutExtended", taskId, newTimeoutMs) + }, + onCleared: (taskId: string) => { + this.emit("taskTimeoutCleared", taskId) + }, + } + + return this.timeoutManager.extendTimeout(subtaskId, extensionMs, config) + } + + public clearSubtaskTimeout(subtaskId: string): boolean { + const result = this.timeoutManager.clearTimeout(subtaskId) + if (result) { + this.emit("taskTimeoutCleared", subtaskId) + } + return result + } + + public getSubtaskTimeoutStatus(subtaskId: string): TimeoutStatus | undefined { + return this.timeoutManager.getStatus(subtaskId) + } + + public getSubtaskTimeRemaining(subtaskId: string): number { + return this.timeoutManager.getTimeRemaining(subtaskId) + } + + public isSubtaskTimeoutActive(subtaskId: string): boolean { + return this.timeoutManager.isActive(subtaskId) + } + // Getters public get cwd() { diff --git a/src/core/task/__tests__/SubtaskTimeoutManager.test.ts b/src/core/task/__tests__/SubtaskTimeoutManager.test.ts new file mode 100644 index 00000000000..c33265d1538 --- /dev/null +++ b/src/core/task/__tests__/SubtaskTimeoutManager.test.ts @@ -0,0 +1,222 @@ +import { jest } from "@jest/globals" +import { SubtaskTimeoutManager, type TimeoutConfig } from "../SubtaskTimeoutManager" + +describe("SubtaskTimeoutManager", () => { + let manager: SubtaskTimeoutManager + let mockOnTimeout: jest.MockedFunction<(taskId: string) => void> + let mockOnWarning: jest.MockedFunction<(taskId: string, remainingMs: number) => void> + + beforeEach(() => { + jest.useFakeTimers() + manager = new SubtaskTimeoutManager() + mockOnTimeout = jest.fn() + mockOnWarning = jest.fn() + }) + + afterEach(() => { + manager.dispose() + jest.useRealTimers() + }) + + describe("startTimeout", () => { + it("should start a timeout for a task", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + + expect(manager.isActive("task1")).toBe(true) + expect(manager.getTimeRemaining("task1")).toBe(5000) + }) + + it("should call onTimeout when timeout expires", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + + jest.advanceTimersByTime(5000) + + expect(mockOnTimeout).toHaveBeenCalledWith("task1") + expect(manager.isActive("task1")).toBe(false) + }) + + it("should call onWarning at the specified time", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + warningMs: 2000, + onTimeout: mockOnTimeout, + onWarning: mockOnWarning, + } + + manager.startTimeout("task1", config) + + jest.advanceTimersByTime(2000) + + expect(mockOnWarning).toHaveBeenCalledWith("task1", 3000) + expect(mockOnTimeout).not.toHaveBeenCalled() + }) + + it("should replace existing timeout when starting new one for same task", () => { + const config1: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + const config2: TimeoutConfig = { + timeoutMs: 10000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config1) + manager.startTimeout("task1", config2) + + jest.advanceTimersByTime(5000) + expect(mockOnTimeout).not.toHaveBeenCalled() + expect(manager.isActive("task1")).toBe(true) + + jest.advanceTimersByTime(5000) + expect(mockOnTimeout).toHaveBeenCalledWith("task1") + }) + }) + + describe("extendTimeout", () => { + it("should extend an active timeout", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + onExtended: jest.fn(), + } + + manager.startTimeout("task1", config) + jest.advanceTimersByTime(2000) + + const result = manager.extendTimeout("task1", 3000, config) + + expect(result).toBe(true) + expect(manager.getTimeRemaining("task1")).toBeGreaterThan(5000) + }) + + it("should return false for inactive task", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + const result = manager.extendTimeout("nonexistent", 3000, config) + expect(result).toBe(false) + }) + + it("should call onExtended callback when extending", () => { + const mockOnExtended = jest.fn() + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + onExtended: mockOnExtended, + } + + manager.startTimeout("task1", config) + manager.extendTimeout("task1", 3000, config) + + expect(mockOnExtended).toHaveBeenCalledWith("task1", 8000) + }) + }) + + describe("clearTimeout", () => { + it("should clear an active timeout", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + const result = manager.clearTimeout("task1") + + expect(result).toBe(true) + expect(manager.isActive("task1")).toBe(false) + + jest.advanceTimersByTime(5000) + expect(mockOnTimeout).not.toHaveBeenCalled() + }) + + it("should return false for non-existent task", () => { + const result = manager.clearTimeout("nonexistent") + expect(result).toBe(false) + }) + }) + + describe("getTimeRemaining", () => { + it("should return correct remaining time", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + jest.advanceTimersByTime(2000) + + const remaining = manager.getTimeRemaining("task1") + expect(remaining).toBe(3000) + }) + + it("should return 0 for inactive task", () => { + const remaining = manager.getTimeRemaining("nonexistent") + expect(remaining).toBe(0) + }) + }) + + describe("getActiveTimeouts", () => { + it("should return list of active timeout task IDs", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + manager.startTimeout("task2", config) + + const active = manager.getActiveTimeouts() + expect(active).toEqual(expect.arrayContaining(["task1", "task2"])) + expect(active).toHaveLength(2) + }) + + it("should not include expired timeouts", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + manager.startTimeout("task2", config) + + jest.advanceTimersByTime(5000) + + const active = manager.getActiveTimeouts() + expect(active).toHaveLength(0) + }) + }) + + describe("dispose", () => { + it("should clear all timeouts and statuses", () => { + const config: TimeoutConfig = { + timeoutMs: 5000, + onTimeout: mockOnTimeout, + } + + manager.startTimeout("task1", config) + manager.startTimeout("task2", config) + + manager.dispose() + + expect(manager.getActiveTimeouts()).toHaveLength(0) + expect(manager.isActive("task1")).toBe(false) + expect(manager.isActive("task2")).toBe(false) + + jest.advanceTimersByTime(5000) + expect(mockOnTimeout).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/core/tools/newTaskTool.ts b/src/core/tools/newTaskTool.ts index ab2519e9b46..98c140820df 100644 --- a/src/core/tools/newTaskTool.ts +++ b/src/core/tools/newTaskTool.ts @@ -16,6 +16,7 @@ export async function newTaskTool( ) { const mode: string | undefined = block.params.mode const message: string | undefined = block.params.message + const timeoutSeconds: string | undefined = block.params.timeout_seconds try { if (block.partial) { @@ -23,6 +24,7 @@ export async function newTaskTool( tool: "newTask", mode: removeClosingTag("mode", mode), message: removeClosingTag("message", message), + timeout_seconds: removeClosingTag("timeout_seconds", timeoutSeconds), }) await cline.ask("tool", partialMessage, block.partial).catch(() => {}) @@ -47,6 +49,17 @@ export async function newTaskTool( // Un-escape one level: \\@ -> \@ (removes one backslash for hierarchical subtasks) const unescapedMessage = message.replace(/\\\\@/g, "\\@") + // Parse timeout if provided + let timeoutMs: number | undefined + if (timeoutSeconds) { + const parsedTimeout = parseInt(timeoutSeconds, 10) + if (isNaN(parsedTimeout) || parsedTimeout <= 0) { + pushToolResult(formatResponse.toolError("Invalid timeout_seconds: must be a positive number")) + return + } + timeoutMs = parsedTimeout * 1000 // Convert to milliseconds + } + // Verify the mode exists const targetMode = getModeBySlug(mode, (await cline.providerRef.deref()?.getState())?.customModes) @@ -59,6 +72,7 @@ export async function newTaskTool( tool: "newTask", mode: targetMode.name, content: message, + timeout_seconds: timeoutSeconds ? parseInt(timeoutSeconds, 10) : undefined, }) const didApprove = await askApproval("tool", toolMessage) @@ -86,13 +100,18 @@ export async function newTaskTool( // Delay to allow mode change to take effect before next tool is executed. await delay(500) - const newCline = await provider.initClineWithTask(unescapedMessage, undefined, cline) + const newCline = await provider.initClineWithTask(unescapedMessage, undefined, cline, timeoutMs) if (!newCline) { pushToolResult(t("tools:newTask.errors.policy_restriction")) return } cline.emit("taskSpawned", newCline.taskId) + // Start timeout if specified + if (timeoutMs) { + cline.startSubtaskTimeout(newCline.taskId, timeoutMs) + } + pushToolResult(`Successfully created new task in ${targetMode.name} mode with message: ${unescapedMessage}`) // Set the isPaused flag to true so the parent diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 49fd0c1258f..8bf8f901a2e 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -239,6 +239,32 @@ export class ClineProvider await this.removeClineFromStack() } + // Abort a specific subtask by taskId (used for timeout scenarios) + async abortSubtask(taskId: string) { + console.log(`[subtasks] aborting subtask ${taskId} due to timeout`) + + // Find the task in the stack + const taskIndex = this.clineStack.findIndex((task) => task.taskId === taskId) + if (taskIndex === -1) { + console.warn(`[subtasks] task ${taskId} not found in stack for abortion`) + return + } + + const task = this.clineStack[taskIndex] + + // If it's the current task (top of stack), handle like normal cancellation + if (taskIndex === this.clineStack.length - 1) { + await this.finishSubTask("Task timed out and was aborted") + } else { + // If it's not the current task, abort it directly and remove from stack + await task.abortTask(true) + this.clineStack.splice(taskIndex, 1) + + // Update UI to reflect stack change + await this.postStateToWebview() + } + } + /* VSCode extensions use the disposable pattern to clean up resources when the sidebar/editor tab is closed by the user or system. This applies to event listening, commands, interacting with the UI, etc. - https://vscode-docs.readthedocs.io/en/stable/extensions/patterns-and-principles/ @@ -526,6 +552,7 @@ export class ClineProvider task?: string, images?: string[], parentTask?: Task, + subtaskTimeoutMs?: number, options: Partial< Pick< TaskOptions, @@ -559,6 +586,7 @@ export class ClineProvider parentTask, taskNumber: this.clineStack.length + 1, onCreated: (cline) => this.emit("clineCreated", cline), + subtaskTimeoutMs, ...options, }) @@ -1376,6 +1404,7 @@ export class ClineProvider customCondensingPrompt, codebaseIndexConfig, codebaseIndexModels, + profileThresholds, } = await this.getState() const telemetryKey = process.env.POSTHOG_API_KEY @@ -1483,6 +1512,7 @@ export class ClineProvider codebaseIndexEmbedderModelId: "", }, mdmCompliant: this.checkMdmCompliance(), + profileThresholds: profileThresholds ?? {}, } } @@ -1632,6 +1662,7 @@ export class ClineProvider codebaseIndexEmbedderBaseUrl: "", codebaseIndexEmbedderModelId: "", }, + profileThresholds: stateValues.profileThresholds ?? {}, } } diff --git a/src/core/webview/__tests__/ClineProvider.spec.ts b/src/core/webview/__tests__/ClineProvider.spec.ts index de4f34a12ac..fabb0aae60b 100644 --- a/src/core/webview/__tests__/ClineProvider.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.spec.ts @@ -522,6 +522,7 @@ describe("ClineProvider", () => { autoCondenseContextPercent: 100, cloudIsAuthenticated: false, sharingEnabled: false, + profileThresholds: {}, } const message: ExtensionMessage = { @@ -2266,6 +2267,8 @@ describe("ClineProvider - Router Models", () => { glama: mockModels, unbound: mockModels, litellm: mockModels, + ollama: {}, + lmstudio: {}, }, }) }) @@ -2308,6 +2311,8 @@ describe("ClineProvider - Router Models", () => { requesty: {}, glama: mockModels, unbound: {}, + ollama: {}, + lmstudio: {}, litellm: {}, }, }) @@ -2327,6 +2332,13 @@ describe("ClineProvider - Router Models", () => { values: { provider: "unbound" }, }) + expect(mockPostMessage).toHaveBeenCalledWith({ + type: "singleRouterModelFetchResponse", + success: false, + error: "Unbound API error", + values: { provider: "unbound" }, + }) + expect(mockPostMessage).toHaveBeenCalledWith({ type: "singleRouterModelFetchResponse", success: false, @@ -2410,6 +2422,8 @@ describe("ClineProvider - Router Models", () => { glama: mockModels, unbound: mockModels, litellm: {}, + ollama: {}, + lmstudio: {}, }, }) }) diff --git a/src/core/webview/__tests__/webviewMessageHandler.spec.ts b/src/core/webview/__tests__/webviewMessageHandler.spec.ts index e15b18ccdb4..46ace3ce85b 100644 --- a/src/core/webview/__tests__/webviewMessageHandler.spec.ts +++ b/src/core/webview/__tests__/webviewMessageHandler.spec.ts @@ -73,6 +73,8 @@ describe("webviewMessageHandler - requestRouterModels", () => { glama: mockModels, unbound: mockModels, litellm: mockModels, + ollama: {}, + lmstudio: {}, }, }) }) @@ -158,6 +160,8 @@ describe("webviewMessageHandler - requestRouterModels", () => { glama: mockModels, unbound: mockModels, litellm: {}, + ollama: {}, + lmstudio: {}, }, }) }) @@ -193,6 +197,8 @@ describe("webviewMessageHandler - requestRouterModels", () => { glama: mockModels, unbound: {}, litellm: {}, + ollama: {}, + lmstudio: {}, }, }) @@ -222,11 +228,11 @@ describe("webviewMessageHandler - requestRouterModels", () => { it("handles Error objects and string errors correctly", async () => { // Mock providers to fail with different error types mockGetModels - .mockRejectedValueOnce(new Error("Structured error message")) // Error object - .mockRejectedValueOnce("String error message") // String error - .mockRejectedValueOnce({ message: "Object with message" }) // Object error - .mockResolvedValueOnce({}) // Success - .mockResolvedValueOnce({}) // Success + .mockRejectedValueOnce(new Error("Structured error message")) // openrouter + .mockRejectedValueOnce(new Error("Requesty API error")) // requesty + .mockRejectedValueOnce(new Error("Glama API error")) // glama + .mockRejectedValueOnce(new Error("Unbound API error")) // unbound + .mockRejectedValueOnce(new Error("LiteLLM connection failed")) // litellm await webviewMessageHandler(mockClineProvider, { type: "requestRouterModels", @@ -243,16 +249,30 @@ describe("webviewMessageHandler - requestRouterModels", () => { expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({ type: "singleRouterModelFetchResponse", success: false, - error: "String error message", + error: "Requesty API error", values: { provider: "requesty" }, }) expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({ type: "singleRouterModelFetchResponse", success: false, - error: "[object Object]", + error: "Glama API error", values: { provider: "glama" }, }) + + expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "singleRouterModelFetchResponse", + success: false, + error: "Unbound API error", + values: { provider: "unbound" }, + }) + + expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({ + type: "singleRouterModelFetchResponse", + success: false, + error: "LiteLLM connection failed", + values: { provider: "litellm" }, + }) }) it("prefers config values over message values for LiteLLM", async () => { diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 3e988a0c797..ee7796ed24f 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -29,9 +29,7 @@ import { singleCompletionHandler } from "../../utils/single-completion-handler" import { searchCommits } from "../../utils/git" import { exportSettings, importSettings } from "../config/importExport" import { getOpenAiModels } from "../../api/providers/openai" -import { getOllamaModels } from "../../api/providers/ollama" import { getVsCodeLmModels } from "../../api/providers/vscode-lm" -import { getLmStudioModels } from "../../api/providers/lm-studio" import { openMention } from "../mentions" import { TelemetrySetting } from "../../shared/TelemetrySetting" import { getWorkspacePath } from "../../utils/path" @@ -357,6 +355,8 @@ export const webviewMessageHandler = async ( glama: {}, unbound: {}, litellm: {}, + ollama: {}, + lmstudio: {}, } const safeGetModels = async (options: GetModelsOptions): Promise => { @@ -378,6 +378,9 @@ export const webviewMessageHandler = async ( { key: "unbound", options: { provider: "unbound", apiKey: apiConfiguration.unboundApiKey } }, ] + // Don't fetch Ollama and LM Studio models by default anymore + // They have their own specific handlers: requestOllamaModels and requestLmStudioModels + const litellmApiKey = apiConfiguration.litellmApiKey || message?.values?.litellmApiKey const litellmBaseUrl = apiConfiguration.litellmBaseUrl || message?.values?.litellmBaseUrl if (litellmApiKey && litellmBaseUrl) { @@ -394,13 +397,31 @@ export const webviewMessageHandler = async ( }), ) - const fetchedRouterModels: Partial> = { ...routerModels } + const fetchedRouterModels: Partial> = { + ...routerModels, + // Initialize ollama and lmstudio with empty objects since they use separate handlers + ollama: {}, + lmstudio: {}, + } results.forEach((result, index) => { const routerName = modelFetchPromises[index].key // Get RouterName using index if (result.status === "fulfilled") { fetchedRouterModels[routerName] = result.value.models + + // Ollama and LM Studio settings pages still need these events + if (routerName === "ollama" && Object.keys(result.value.models).length > 0) { + provider.postMessageToWebview({ + type: "ollamaModels", + ollamaModels: Object.keys(result.value.models), + }) + } else if (routerName === "lmstudio" && Object.keys(result.value.models).length > 0) { + provider.postMessageToWebview({ + type: "lmStudioModels", + lmStudioModels: Object.keys(result.value.models), + }) + } } else { // Handle rejection: Post a specific error message for this provider const errorMessage = result.reason instanceof Error ? result.reason.message : String(result.reason) @@ -421,7 +442,50 @@ export const webviewMessageHandler = async ( type: "routerModels", routerModels: fetchedRouterModels as Record, }) + break + case "requestOllamaModels": { + // Specific handler for Ollama models only + const { apiConfiguration: ollamaApiConfig } = await provider.getState() + try { + const ollamaModels = await getModels({ + provider: "ollama", + baseUrl: ollamaApiConfig.ollamaBaseUrl, + }) + + if (Object.keys(ollamaModels).length > 0) { + provider.postMessageToWebview({ + type: "ollamaModels", + ollamaModels: Object.keys(ollamaModels), + }) + } + } catch (error) { + // Silently fail - user hasn't configured Ollama yet + console.debug("Ollama models fetch failed:", error) + } + break + } + case "requestLmStudioModels": { + // Specific handler for LM Studio models only + const { apiConfiguration: lmStudioApiConfig } = await provider.getState() + try { + const lmStudioModels = await getModels({ + provider: "lmstudio", + baseUrl: lmStudioApiConfig.lmStudioBaseUrl, + }) + + if (Object.keys(lmStudioModels).length > 0) { + provider.postMessageToWebview({ + type: "lmStudioModels", + lmStudioModels: Object.keys(lmStudioModels), + }) + } + } catch (error) { + // Silently fail - user hasn't configured LM Studio yet + console.debug("LM Studio models fetch failed:", error) + } + break + } case "requestOpenAiModels": if (message?.values?.baseUrl && message?.values?.apiKey) { const openAiModels = await getOpenAiModels( @@ -433,16 +497,6 @@ export const webviewMessageHandler = async ( provider.postMessageToWebview({ type: "openAiModels", openAiModels }) } - break - case "requestOllamaModels": - const ollamaModels = await getOllamaModels(message.text) - // TODO: Cache like we do for OpenRouter, etc? - provider.postMessageToWebview({ type: "ollamaModels", ollamaModels }) - break - case "requestLmStudioModels": - const lmStudioModels = await getLmStudioModels(message.text) - // TODO: Cache like we do for OpenRouter, etc? - provider.postMessageToWebview({ type: "lmStudioModels", lmStudioModels }) break case "requestVsCodeLmModels": const vsCodeLmModels = await getVsCodeLmModels() @@ -1065,6 +1119,10 @@ export const webviewMessageHandler = async ( await updateGlobalState("customCondensingPrompt", message.text) await provider.postStateToWebview() break + case "profileThresholds": + await updateGlobalState("profileThresholds", message.values) + await provider.postStateToWebview() + break case "autoApprovalEnabled": await updateGlobalState("autoApprovalEnabled", message.bool ?? false) await provider.postStateToWebview() @@ -1597,5 +1655,57 @@ export const webviewMessageHandler = async ( } break } + case "extendSubtaskTimeout": + if (message.taskId && typeof message.extensionMs === "number") { + try { + const currentTask = provider.getCurrentCline() + if (currentTask) { + const success = currentTask.extendSubtaskTimeout(message.taskId, message.extensionMs) + if (!success) { + provider.log( + `Failed to extend subtask timeout: task ${message.taskId} not found or inactive`, + ) + vscode.window.showWarningMessage(t("common:errors.subtask_timeout_not_found")) + } + } + } catch (error) { + provider.log( + `Failed to extend subtask timeout: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + vscode.window.showErrorMessage(t("common:errors.extend_subtask_timeout")) + } + } + break + case "clearSubtaskTimeout": + if (message.taskId) { + try { + const currentTask = provider.getCurrentCline() + if (currentTask) { + const success = currentTask.clearSubtaskTimeout(message.taskId) + if (!success) { + provider.log(`Failed to clear subtask timeout: task ${message.taskId} not found`) + vscode.window.showWarningMessage(t("common:errors.subtask_timeout_not_found")) + } + } + } catch (error) { + provider.log( + `Failed to clear subtask timeout: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + vscode.window.showErrorMessage(t("common:errors.clear_subtask_timeout")) + } + } + break + case "defaultSubtaskTimeoutMs": + await updateGlobalState("defaultSubtaskTimeoutMs", message.value) + await provider.postStateToWebview() + break + case "subtaskTimeoutWarningPercent": + await updateGlobalState("subtaskTimeoutWarningPercent", message.value) + await provider.postStateToWebview() + break + case "maxSubtaskTimeoutExtensions": + await updateGlobalState("maxSubtaskTimeoutExtensions", message.value) + await provider.postStateToWebview() + break } } diff --git a/src/extension/api.ts b/src/extension/api.ts index 3bb538dcb30..c9d31c784ed 100644 --- a/src/extension/api.ts +++ b/src/extension/api.ts @@ -132,7 +132,7 @@ export class API extends EventEmitter implements RooCodeAPI { await provider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) await provider.postMessageToWebview({ type: "invoke", invoke: "newChat", text, images }) - const cline = await provider.initClineWithTask(text, images, undefined, { + const cline = await provider.initClineWithTask(text, images, undefined, undefined, { consecutiveMistakeLimit: Number.MAX_SAFE_INTEGER, }) diff --git a/src/package.json b/src/package.json index 4c2df62ddd2..bb4a784173b 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "RooVeterinaryInc", - "version": "3.21.1", + "version": "3.21.3", "icon": "assets/icons/icon.png", "galleryBanner": { "color": "#617A91", @@ -369,6 +369,7 @@ "@aws-sdk/client-bedrock-runtime": "^3.779.0", "@aws-sdk/credential-providers": "^3.806.0", "@google/genai": "^1.0.0", + "@lmstudio/sdk": "^1.1.1", "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.9.0", "@qdrant/js-client-rest": "^1.14.0", @@ -408,14 +409,14 @@ "p-wait-for": "^5.0.2", "pdf-parse": "^1.1.1", "pkce-challenge": "^5.0.0", - "pretty-bytes": "^6.1.1", + "pretty-bytes": "^7.0.0", "ps-tree": "^1.2.0", "puppeteer-chromium-resolver": "^24.0.0", "puppeteer-core": "^23.4.0", "reconnecting-eventsource": "^1.6.4", "sanitize-filename": "^1.6.3", "say": "^0.16.0", - "serialize-error": "^11.0.3", + "serialize-error": "^12.0.0", "simple-git": "^3.27.0", "sound-play": "^1.1.0", "string-similarity": "^4.0.4", diff --git a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts index a403c4e8518..cba8eee8ba4 100644 --- a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts +++ b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts @@ -12,8 +12,6 @@ import * as fileSearch from "../../../services/search/file-search" import { RepoPerTaskCheckpointService } from "../RepoPerTaskCheckpointService" -vitest.setConfig({ testTimeout: 20_000 }) - const tmpDir = path.join(os.tmpdir(), "CheckpointService") const initWorkspaceRepo = async ({ diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index a515a2d0040..9a2c9230bd7 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -213,6 +213,7 @@ export type ExtensionState = Pick< | "customCondensingPrompt" | "codebaseIndexConfig" | "codebaseIndexModels" + | "profileThresholds" > & { version: string clineMessages: ClineMessage[] @@ -259,6 +260,7 @@ export type ExtensionState = Pick< autoCondenseContextPercent: number marketplaceItems?: MarketplaceItem[] marketplaceInstalledMetadata?: { project: Record; global: Record } + profileThresholds: Record } export interface ClineSayTool { diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 0f2342cbd08..cd2775e4012 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -72,6 +72,11 @@ export interface WebviewMessage { | "alwaysAllowSubtasks" | "autoCondenseContext" | "autoCondenseContextPercent" + | "extendSubtaskTimeout" + | "clearSubtaskTimeout" + | "defaultSubtaskTimeoutMs" + | "subtaskTimeoutWarningPercent" + | "maxSubtaskTimeoutExtensions" | "condensingApiConfigId" | "updateCondensingPrompt" | "playSound" @@ -159,6 +164,7 @@ export interface WebviewMessage { | "indexCleared" | "focusPanelRequest" | "codebaseIndexConfig" + | "profileThresholds" | "setHistoryPreviewCollapsed" | "openExternal" | "filterMarketplaceItems" @@ -170,6 +176,7 @@ export interface WebviewMessage { | "marketplaceInstallResult" | "fetchMarketplaceData" | "switchTab" + | "profileThresholds" text?: string tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account" disabled?: boolean @@ -199,6 +206,8 @@ export interface WebviewMessage { source?: "global" | "project" requestId?: string ids?: string[] + taskId?: string + extensionMs?: number hasSystemPromptOverride?: boolean terminalOperation?: "continue" | "abort" historyPreviewCollapsed?: boolean diff --git a/src/shared/api.ts b/src/shared/api.ts index 8ad88286589..d1bfa2794b1 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -6,7 +6,7 @@ export type ApiHandlerOptions = Omit // RouterName -const routerNames = ["openrouter", "requesty", "glama", "unbound", "litellm"] as const +const routerNames = ["openrouter", "requesty", "glama", "unbound", "litellm", "ollama", "lmstudio"] as const export type RouterName = (typeof routerNames)[number] @@ -82,3 +82,5 @@ export type GetModelsOptions = | { provider: "requesty"; apiKey?: string } | { provider: "unbound"; apiKey?: string } | { provider: "litellm"; apiKey: string; baseUrl: string } + | { provider: "ollama"; baseUrl?: string } + | { provider: "lmstudio"; baseUrl?: string } diff --git a/src/shared/tools.ts b/src/shared/tools.ts index 0725e2e4d64..59f07ce76fa 100644 --- a/src/shared/tools.ts +++ b/src/shared/tools.ts @@ -64,6 +64,7 @@ export const toolParamNames = [ "end_line", "query", "args", + "timeout_seconds", ] as const export type ToolParamName = (typeof toolParamNames)[number] diff --git a/src/vitest.config.ts b/src/vitest.config.ts index e20e40c655c..4e576f3c96c 100644 --- a/src/vitest.config.ts +++ b/src/vitest.config.ts @@ -8,6 +8,8 @@ export default defineConfig({ watch: false, reporters: ["dot"], silent: true, + testTimeout: 20_000, + hookTimeout: 20_000, }, resolve: { alias: { diff --git a/webview-ui/package.json b/webview-ui/package.json index 859c7315515..4d5e5cc821c 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -50,7 +50,7 @@ "lucide-react": "^0.518.0", "mermaid": "^11.4.1", "posthog-js": "^1.227.2", - "pretty-bytes": "^6.1.1", + "pretty-bytes": "^7.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^15.4.1", @@ -68,7 +68,7 @@ "shiki": "^3.2.1", "source-map": "^0.7.4", "styled-components": "^6.1.13", - "tailwind-merge": "^2.6.0", + "tailwind-merge": "^3.0.0", "tailwindcss": "^4.0.0", "tailwindcss-animate": "^1.0.7", "unist-util-visit": "^5.0.0", diff --git a/webview-ui/src/components/chat/McpExecution.tsx b/webview-ui/src/components/chat/McpExecution.tsx index 8e0882340b9..a96f368a17e 100644 --- a/webview-ui/src/components/chat/McpExecution.tsx +++ b/webview-ui/src/components/chat/McpExecution.tsx @@ -242,6 +242,7 @@ export const McpExecution = ({ serverName={useMcpServer.serverName} serverSource={server?.source} alwaysAllowMcp={alwaysAllowMcp} + isInChatContext={true} />
)} @@ -256,6 +257,7 @@ export const McpExecution = ({ serverName={serverName} serverSource={undefined} alwaysAllowMcp={alwaysAllowMcp} + isInChatContext={true} /> )} diff --git a/webview-ui/src/components/chat/SubtaskTimeoutProgress.tsx b/webview-ui/src/components/chat/SubtaskTimeoutProgress.tsx new file mode 100644 index 00000000000..cd03273e9f3 --- /dev/null +++ b/webview-ui/src/components/chat/SubtaskTimeoutProgress.tsx @@ -0,0 +1,155 @@ +import { memo, useState, useEffect } from "react" +import { useTranslation } from "react-i18next" +import { Clock, Plus, X } from "lucide-react" + +import { Button } from "@src/components/ui" +import { cn } from "@src/lib/utils" +import { vscode } from "@src/utils/vscode" + +export interface SubtaskTimeoutProgressProps { + taskId: string + timeoutMs: number + startTime: number + warningPercent?: number + onExtend?: (taskId: string, extensionMs: number) => void + onClear?: (taskId: string) => void + className?: string +} + +const SubtaskTimeoutProgress = ({ + taskId, + timeoutMs, + startTime, + warningPercent = 80, + onExtend, + onClear, + className, +}: SubtaskTimeoutProgressProps) => { + const { t } = useTranslation() + const [currentTime, setCurrentTime] = useState(Date.now()) + const [isExpired, setIsExpired] = useState(false) + + useEffect(() => { + const interval = setInterval(() => { + setCurrentTime(Date.now()) + }, 1000) + + return () => clearInterval(interval) + }, []) + + const elapsed = currentTime - startTime + const remaining = Math.max(0, timeoutMs - elapsed) + const progress = Math.min(100, (elapsed / timeoutMs) * 100) + const isWarning = progress >= warningPercent + const isUrgent = progress >= 95 + + useEffect(() => { + if (remaining <= 0 && !isExpired) { + setIsExpired(true) + } + }, [remaining, isExpired]) + + const formatTime = (ms: number): string => { + const seconds = Math.ceil(ms / 1000) + const minutes = Math.floor(seconds / 60) + const remainingSeconds = seconds % 60 + + if (minutes > 0) { + return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}` + } + return `${seconds}s` + } + + const handleExtend = () => { + const extensionMs = Math.max(60000, Math.floor(timeoutMs * 0.5)) // Extend by 50% or 1 minute, whichever is larger + onExtend?.(taskId, extensionMs) + vscode.postMessage({ + type: "extendSubtaskTimeout", + taskId, + extensionMs, + }) + } + + const handleClear = () => { + onClear?.(taskId) + vscode.postMessage({ + type: "clearSubtaskTimeout", + taskId, + }) + } + + if (remaining <= 0 && isExpired) { + return ( +
+ + {t("chat:timeout.expired")} +
+ ) + } + + return ( +
+
+ +
+
+ + {t("chat:timeout.remaining")}: {formatTime(remaining)} + + {progress.toFixed(0)}% +
+
+
+
+
+
+ + {isWarning && ( +
+ + +
+ )} +
+ ) +} + +export default memo(SubtaskTimeoutProgress) diff --git a/webview-ui/src/components/mcp/McpToolRow.tsx b/webview-ui/src/components/mcp/McpToolRow.tsx index 76664fea464..892304d1c64 100644 --- a/webview-ui/src/components/mcp/McpToolRow.tsx +++ b/webview-ui/src/components/mcp/McpToolRow.tsx @@ -10,9 +10,10 @@ type McpToolRowProps = { serverName?: string serverSource?: "global" | "project" alwaysAllowMcp?: boolean + isInChatContext?: boolean } -const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp }: McpToolRowProps) => { +const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp, isInChatContext = false }: McpToolRowProps) => { const { t } = useAppTranslation() const handleAlwaysAllowChange = () => { if (!serverName) return @@ -66,25 +67,27 @@ const McpToolRow = ({ tool, serverName, serverSource, alwaysAllowMcp }: McpToolR )} - {/* Enabled eye button */} - + {/* Enabled eye button - only show in settings context */} + {!isInChatContext && ( + + )}
)} diff --git a/webview-ui/src/components/mcp/__tests__/McpToolRow.spec.tsx b/webview-ui/src/components/mcp/__tests__/McpToolRow.spec.tsx index 43889c3cc5b..a3ccd6a9905 100644 --- a/webview-ui/src/components/mcp/__tests__/McpToolRow.spec.tsx +++ b/webview-ui/src/components/mcp/__tests__/McpToolRow.spec.tsx @@ -12,6 +12,7 @@ vi.mock("@src/i18n/TranslationContext", () => ({ "mcp:tool.alwaysAllow": "Always allow", "mcp:tool.parameters": "Parameters", "mcp:tool.noDescription": "No description", + "mcp:tool.togglePromptInclusion": "Toggle prompt inclusion", } return translations[key] || key }, @@ -48,6 +49,7 @@ describe("McpToolRow", () => { name: "test-tool", description: "A test tool", alwaysAllow: false, + enabledForPrompt: true, } beforeEach(() => { @@ -141,4 +143,48 @@ describe("McpToolRow", () => { expect(screen.getByText("First parameter")).toBeInTheDocument() expect(screen.getByText("Second parameter")).toBeInTheDocument() }) + + it("shows eye button when serverName is provided and not in chat context", () => { + render() + + const eyeButton = screen.getByRole("button", { name: "Toggle prompt inclusion" }) + expect(eyeButton).toBeInTheDocument() + }) + + it("hides eye button when isInChatContext is true", () => { + render() + + const eyeButton = screen.queryByRole("button", { name: "Toggle prompt inclusion" }) + expect(eyeButton).not.toBeInTheDocument() + }) + + it("shows correct eye icon based on enabledForPrompt state", () => { + // Test when enabled (should show eye-closed icon) + const { rerender } = render() + + let eyeIcon = screen.getByRole("button", { name: "Toggle prompt inclusion" }).querySelector("span") + expect(eyeIcon).toHaveClass("codicon-eye-closed") + + // Test when disabled (should show eye icon) + const disabledTool = { ...mockTool, enabledForPrompt: false } + rerender() + + eyeIcon = screen.getByRole("button", { name: "Toggle prompt inclusion" }).querySelector("span") + expect(eyeIcon).toHaveClass("codicon-eye") + }) + + it("sends message to toggle enabledForPrompt when eye button is clicked", () => { + render() + + const eyeButton = screen.getByRole("button", { name: "Toggle prompt inclusion" }) + fireEvent.click(eyeButton) + + expect(vscode.postMessage).toHaveBeenCalledWith({ + type: "toggleToolEnabledForPrompt", + serverName: "test-server", + source: "global", + toolName: "test-tool", + isEnabled: false, + }) + }) }) diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index c55999efbda..c5cd3f1e42f 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -162,9 +162,9 @@ const ApiOptions = ({ }, }) } else if (selectedProvider === "ollama") { - vscode.postMessage({ type: "requestOllamaModels", text: apiConfiguration?.ollamaBaseUrl }) + vscode.postMessage({ type: "requestOllamaModels" }) } else if (selectedProvider === "lmstudio") { - vscode.postMessage({ type: "requestLmStudioModels", text: apiConfiguration?.lmStudioBaseUrl }) + vscode.postMessage({ type: "requestLmStudioModels" }) } else if (selectedProvider === "vscode-lm") { vscode.postMessage({ type: "requestVsCodeLmModels" }) } else if (selectedProvider === "litellm") { diff --git a/webview-ui/src/components/settings/ContextManagementSettings.tsx b/webview-ui/src/components/settings/ContextManagementSettings.tsx index 548020159e7..6fbd2f1dab7 100644 --- a/webview-ui/src/components/settings/ContextManagementSettings.tsx +++ b/webview-ui/src/components/settings/ContextManagementSettings.tsx @@ -1,4 +1,5 @@ import { HTMLAttributes } from "react" +import React from "react" import { useAppTranslation } from "@/i18n/TranslationContext" import { VSCodeCheckbox, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react" import { Database, FoldVertical } from "lucide-react" @@ -62,6 +63,7 @@ type ContextManagementSettingsProps = HTMLAttributes & { showRooIgnoredFiles?: boolean maxReadFileLine?: number maxConcurrentFileReads?: number + profileThresholds?: Record setCachedStateField: SetCachedStateField< | "autoCondenseContext" | "autoCondenseContextPercent" @@ -72,6 +74,7 @@ type ContextManagementSettingsProps = HTMLAttributes & { | "showRooIgnoredFiles" | "maxReadFileLine" | "maxConcurrentFileReads" + | "profileThresholds" > } @@ -87,10 +90,41 @@ export const ContextManagementSettings = ({ setCachedStateField, maxReadFileLine, maxConcurrentFileReads, + profileThresholds = {}, className, ...props }: ContextManagementSettingsProps) => { const { t } = useAppTranslation() + const [selectedThresholdProfile, setSelectedThresholdProfile] = React.useState("default") + + // Helper function to get the current threshold value based on selected profile + const getCurrentThresholdValue = () => { + if (selectedThresholdProfile === "default") { + return autoCondenseContextPercent + } + const profileThreshold = profileThresholds[selectedThresholdProfile] + if (profileThreshold === undefined || profileThreshold === -1) { + return autoCondenseContextPercent // Use default if profile not configured or set to -1 + } + return profileThreshold + } + + // Helper function to handle threshold changes + const handleThresholdChange = (value: number) => { + if (selectedThresholdProfile === "default") { + setCachedStateField("autoCondenseContextPercent", value) + } else { + const newThresholds = { + ...profileThresholds, + [selectedThresholdProfile]: value, + } + setCachedStateField("profileThresholds", newThresholds) + vscode.postMessage({ + type: "profileThresholds", + values: newThresholds, + }) + } + } return (
@@ -220,29 +254,76 @@ export const ContextManagementSettings = ({
-
{t("settings:contextManagement.autoCondenseContextPercent.label")}
+
{t("settings:contextManagement.condensingThreshold.label")}
+
+ +
+ + {/* Threshold Slider */}
- setCachedStateField("autoCondenseContextPercent", value) - } - data-testid="auto-condense-percent-slider" + value={[getCurrentThresholdValue()]} + onValueChange={([value]) => handleThresholdChange(value)} + data-testid="condense-threshold-slider" /> - {autoCondenseContextPercent}% + {getCurrentThresholdValue()}%
- {t("settings:contextManagement.autoCondenseContextPercent.description")} + {selectedThresholdProfile === "default" + ? t("settings:contextManagement.condensingThreshold.defaultDescription", { + threshold: autoCondenseContextPercent, + }) + : t("settings:contextManagement.condensingThreshold.profileDescription")}
{/* API Configuration Selection */} -
+
{t("settings:contextManagement.condensingApiConfiguration.label")}
@@ -286,7 +367,7 @@ export const ContextManagementSettings = ({
{/* Custom Prompt Section */} -
+
{t("settings:contextManagement.customCondensingPrompt.label")}
diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index bc962b921d5..13dbba8a63f 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -59,6 +59,8 @@ export const ModelPicker = ({ const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false) const isInitialized = useRef(false) const searchInputRef = useRef(null) + const selectTimeoutRef = useRef(null) + const closeTimeoutRef = useRef(null) const modelIds = useMemo(() => { const filteredModels = filterModels(models, apiConfiguration.apiProvider, organizationAllowList) @@ -79,8 +81,13 @@ export const ModelPicker = ({ setOpen(false) setApiConfigurationField(modelIdKey, modelId) + // Clear any existing timeout + if (selectTimeoutRef.current) { + clearTimeout(selectTimeoutRef.current) + } + // Delay to ensure the popover is closed before setting the search value. - setTimeout(() => setSearchValue(modelId), 100) + selectTimeoutRef.current = setTimeout(() => setSearchValue(modelId), 100) }, [modelIdKey, setApiConfigurationField], ) @@ -91,8 +98,13 @@ export const ModelPicker = ({ // Abandon the current search if the popover is closed. if (!open) { + // Clear any existing timeout + if (closeTimeoutRef.current) { + clearTimeout(closeTimeoutRef.current) + } + // Delay to ensure the popover is closed before setting the search value. - setTimeout(() => setSearchValue(selectedModelId), 100) + closeTimeoutRef.current = setTimeout(() => setSearchValue(selectedModelId), 100) } }, [selectedModelId], @@ -112,6 +124,18 @@ export const ModelPicker = ({ isInitialized.current = true }, [modelIds, setApiConfigurationField, modelIdKey, selectedModelId, defaultModelId]) + // Cleanup timeouts on unmount to prevent test flakiness + useEffect(() => { + return () => { + if (selectTimeoutRef.current) { + clearTimeout(selectTimeoutRef.current) + } + if (closeTimeoutRef.current) { + clearTimeout(closeTimeoutRef.current) + } + } + }, []) + return ( <>
diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 5a330c89966..839ce25b698 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -172,6 +172,7 @@ const SettingsView = forwardRef(({ onDone, t codebaseIndexConfig, codebaseIndexModels, customSupportPrompts, + profileThresholds, } = cachedState const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration]) @@ -315,6 +316,7 @@ const SettingsView = forwardRef(({ onDone, t vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration }) vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting }) vscode.postMessage({ type: "codebaseIndexConfig", values: codebaseIndexConfig }) + vscode.postMessage({ type: "profileThresholds", values: profileThresholds }) setChangeDetected(false) } } @@ -644,6 +646,7 @@ const SettingsView = forwardRef(({ onDone, t showRooIgnoredFiles={showRooIgnoredFiles} maxReadFileLine={maxReadFileLine} maxConcurrentFileReads={maxConcurrentFileReads} + profileThresholds={profileThresholds} setCachedStateField={setCachedStateField} /> )} diff --git a/webview-ui/src/components/settings/__tests__/ContextManagementSettings.spec.tsx b/webview-ui/src/components/settings/__tests__/ContextManagementSettings.spec.tsx index d1c8f64f57c..9a7d451d1d9 100644 --- a/webview-ui/src/components/settings/__tests__/ContextManagementSettings.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/ContextManagementSettings.spec.tsx @@ -49,6 +49,7 @@ describe("ContextManagementSettings", () => { maxWorkspaceFiles: 200, showRooIgnoredFiles: false, setCachedStateField: vitest.fn(), + profileThresholds: {}, } beforeEach(() => { @@ -173,18 +174,17 @@ describe("ContextManagementSettings", () => { } render() - // Should render the auto condense section // Should render the auto condense section const autoCondenseCheckbox = screen.getByTestId("auto-condense-context-checkbox") expect(autoCondenseCheckbox).toBeInTheDocument() - // Should render the slider with correct value - const slider = screen.getByTestId("auto-condense-percent-slider") + // Should render the threshold slider with correct value + const slider = screen.getByTestId("condense-threshold-slider") expect(slider).toBeInTheDocument() - // Should render the API config select - const apiSelect = screen.getByRole("combobox") - expect(apiSelect).toBeInTheDocument() + // Should render both select dropdowns (profile and API config) + const selects = screen.getAllByRole("combobox") + expect(selects).toHaveLength(2) // Should render the custom prompt textarea const textarea = screen.getByRole("textbox") @@ -207,7 +207,7 @@ describe("ContextManagementSettings", () => { it("toggles auto condense context setting", () => { const mockSetCachedStateField = vitest.fn() const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField } - const { rerender } = render() + render() const checkbox = screen.getByTestId("auto-condense-context-checkbox") expect(checkbox).toBeChecked() @@ -215,42 +215,25 @@ describe("ContextManagementSettings", () => { // Toggle off fireEvent.click(checkbox) expect(mockSetCachedStateField).toHaveBeenCalledWith("autoCondenseContext", false) - - // Re-render with updated props to simulate the state change - rerender() - - // Additional settings should not be visible when disabled - expect(screen.queryByTestId("auto-condense-percent-slider")).not.toBeInTheDocument() - expect(screen.queryByRole("combobox")).not.toBeInTheDocument() - expect(screen.queryByRole("textbox")).not.toBeInTheDocument() }) it("shows additional settings when auto condense is enabled", () => { render() // Additional settings should be visible - expect(screen.getByTestId("auto-condense-percent-slider")).toBeInTheDocument() - expect(screen.getByRole("combobox")).toBeInTheDocument() + expect(screen.getByTestId("condense-threshold-slider")).toBeInTheDocument() + // Two comboboxes: one for profile selection, one for API config + expect(screen.getAllByRole("combobox")).toHaveLength(2) expect(screen.getByRole("textbox")).toBeInTheDocument() }) - it("hides additional settings when auto condense is disabled", () => { - const props = { ...autoCondenseProps, autoCondenseContext: false } - render() - - // Additional settings should not be visible - expect(screen.queryByTestId("auto-condense-percent-slider")).not.toBeInTheDocument() - expect(screen.queryByRole("combobox")).not.toBeInTheDocument() - expect(screen.queryByRole("textbox")).not.toBeInTheDocument() - }) - it("updates auto condense context percent", () => { const mockSetCachedStateField = vitest.fn() const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField } render() - // Find the auto condense percent slider - const slider = screen.getByTestId("auto-condense-percent-slider") + // Find the condense threshold slider + const slider = screen.getByTestId("condense-threshold-slider") // Test slider interaction slider.focus() @@ -273,7 +256,9 @@ describe("ContextManagementSettings", () => { const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField } render() - const apiSelect = screen.getByRole("combobox") + // Get the second combobox (API config select) + const selects = screen.getAllByRole("combobox") + const apiSelect = selects[1] fireEvent.click(apiSelect) const configOption = screen.getByText("Config 1") @@ -295,8 +280,9 @@ describe("ContextManagementSettings", () => { const props = { ...autoCondenseProps, setCachedStateField: mockSetCachedStateField } render() - // Test selecting default config - const apiSelect = screen.getByRole("combobox") + // Test selecting default config - get the second combobox (API config) + const selects = screen.getAllByRole("combobox") + const apiSelect = selects[1] fireEvent.click(apiSelect) const defaultOption = screen.getByText( "settings:contextManagement.condensingApiConfiguration.useCurrentConfig", @@ -463,9 +449,14 @@ describe("ContextManagementSettings", () => { } render() - expect(screen.queryByText("settings:experimental.autoCondenseContextPercent.label")).not.toBeInTheDocument() - expect(screen.queryByText("settings:experimental.condensingApiConfiguration.label")).not.toBeInTheDocument() - expect(screen.queryByText("settings:experimental.customCondensingPrompt.label")).not.toBeInTheDocument() + // When auto condense is false, all condensing-related UI should not be visible + expect(screen.queryByTestId("condense-threshold-slider")).not.toBeInTheDocument() + expect( + screen.queryByText("settings:contextManagement.condensingApiConfiguration.label"), + ).not.toBeInTheDocument() + expect( + screen.queryByText("settings:contextManagement.customCondensingPrompt.label"), + ).not.toBeInTheDocument() }) it("renders max read file controls with default value when maxReadFileLine is undefined", () => { diff --git a/webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx b/webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx index 720216075f6..38237dc0e3c 100644 --- a/webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/ModelPicker.spec.tsx @@ -3,6 +3,7 @@ import { screen, fireEvent, render } from "@testing-library/react" import { act } from "react" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { vi } from "vitest" import { ModelInfo } from "@roo-code/types" @@ -58,6 +59,13 @@ describe("ModelPicker", () => { beforeEach(() => { vi.clearAllMocks() + vi.useFakeTimers() + }) + + afterEach(() => { + // Clear any pending timers to prevent test flakiness + vi.clearAllTimers() + vi.useRealTimers() }) it("calls setApiConfigurationField when a model is selected", async () => { @@ -71,7 +79,7 @@ describe("ModelPicker", () => { // Wait for popover to open and animations to complete. await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 100)) + vi.advanceTimersByTime(100) }) await act(async () => { @@ -87,6 +95,11 @@ describe("ModelPicker", () => { fireEvent.click(modelItem) }) + // Advance timers to trigger the setTimeout in onSelect + await act(async () => { + vi.advanceTimersByTime(100) + }) + // Verify the API config was updated. expect(mockSetApiConfigurationField).toHaveBeenCalledWith(defaultProps.modelIdKey, "model2") }) @@ -102,7 +115,7 @@ describe("ModelPicker", () => { // Wait for popover to open and animations to complete. await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 100)) + vi.advanceTimersByTime(100) }) const customModelId = "custom-model-id" @@ -115,7 +128,7 @@ describe("ModelPicker", () => { // Wait for the UI to update await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 100)) + vi.advanceTimersByTime(100) }) // Find and click the "Use custom" option @@ -125,6 +138,11 @@ describe("ModelPicker", () => { fireEvent.click(customOption) }) + // Advance timers to trigger the setTimeout in onSelect + await act(async () => { + vi.advanceTimersByTime(100) + }) + // Verify the API config was updated with the custom model ID expect(mockSetApiConfigurationField).toHaveBeenCalledWith(defaultProps.modelIdKey, customModelId) }) diff --git a/webview-ui/src/components/settings/providers/LMStudio.tsx b/webview-ui/src/components/settings/providers/LMStudio.tsx index 9177457039f..17af44871b9 100644 --- a/webview-ui/src/components/settings/providers/LMStudio.tsx +++ b/webview-ui/src/components/settings/providers/LMStudio.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react" +import { useCallback, useState, useMemo } from "react" import { useEvent } from "react-use" import { Trans } from "react-i18next" import { Checkbox } from "vscrui" @@ -8,6 +8,7 @@ import type { ProviderSettings } from "@roo-code/types" import { useAppTranslation } from "@src/i18n/TranslationContext" import { ExtensionMessage } from "@roo/ExtensionMessage" +import { useRouterModels } from "@src/components/ui/hooks/useRouterModels" import { inputEventTransform } from "../transforms" @@ -20,6 +21,7 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi const { t } = useAppTranslation() const [lmStudioModels, setLmStudioModels] = useState([]) + const routerModels = useRouterModels() const handleInputChange = useCallback( ( @@ -47,6 +49,48 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi useEvent("message", onMessage) + // Check if the selected model exists in the fetched models + const modelNotAvailable = useMemo(() => { + const selectedModel = apiConfiguration?.lmStudioModelId + if (!selectedModel) return false + + // Check if model exists in local LM Studio models + if (lmStudioModels.length > 0 && lmStudioModels.includes(selectedModel)) { + return false // Model is available locally + } + + // If we have router models data for LM Studio + if (routerModels.data?.lmstudio) { + const availableModels = Object.keys(routerModels.data.lmstudio) + // Show warning if model is not in the list (regardless of how many models there are) + return !availableModels.includes(selectedModel) + } + + // If neither source has loaded yet, don't show warning + return false + }, [apiConfiguration?.lmStudioModelId, routerModels.data, lmStudioModels]) + + // Check if the draft model exists + const draftModelNotAvailable = useMemo(() => { + const draftModel = apiConfiguration?.lmStudioDraftModelId + if (!draftModel) return false + + // Check if model exists in local LM Studio models + if (lmStudioModels.length > 0 && lmStudioModels.includes(draftModel)) { + return false // Model is available locally + } + + // If we have router models data for LM Studio + if (routerModels.data?.lmstudio) { + const availableModels = Object.keys(routerModels.data.lmstudio) + // Show warning if model is not in the list (regardless of how many models there are) + return !availableModels.includes(draftModel) + } + + // If neither source has loaded yet, don't show warning + return false + }, [apiConfiguration?.lmStudioDraftModelId, routerModels.data, lmStudioModels]) + return ( <> + {modelNotAvailable && ( +
+
+
+
+ {t("settings:validation.modelAvailability", { modelId: apiConfiguration?.lmStudioModelId })} +
+
+
+ )} {lmStudioModels.length > 0 && ( {t("settings:providers.lmStudio.draftModelDesc")}
+ {draftModelNotAvailable && ( +
+
+
+
+ {t("settings:validation.modelAvailability", { + modelId: apiConfiguration?.lmStudioDraftModelId, + })} +
+
+
+ )}
{lmStudioModels.length > 0 && ( <> diff --git a/webview-ui/src/components/settings/providers/Ollama.tsx b/webview-ui/src/components/settings/providers/Ollama.tsx index 27fd2a51892..e118f68b460 100644 --- a/webview-ui/src/components/settings/providers/Ollama.tsx +++ b/webview-ui/src/components/settings/providers/Ollama.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback } from "react" +import { useState, useCallback, useMemo } from "react" import { useEvent } from "react-use" import { VSCodeTextField, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react" @@ -7,6 +7,7 @@ import type { ProviderSettings } from "@roo-code/types" import { ExtensionMessage } from "@roo/ExtensionMessage" import { useAppTranslation } from "@src/i18n/TranslationContext" +import { useRouterModels } from "@src/components/ui/hooks/useRouterModels" import { inputEventTransform } from "../transforms" @@ -19,6 +20,7 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro const { t } = useAppTranslation() const [ollamaModels, setOllamaModels] = useState([]) + const routerModels = useRouterModels() const handleInputChange = useCallback( ( @@ -46,6 +48,27 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro useEvent("message", onMessage) + // Check if the selected model exists in the fetched models + const modelNotAvailable = useMemo(() => { + const selectedModel = apiConfiguration?.ollamaModelId + if (!selectedModel) return false + + // Check if model exists in local ollama models + if (ollamaModels.length > 0 && ollamaModels.includes(selectedModel)) { + return false // Model is available locally + } + + // If we have router models data for Ollama + if (routerModels.data?.ollama) { + const availableModels = Object.keys(routerModels.data.ollama) + // Show warning if model is not in the list (regardless of how many models there are) + return !availableModels.includes(selectedModel) + } + + // If neither source has loaded yet, don't show warning + return false + }, [apiConfiguration?.ollamaModelId, routerModels.data, ollamaModels]) + return ( <> + {modelNotAvailable && ( +
+
+
+
+ {t("settings:validation.modelAvailability", { modelId: apiConfiguration?.ollamaModelId })} +
+
+
+ )} {ollamaModels.length > 0 && ( void marketplaceItems?: any[] marketplaceInstalledMetadata?: MarketplaceInstalledMetadata + profileThresholds: Record + setProfileThresholds: (value: Record) => void setApiConfiguration: (config: ProviderSettings) => void setCustomInstructions: (value?: string) => void setAlwaysAllowReadOnly: (value: boolean) => void @@ -201,6 +203,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode organizationAllowList: ORGANIZATION_ALLOW_ALL, autoCondenseContext: true, autoCondenseContextPercent: 100, + profileThresholds: {}, codebaseIndexConfig: { codebaseIndexEnabled: false, codebaseIndexQdrantUrl: "http://localhost:6333", @@ -345,6 +348,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode cloudIsAuthenticated: state.cloudIsAuthenticated ?? false, marketplaceItems, marketplaceInstalledMetadata, + profileThresholds: state.profileThresholds ?? {}, setExperimentEnabled: (id, enabled) => setState((prevState) => ({ ...prevState, experiments: { ...prevState.experiments, [id]: enabled } })), setApiConfiguration, @@ -429,6 +433,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setCondensingApiConfigId: (value) => setState((prevState) => ({ ...prevState, condensingApiConfigId: value })), setCustomCondensingPrompt: (value) => setState((prevState) => ({ ...prevState, customCondensingPrompt: value })), + setProfileThresholds: (value) => setState((prevState) => ({ ...prevState, profileThresholds: value })), } return {children} diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx index d426e59252f..56dd2ef426b 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx @@ -207,6 +207,7 @@ describe("mergeExtensionState", () => { autoCondenseContextPercent: 100, cloudIsAuthenticated: false, sharingEnabled: false, + profileThresholds: {}, } const prevState: ExtensionState = { diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index d72c7455fe4..e25b16fd490 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -370,7 +370,8 @@ "hint": "Buit = utilitzar indicació per defecte" }, "autoCondenseContext": { - "name": "Activar automàticament la condensació intel·ligent de context" + "name": "Activar automàticament la condensació intel·ligent de context", + "description": "Quan està activat, Roo condensarà automàticament el context quan s'assoleixi el llindar. Quan està desactivat, encara pots activar manualment la condensació de context." }, "openTabs": { "label": "Límit de context de pestanyes obertes", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Límit de lectures simultànies", "description": "Nombre màxim de fitxers que l'eina 'read_file' pot processar simultàniament. Els valors més alts poden accelerar la lectura de múltiples fitxers petits però augmenten l'ús de memòria." + }, + "condensingThreshold": { + "label": "Llindar d'activació de condensació", + "selectProfile": "Configura el llindar per al perfil", + "defaultProfile": "Per defecte global (tots els perfils)", + "defaultDescription": "Quan el context arribi a aquest percentatge, es condensarà automàticament per a tots els perfils tret que tinguin configuracions personalitzades", + "profileDescription": "Llindar personalitzat només per a aquest perfil (substitueix el per defecte global)", + "inheritDescription": "Aquest perfil hereta el llindar per defecte global ({{threshold}}%)", + "usesGlobal": "(utilitza global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 7aacb054e2a..3626e86cad8 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -370,7 +370,8 @@ "hint": "Leer = Standard-Prompt verwenden" }, "autoCondenseContext": { - "name": "Intelligente Kontextkomprimierung automatisch auslösen" + "name": "Intelligente Kontextkomprimierung automatisch auslösen", + "description": "Wenn aktiviert, wird Roo automatisch den Kontext komprimieren, wenn der Schwellenwert erreicht wird. Wenn deaktiviert, können Sie die Kontextkomprimierung weiterhin manuell auslösen." }, "openTabs": { "label": "Geöffnete Tabs Kontextlimit", @@ -393,6 +394,15 @@ "description": "Roo liest diese Anzahl von Zeilen, wenn das Modell keine Start-/Endwerte angibt. Wenn diese Zahl kleiner als die Gesamtzahl der Zeilen ist, erstellt Roo einen Zeilennummernindex der Codedefinitionen. Spezialfälle: -1 weist Roo an, die gesamte Datei zu lesen (ohne Indexierung), und 0 weist an, keine Zeilen zu lesen und nur Zeilenindizes für minimalen Kontext bereitzustellen. Niedrigere Werte minimieren die anfängliche Kontextnutzung und ermöglichen präzise nachfolgende Zeilenbereich-Lesungen. Explizite Start-/End-Anfragen sind von dieser Einstellung nicht begrenzt.", "lines": "Zeilen", "always_full_read": "Immer die gesamte Datei lesen" + }, + "condensingThreshold": { + "label": "Schwellenwert für Kontextkomprimierung", + "selectProfile": "Profil für Schwellenwert konfigurieren", + "defaultProfile": "Globaler Standard (alle Profile)", + "defaultDescription": "Wenn der Kontext diesen Prozentsatz erreicht, wird er automatisch für alle Profile komprimiert, es sei denn, sie haben benutzerdefinierte Einstellungen", + "profileDescription": "Benutzerdefinierter Schwellenwert nur für dieses Profil (überschreibt globalen Standard)", + "inheritDescription": "Dieses Profil erbt den globalen Standard-Schwellenwert ({{threshold}}%)", + "usesGlobal": "(verwendet global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 690fea5026a..011c8df2ef6 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -370,7 +370,8 @@ "hint": "Empty = use default prompt" }, "autoCondenseContext": { - "name": "Automatically trigger intelligent context condensing" + "name": "Automatically trigger intelligent context condensing", + "description": "When enabled, Roo will automatically condense the context when the threshold is reached. When disabled, you can still manually trigger context condensing." }, "openTabs": { "label": "Open tabs context limit", @@ -393,6 +394,15 @@ "description": "Roo reads this number of lines when the model omits start/end values. If this number is less than the file's total, Roo generates a line number index of code definitions. Special cases: -1 instructs Roo to read the entire file (without indexing), and 0 instructs it to read no lines and provides line indexes only for minimal context. Lower values minimize initial context usage, enabling precise subsequent line-range reads. Explicit start/end requests are not limited by this setting.", "lines": "lines", "always_full_read": "Always read entire file" + }, + "condensingThreshold": { + "label": "Condensing Trigger Threshold", + "selectProfile": "Configure threshold for profile", + "defaultProfile": "Global Default (all profiles)", + "defaultDescription": "When context reaches this percentage, it will be automatically condensed for all profiles unless they have custom settings", + "profileDescription": "Custom threshold for this profile only (overrides global default)", + "inheritDescription": "This profile inherits the global default threshold ({{threshold}}%)", + "usesGlobal": "(uses global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 9b2e239cf36..2664e948cb0 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -370,7 +370,8 @@ "hint": "Vacío = usar prompt predeterminado" }, "autoCondenseContext": { - "name": "Activar automáticamente la condensación inteligente de contexto" + "name": "Activar automáticamente la condensación inteligente de contexto", + "description": "Cuando está habilitado, Roo condensará automáticamente el contexto cuando se alcance el umbral. Cuando está deshabilitado, aún puedes activar manualmente la condensación de contexto." }, "openTabs": { "label": "Límite de contexto de pestañas abiertas", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Límite de lecturas simultáneas", "description": "Número máximo de archivos que la herramienta 'read_file' puede procesar simultáneamente. Valores más altos pueden acelerar la lectura de múltiples archivos pequeños pero aumentan el uso de memoria." + }, + "condensingThreshold": { + "label": "Umbral de condensación de contexto", + "selectProfile": "Configurar umbral para perfil", + "defaultProfile": "Predeterminado global (todos los perfiles)", + "defaultDescription": "Cuando el contexto alcance este porcentaje, se condensará automáticamente para todos los perfiles a menos que tengan configuraciones personalizadas", + "profileDescription": "Umbral personalizado solo para este perfil (anula el predeterminado global)", + "inheritDescription": "Este perfil hereda el umbral predeterminado global ({{threshold}}%)", + "usesGlobal": "(usa global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 2ac2efcc004..085376b4a78 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -370,7 +370,8 @@ "hint": "Vide = utiliser le prompt par défaut" }, "autoCondenseContext": { - "name": "Déclencher automatiquement la condensation intelligente du contexte" + "name": "Déclencher automatiquement la condensation intelligente du contexte", + "description": "Lorsque cette option est activée, Roo condensera automatiquement le contexte lorsque le seuil est atteint. Lorsqu'elle est désactivée, vous pouvez toujours déclencher manuellement la condensation du contexte." }, "openTabs": { "label": "Limite de contexte des onglets ouverts", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Limite de lectures simultanées", "description": "Nombre maximum de fichiers que l'outil 'read_file' peut traiter simultanément. Des valeurs plus élevées peuvent accélérer la lecture de plusieurs petits fichiers mais augmentent l'utilisation de la mémoire." + }, + "condensingThreshold": { + "label": "Seuil de condensation du contexte", + "selectProfile": "Configurer le seuil pour le profil", + "defaultProfile": "Par défaut global (tous les profils)", + "defaultDescription": "Lorsque le contexte atteint ce pourcentage, il sera automatiquement condensé pour tous les profils sauf s'ils ont des paramètres personnalisés", + "profileDescription": "Seuil personnalisé pour ce profil uniquement (remplace le défaut global)", + "inheritDescription": "Ce profil hérite du seuil par défaut global ({{threshold}}%)", + "usesGlobal": "(utilise global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 87628e55508..62ad6caad1b 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -370,7 +370,8 @@ "hint": "खाली = डिफ़ॉल्ट प्रॉम्प्ट का उपयोग करें" }, "autoCondenseContext": { - "name": "बुद्धिमान संदर्भ संघनन को स्वचालित रूप से ट्रिगर करें" + "name": "बुद्धिमान संदर्भ संघनन को स्वचालित रूप से ट्रिगर करें", + "description": "जब सक्षम हो, तो Roo स्वचालित रूप से संदर्भ को संघनित करेगा जब सीमा पहुंच जाएगी। जब अक्षम हो, तो आप अभी भी मैन्युअल रूप से संदर्भ संघनन को ट्रिगर कर सकते हैं।" }, "openTabs": { "label": "खुले टैब संदर्भ सीमा", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "एक साथ फ़ाइल पढ़ने की सीमा", "description": "'read_file' टूल द्वारा एक साथ प्रोसेस की जा सकने वाली अधिकतम फ़ाइलों की संख्या। उच्च मान कई छोटी फ़ाइलों को पढ़ने की गति बढ़ा सकते हैं लेकिन मेमोरी उपयोग बढ़ा देते हैं।" + }, + "condensingThreshold": { + "label": "संघनन ट्रिगर सीमा", + "selectProfile": "प्रोफ़ाइल के लिए सीमा कॉन्फ़िगर करें", + "defaultProfile": "वैश्विक डिफ़ॉल्ट (सभी प्रोफ़ाइल)", + "defaultDescription": "जब संदर्भ इस प्रतिशत तक पहुंचता है, तो यह सभी प्रोफ़ाइल के लिए स्वचालित रूप से संघनित हो जाएगा जब तक कि उनकी कस्टम सेटिंग्स न हों", + "profileDescription": "केवल इस प्रोफ़ाइल के लिए कस्टम सीमा (वैश्विक डिफ़ॉल्ट को ओवरराइड करता है)", + "inheritDescription": "यह प्रोफ़ाइल वैश्विक डिफ़ॉल्ट सीमा को इनहेरिट करता है ({{threshold}}%)", + "usesGlobal": "(वैश्विक {{threshold}}% का उपयोग करता है)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 1a4005446c4..afad7d8700f 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -374,7 +374,17 @@ "hint": "Kosong = gunakan prompt default" }, "autoCondenseContext": { - "name": "Secara otomatis memicu kondensasi konteks cerdas" + "name": "Secara otomatis memicu kondensasi konteks cerdas", + "description": "Ketika diaktifkan, Roo akan secara otomatis mengondensasi konteks ketika ambang batas tercapai. Ketika dinonaktifkan, kamu masih dapat memicu kondensasi konteks secara manual." + }, + "condensingThreshold": { + "label": "Ambang Batas Pemicu Kondensasi", + "selectProfile": "Konfigurasi ambang batas untuk profil", + "defaultProfile": "Default Global (semua profil)", + "defaultDescription": "Ketika konteks mencapai persentase ini, akan secara otomatis dikondensasi untuk semua profil kecuali mereka memiliki pengaturan kustom", + "profileDescription": "Ambang batas kustom untuk profil ini saja (menimpa default global)", + "inheritDescription": "Profil ini mewarisi ambang batas default global ({{threshold}}%)", + "usesGlobal": "(menggunakan global {{threshold}}%)" }, "openTabs": { "label": "Batas konteks tab terbuka", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 515cbe8ec73..6d7d8417a05 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -370,7 +370,8 @@ "hint": "Vuoto = usa prompt predefinito" }, "autoCondenseContext": { - "name": "Attiva automaticamente la condensazione intelligente del contesto" + "name": "Attiva automaticamente la condensazione intelligente del contesto", + "description": "Quando abilitato, Roo condenserà automaticamente il contesto quando viene raggiunta la soglia. Quando disabilitato, puoi ancora attivare manualmente la condensazione del contesto." }, "openTabs": { "label": "Limite contesto schede aperte", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Limite letture simultanee", "description": "Numero massimo di file che lo strumento 'read_file' può elaborare contemporaneamente. Valori più alti possono velocizzare la lettura di più file piccoli ma aumentano l'utilizzo della memoria." + }, + "condensingThreshold": { + "label": "Soglia di attivazione condensazione", + "selectProfile": "Configura soglia per profilo", + "defaultProfile": "Predefinito globale (tutti i profili)", + "defaultDescription": "Quando il contesto raggiunge questa percentuale, verrà automaticamente condensato per tutti i profili a meno che non abbiano impostazioni personalizzate", + "profileDescription": "Soglia personalizzata solo per questo profilo (sovrascrive il predefinito globale)", + "inheritDescription": "Questo profilo eredita la soglia predefinita globale ({{threshold}}%)", + "usesGlobal": "(usa globale {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 3d3e53d6cdf..14a6aae7fc9 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -370,7 +370,8 @@ "hint": "空 = デフォルトプロンプトを使用" }, "autoCondenseContext": { - "name": "インテリジェントなコンテキスト圧縮を自動的にトリガーする" + "name": "インテリジェントなコンテキスト圧縮を自動的にトリガーする", + "description": "有効にすると、Rooは閾値に達したときに自動的にコンテキストを圧縮します。無効にすると、手動でコンテキスト圧縮をトリガーできます。" }, "openTabs": { "label": "オープンタブコンテキスト制限", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "同時ファイル読み取り制限", "description": "read_file ツールが同時に処理できるファイルの最大数。値を高くすると複数の小さなファイルの読み取りが速くなる可能性がありますが、メモリ使用量が増加します。" + }, + "condensingThreshold": { + "label": "圧縮トリガーしきい値", + "selectProfile": "プロファイルのしきい値を設定", + "defaultProfile": "グローバルデフォルト(全プロファイル)", + "defaultDescription": "コンテキストがこの割合に達すると、カスタム設定がない限り、すべてのプロファイルで自動的に圧縮されます", + "profileDescription": "このプロファイルのみのカスタムしきい値(グローバルデフォルトを上書き)", + "inheritDescription": "このプロファイルはグローバルデフォルトしきい値を継承します({{threshold}}%)", + "usesGlobal": "(グローバル {{threshold}}% を使用)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index eb0417ba760..abfd71bf365 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -370,7 +370,8 @@ "hint": "비어있음 = 기본 프롬프트 사용" }, "autoCondenseContext": { - "name": "지능적 컨텍스트 압축 자동 트리거" + "name": "지능적 컨텍스트 압축 자동 트리거", + "description": "활성화되면 Roo는 임계값에 도달했을 때 자동으로 컨텍스트를 압축합니다. 비활성화되면 여전히 수동으로 컨텍스트 압축을 트리거할 수 있습니다." }, "openTabs": { "label": "열린 탭 컨텍스트 제한", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "동시 파일 읽기 제한", "description": "read_file 도구가 동시에 처리할 수 있는 최대 파일 수입니다. 높은 값은 여러 작은 파일을 읽는 속도를 높일 수 있지만 메모리 사용량이 증가합니다." + }, + "condensingThreshold": { + "label": "압축 트리거 임계값", + "selectProfile": "프로필 임계값 구성", + "defaultProfile": "글로벌 기본값 (모든 프로필)", + "defaultDescription": "컨텍스트가 이 비율에 도달하면 사용자 정의 설정이 없는 한 모든 프로필에 대해 자동으로 압축됩니다", + "profileDescription": "이 프로필만을 위한 사용자 정의 임계값 (글로벌 기본값 재정의)", + "inheritDescription": "이 프로필은 글로벌 기본 임계값을 상속합니다 ({{threshold}}%)", + "usesGlobal": "(글로벌 {{threshold}}% 사용)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index d94ad5480e7..54b5c32795a 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -370,7 +370,8 @@ "hint": "Leeg = gebruik standaardprompt" }, "autoCondenseContext": { - "name": "Automatisch intelligente contextcompressie activeren" + "name": "Automatisch intelligente contextcompressie activeren", + "description": "Wanneer ingeschakeld, zal Roo automatisch de context comprimeren wanneer de drempel wordt bereikt. Wanneer uitgeschakeld, kun je nog steeds handmatig contextcompressie activeren." }, "openTabs": { "label": "Limiet geopende tabbladen in context", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Limiet gelijktijdige bestandslezingen", "description": "Maximum aantal bestanden dat de 'read_file' tool tegelijkertijd kan verwerken. Hogere waarden kunnen het lezen van meerdere kleine bestanden versnellen maar verhogen het geheugengebruik." + }, + "condensingThreshold": { + "label": "Compressie trigger drempelwaarde", + "selectProfile": "Drempelwaarde voor profiel configureren", + "defaultProfile": "Globale standaard (alle profielen)", + "defaultDescription": "Wanneer de context dit percentage bereikt, wordt het automatisch gecomprimeerd voor alle profielen tenzij ze aangepaste instellingen hebben", + "profileDescription": "Aangepaste drempelwaarde alleen voor dit profiel (overschrijft globale standaard)", + "inheritDescription": "Dit profiel erft de globale standaard drempelwaarde ({{threshold}}%)", + "usesGlobal": "(gebruikt globaal {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 8b900ae0d4c..96e33e60b9e 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -370,7 +370,8 @@ "hint": "Puste = użyj domyślnego monitu" }, "autoCondenseContext": { - "name": "Automatycznie wyzwalaj inteligentną kondensację kontekstu" + "name": "Automatycznie wyzwalaj inteligentną kondensację kontekstu", + "description": "Gdy włączone, Roo automatycznie skondensuje kontekst po osiągnięciu progu. Gdy wyłączone, nadal możesz ręcznie wyzwolić kondensację kontekstu." }, "openTabs": { "label": "Limit kontekstu otwartych kart", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Limit jednoczesnych odczytów", "description": "Maksymalna liczba plików, które narzędzie 'read_file' może przetwarzać jednocześnie. Wyższe wartości mogą przyspieszyć odczyt wielu małych plików, ale zwiększają zużycie pamięci." + }, + "condensingThreshold": { + "label": "Próg wyzwalania kondensacji", + "selectProfile": "Skonfiguruj próg dla profilu", + "defaultProfile": "Globalny domyślny (wszystkie profile)", + "defaultDescription": "Gdy kontekst osiągnie ten procent, zostanie automatycznie skondensowany dla wszystkich profili, chyba że mają niestandardowe ustawienia", + "profileDescription": "Niestandardowy próg tylko dla tego profilu (zastępuje globalny domyślny)", + "inheritDescription": "Ten profil dziedziczy globalny domyślny próg ({{threshold}}%)", + "usesGlobal": "(używa globalnego {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 9d1884efa91..56b82cc8494 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -370,7 +370,8 @@ "hint": "Vazio = usar prompt padrão" }, "autoCondenseContext": { - "name": "Acionar automaticamente a condensação inteligente de contexto" + "name": "Acionar automaticamente a condensação inteligente de contexto", + "description": "Quando habilitado, o Roo condensará automaticamente o contexto quando o limite for atingido. Quando desabilitado, você ainda pode acionar manualmente a condensação de contexto." }, "openTabs": { "label": "Limite de contexto de abas abertas", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Limite de leituras simultâneas", "description": "Número máximo de arquivos que a ferramenta 'read_file' pode processar simultaneamente. Valores mais altos podem acelerar a leitura de vários arquivos pequenos, mas aumentam o uso de memória." + }, + "condensingThreshold": { + "label": "Limite de Ativação de Condensação", + "selectProfile": "Configurar limite para perfil", + "defaultProfile": "Padrão Global (todos os perfis)", + "defaultDescription": "Quando o contexto atingir essa porcentagem, será automaticamente condensado para todos os perfis, a menos que tenham configurações personalizadas", + "profileDescription": "Limite personalizado apenas para este perfil (substitui o padrão global)", + "inheritDescription": "Este perfil herda o limite padrão global ({{threshold}}%)", + "usesGlobal": "(usa global {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index c6a9bca2d61..6290cbe238d 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -370,7 +370,8 @@ "hint": "Пусто = использовать промпт по умолчанию" }, "autoCondenseContext": { - "name": "Автоматически запускать интеллектуальное сжатие контекста" + "name": "Автоматически запускать интеллектуальное сжатие контекста", + "description": "Когда включено, Roo будет автоматически сжимать контекст при достижении порога. Когда отключено, вы все еще можете вручную запускать сжатие контекста." }, "openTabs": { "label": "Лимит контекста открытых вкладок", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Лимит одновременного чтения", "description": "Максимальное количество файлов, которые инструмент 'read_file' может обрабатывать одновременно. Более высокие значения могут ускорить чтение нескольких небольших файлов, но увеличивают использование памяти." + }, + "condensingThreshold": { + "label": "Порог запуска сжатия", + "selectProfile": "Настроить порог для профиля", + "defaultProfile": "Глобальный по умолчанию (все профили)", + "defaultDescription": "Когда контекст достигнет этого процента, он будет автоматически сжат для всех профилей, если у них нет пользовательских настроек", + "profileDescription": "Пользовательский порог только для этого профиля (переопределяет глобальный по умолчанию)", + "inheritDescription": "Этот профиль наследует глобальный порог по умолчанию ({{threshold}}%)", + "usesGlobal": "(использует глобальный {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 6f42914336b..ab4992d4cb2 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -370,7 +370,8 @@ "hint": "Boş = varsayılan promptu kullan" }, "autoCondenseContext": { - "name": "Akıllı bağlam sıkıştırmayı otomatik olarak tetikle" + "name": "Akıllı bağlam sıkıştırmayı otomatik olarak tetikle", + "description": "Etkinleştirildiğinde, Roo eşiğe ulaşıldığında bağlamı otomatik olarak sıkıştırır. Devre dışı bırakıldığında, bağlam sıkıştırmayı hala manuel olarak tetikleyebilirsiniz." }, "openTabs": { "label": "Açık sekmeler bağlam sınırı", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Eşzamanlı dosya okuma sınırı", "description": "'read_file' aracının aynı anda işleyebileceği maksimum dosya sayısı. Daha yüksek değerler birden çok küçük dosyanın okunmasını hızlandırabilir ancak bellek kullanımını artırır." + }, + "condensingThreshold": { + "label": "Sıkıştırma Tetikleme Eşiği", + "selectProfile": "Profil için eşik yapılandır", + "defaultProfile": "Küresel Varsayılan (tüm profiller)", + "defaultDescription": "Bağlam bu yüzdeye ulaştığında, özel ayarları olmadıkça tüm profiller için otomatik olarak sıkıştırılacak", + "profileDescription": "Sadece bu profil için özel eşik (küresel varsayılanı geçersiz kılar)", + "inheritDescription": "Bu profil küresel varsayılan eşiği miras alır ({{threshold}}%)", + "usesGlobal": "(küresel {{threshold}}% kullanır)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index b728ac1766b..9656e0c6e15 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -370,7 +370,8 @@ "hint": "Để trống = sử dụng prompt mặc định" }, "autoCondenseContext": { - "name": "Tự động kích hoạt nén ngữ cảnh thông minh" + "name": "Tự động kích hoạt nén ngữ cảnh thông minh", + "description": "Khi được bật, Roo sẽ tự động nén ngữ cảnh khi đạt đến ngưỡng. Khi bị tắt, bạn vẫn có thể kích hoạt nén ngữ cảnh thủ công." }, "openTabs": { "label": "Giới hạn ngữ cảnh tab đang mở", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "Giới hạn đọc file đồng thời", "description": "Số lượng file tối đa mà công cụ 'read_file' có thể xử lý cùng lúc. Giá trị cao hơn có thể tăng tốc độ đọc nhiều file nhỏ nhưng sẽ tăng mức sử dụng bộ nhớ." + }, + "condensingThreshold": { + "label": "Ngưỡng kích hoạt nén", + "selectProfile": "Cấu hình ngưỡng cho hồ sơ", + "defaultProfile": "Mặc định toàn cục (tất cả hồ sơ)", + "defaultDescription": "Khi ngữ cảnh đạt đến tỷ lệ phần trăm này, nó sẽ được tự động nén cho tất cả hồ sơ trừ khi chúng có cài đặt tùy chỉnh", + "profileDescription": "Ngưỡng tùy chỉnh chỉ cho hồ sơ này (ghi đè mặc định toàn cục)", + "inheritDescription": "Hồ sơ này kế thừa ngưỡng mặc định toàn cục ({{threshold}}%)", + "usesGlobal": "(sử dụng toàn cục {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f02923e14ff..c1639200217 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -370,7 +370,8 @@ "hint": "留空 = 使用默认提示词" }, "autoCondenseContext": { - "name": "自动触发智能上下文压缩" + "name": "自动触发智能上下文压缩", + "description": "启用时,Roo 将在达到阈值时自动压缩上下文。禁用时,您仍可以手动触发上下文压缩。" }, "openTabs": { "label": "标签页数量限制", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "并发文件读取限制", "description": "read_file 工具可以同时处理的最大文件数。较高的值可能会加快读取多个小文件的速度,但会增加内存使用量。" + }, + "condensingThreshold": { + "label": "压缩触发阈值", + "selectProfile": "配置配置文件阈值", + "defaultProfile": "全局默认(所有配置文件)", + "defaultDescription": "当上下文达到此百分比时,将自动为所有配置文件压缩,除非它们有自定义设置", + "profileDescription": "仅此配置文件的自定义阈值(覆盖全局默认)", + "inheritDescription": "此配置文件继承全局默认阈值({{threshold}}%)", + "usesGlobal": "(使用全局 {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index e8b0d2d3cf7..e85da857d01 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -370,7 +370,8 @@ "hint": "留空 = 使用預設提示" }, "autoCondenseContext": { - "name": "自動觸發智慧上下文壓縮" + "name": "自動觸發智慧上下文壓縮", + "description": "啟用時,Roo 會在達到閾值時自動壓縮上下文。停用時,您仍可手動觸發上下文壓縮。" }, "openTabs": { "label": "開啟分頁的上下文限制", @@ -393,6 +394,15 @@ "maxConcurrentFileReads": { "label": "並行檔案讀取限制", "description": "read_file 工具可以同時處理的最大檔案數。較高的值可能會加快讀取多個小檔案的速度,但會增加記憶體使用量。" + }, + "condensingThreshold": { + "label": "壓縮觸發閾值", + "selectProfile": "設定檔案閾值", + "defaultProfile": "全域預設(所有檔案)", + "defaultDescription": "當上下文達到此百分比時,將自動為所有檔案壓縮,除非它們有自訂設定", + "profileDescription": "僅此檔案的自訂閾值(覆蓋全域預設)", + "inheritDescription": "此檔案繼承全域預設閾值({{threshold}}%)", + "usesGlobal": "(使用全域 {{threshold}}%)" } }, "terminal": { diff --git a/webview-ui/src/utils/__tests__/validate.test.ts b/webview-ui/src/utils/__tests__/validate.test.ts index 404b50e1dd6..3a60c27f8ad 100644 --- a/webview-ui/src/utils/__tests__/validate.test.ts +++ b/webview-ui/src/utils/__tests__/validate.test.ts @@ -36,6 +36,8 @@ describe("Model Validation Functions", () => { requesty: {}, unbound: {}, litellm: {}, + ollama: {}, + lmstudio: {}, } const allowAllOrganization: OrganizationAllowList = { diff --git a/webview-ui/src/utils/validate.ts b/webview-ui/src/utils/validate.ts index 9fc393eafea..1040b60c2df 100644 --- a/webview-ui/src/utils/validate.ts +++ b/webview-ui/src/utils/validate.ts @@ -227,6 +227,12 @@ export function validateModelId(apiConfiguration: ProviderSettings, routerModels case "requesty": modelId = apiConfiguration.requestyModelId break + case "ollama": + modelId = apiConfiguration.ollamaModelId + break + case "lmstudio": + modelId = apiConfiguration.lmStudioModelId + break case "litellm": modelId = apiConfiguration.litellmModelId break