- Developers can create Custom Modes for specialized tasks like security auditing or
- performance tuning.
+ Deploy your Roo Code control-plane instantly with our SaaS solution. No infrastructure
+ required.
- Ask Mode enables developers to query their codebase in plain language and receive
- instant answers.
+ Track and control Roo Code costs with detailed analytics and budget controls.
- Automate routine tasks to accelerate software releases and reduce costs.
+ Developers get seamless Roo Code access while you maintain governance and visibility.
-
+
- Roo Code Marketing Landing Page Privacy Policy
+ Roo Code Cloud Privacy Policy
-
Last Updated: March 7th, 2025
+
Last Updated: June 19, 2025
- Roo Code respects your privacy and is committed to being transparent about how data is collected
- and used on our marketing landing page. This policy focuses on data handling for the Roo Code
- marketing website. For details on how your data is handled within the Roo Code extension itself,
- please refer to our separate{" "}
-
- Roo Code Extension Privacy Policy
-
- .
+ This Privacy Policy explains how Roo Code, Inc. ("Roo Code," "we,"
+ "our," or "us") collects, uses, and shares information when you:
-
-
Where Your Data Goes (And Where It Doesn't)
-
-
Website Analytics & Tracking
-
+
- We use PostHog (and its standard features) on our marketing landing page to analyze site
- traffic and usage trends. This collection includes information such as your IP address,
- browser type, device information, and pages visited.
+ browse any page under roocode.com (the Marketing Site ); and/or
- These analytics help us understand how users engage with the website, so we can improve
- content and design.
-
- We do not collect code, project data, or any AI-related prompts on this page.
-
-
- Cookies and Similar Technologies
-
-
- Our marketing website may use cookies or similar tracking technologies to remember user
- preferences and provide aggregated analytics.
-
-
- Cookies help with things like user session management, remembering certain selections or
- preferences, and compiling anonymous statistics.
+ create an account for, sign in to, or otherwise use Roo Code Cloud at{" "}
+ app.roocode.com or through the Roo Code extension while authenticated to
+ that Cloud account (the Cloud Service ).
- Forms & Voluntary Submissions
-
-
- If you submit your email or other personal data on our landing page (for example, to receive
- updates or join a waiting list), we collect that information voluntarily provided by you.
-
-
- We do not share or sell this data to third parties for their own marketing purposes. It is
- used only to communicate with you about Roo Code, respond to inquiries, or send updates
- you've requested.
-
-
-
- Third-Party Integrations
-
-
- Our website may embed content or links to external platforms (e.g., for processing payments
- or handling support). Any data you provide through these external sites is governed by the
- privacy policies of those platforms.
-
-
-
- How We Use Your Data
-
- Site Improvements & Marketing
-
-
- We analyze aggregated user behavior to measure the effectiveness of our site, troubleshoot
- any issues, and guide future improvements.
-
-
- If you sign up for newsletters or updates, we use your email or other contact information
- only to send you relevant Roo Code communications.
-
-
-
- No Selling or Sharing of Data
-
-
- We do not sell or share your personally identifiable information with third parties for
- their marketing.
-
- We do not train any models on your marketing site data.
-
-
- Your Choices & Control
-
- Manage Cookies
-
-
- Most browsers allow you to manage or block cookies. If you disable cookies, some features of
- the site may not function properly.
-
-
-
- Opt-Out of Communications
-
-
- If you have signed up to receive updates, you can unsubscribe anytime by following the
- instructions in our emails or contacting us directly.
-
-
-
- Request Deletion
-
-
- You may request the deletion of any personal data you've provided through our marketing
- forms by reaching out to us at{" "}
-
- support@roocode.com
-
- .
-
-
-
- Security & Updates
-
-
- We take reasonable measures to protect your data from unauthorized access or disclosure, but
- no website can be 100% secure.
-
-
- If our privacy practices for the marketing site change, we will update this policy and note
- the effective date at the top.
-
-
-
- Contact Us
-
- If you have questions or concerns about this Privacy Policy or wish to make a request regarding
- your data, please reach out to us at{" "}
-
- support@roocode.com
-
- .
-
-
-
-
- By using the Roo Code marketing landing page, you agree to this Privacy Policy. If you use
- the Roo Code extension, please see our separate{" "}
+
+
Extension‑Only Usage
+
+ If you run the Roo Code extension without connecting to a Cloud account,
+ your data is governed by the standalone{" "}
Roo Code Extension Privacy Policy
- {" "}
- for details on data handling in the extension.
+
+ .
+
+
Quick Summary
+
+
+ Your source code never transits Roo Code servers. It stays on your device
+ and is sent directly —via a client‑to‑provider TLS connection—to the
+ third‑party AI model you select. Roo Code never stores, inspects, or trains on your code.
+
+
+ Prompts and chat snippets are collected by default in Roo Code Cloud so you
+ can search and re‑use past conversations. Organization admins can disable this collection at
+ any time.
+
+
+ We collect only the data needed to operate Roo Code Cloud, do not sell
+ customer data, and do not use your content to train models.
+
+
+
+
1. Information We Collect
+
+
+
+
+
+ Category
+ Examples
+ Source
+
+
+
+
+ Account Information
+
+ Name, email, organization, auth tokens
+
+ You
+
+
+
+ Workspace Configuration
+
+
+ Org settings, allow‑lists, rules files, modes, dashboards
+
+ You / Extension (when signed in)
+
+
+
+ Prompts, Chat Snippets & Token Counts
+
+
+ Text prompts, model outputs, token counts
+
+ Extension (when signed in)
+
+
+ Usage Data
+
+ Feature clicks, error logs, performance metrics (captured via PostHog)
+
+ Services automatically (PostHog)
+
+
+ Payment Data
+
+ Tokenized card details, billing address, invoices
+
+ Payment processor (Stripe)
+
+
+ Marketing Data
+
+ Cookies, IP address, browser type, page views,{" "}
+ voluntary form submissions (e.g., newsletter or wait‑list
+ sign‑ups)
+
+
+ Marketing Site automatically / You
+
+
+
+
+
+
+
2. How We Use Information
+
+
+ Operate & secure Roo Code Cloud (authentication, completions, abuse
+ prevention)
+
+
+ Provide support & improve features (debugging, analytics, product
+ decisions)
+
+
+ Process payments & manage subscriptions
+
+
+ Send product updates and roadmap communications (opt‑out available)
+
+
+
+
3. Where Your Data Goes (And Doesn't)
+
+
+
+
+
+ Data
+ Sent To
+
+ Not Sent To
+
+
+
+
+
+
+ Code & files you work on
+
+
+ Your chosen model provider (direct client → provider TLS)
+
+
+ Roo Code servers; ad networks; model‑training pipelines
+
+
+
+
+ Prompts, chat snippets & token counts (Cloud)
+
+
+ Roo Code Cloud (encrypted at rest)
+
+ Any third‑party
+
+
+
+ Workspace Configuration
+
+
+ Roo Code Cloud (encrypted at rest)
+
+ Any third-party
+
+
+ Usage & Telemetry
+
+ PostHog (self‑hosted analytics platform)
+
+ Ad networks or data brokers
+
+
+ Payment Data
+ Stripe (PCI‑DSS Level 1)
+
+ Roo Code servers (we store only the Stripe customer ID)
+
+
+
+
+
+
+
4. Data Retention
+
+
+ Source Code: Never stored on Roo Code servers.
+
+
+ Prompts & Chat Snippets: Persist in your Cloud workspace until you or your
+ organization admin deletes them or disables collection.
+
+
+ Operational Logs & Analytics: Retained only as needed to operate and secure
+ Roo Code Cloud.
+
+
+
+
5. Your Choices
+
+
+ Manage cookies: You can block or delete cookies in your browser settings;
+ some site features may not function without them.
+
+
+ Disable prompt collection in Organization settings.
+
+
+ Delete your Cloud account at any time from{" "}
+ Security Settings inside Roo Code Cloud.
+
+
+
+
6. Security Practices
+
+ We use TLS for all data in transit, AES‑256 encryption at rest, least‑privilege IAM, continuous
+ monitoring, routine penetration testing, and maintain a SOC 2 program.
+
+
+
7. Updates to This Policy
+
+ If our privacy practices change, we will update this policy and note the new{" "}
+ Last Updated date at the top. For material changes that affect Cloud
+ workspaces, we will also email registered workspace owners before the changes take effect.
+
+
+
8. Contact Us
+
+ Questions or concerns? Email{" "}
+
+ privacy@roocode.com
+
+ .
+
>
diff --git a/apps/web-roo-code/src/app/terms/page.tsx b/apps/web-roo-code/src/app/terms/page.tsx
new file mode 100644
index 0000000000..545e577457
--- /dev/null
+++ b/apps/web-roo-code/src/app/terms/page.tsx
@@ -0,0 +1,320 @@
+import { Metadata } from "next"
+
+export const metadata: Metadata = {
+ title: "Terms of Service - Roo Code",
+ description:
+ "Terms of Service for Roo Code Cloud. Learn about our service terms, commercial conditions, and legal framework.",
+}
+
+export default function Terms() {
+ return (
+ <>
+
+
+
+ Roo Code Cloud Terms of Service
+
+
+ (Version 1.0 – Effective June 19, 2025)
+
+
+
+ These Terms of Service ("TOS ") govern access to and use of the Roo
+ Code Cloud service (the "Service "). They apply to:
+
+
+
+ (a) every Sales Order Form or similar document mutually
+ executed by Roo Code and the customer that references these TOS; and
+
+
+ (b) any{" "}
+ online plan-selection, self-service sign-up, or in-app purchase flow {" "}
+ through which a customer clicks an "I Agree" (or equivalent) button to accept
+ these TOS — such flow also being an "Order Form."
+
+
+
+
+ By creating an account, clicking to accept, or using the Service , the person or
+ entity doing so ("Customer ") agrees to be bound by these TOS, even if
+ no separate Order Form is signed.
+
+
+
+ If Roo Code and Customer later execute a Master Subscription Agreement ("
+ MSA "), the MSA governs; otherwise, these TOS and the applicable Order Form
+ together form the entire agreement (the "Agreement ").
+
+
+
1. Agreement Framework
+
+
+ Incorporation of Standard Terms.
+
+ The{" "}
+
+ Common Paper Cloud Service Standard Terms v 2.0
+ {" "}
+ (the "Standard Terms ") are incorporated by reference. If these
+ TOS conflict with the Standard Terms, these TOS control.
+
+
+ Order of Precedence.
+
+ (a) Order Form (b) these TOS (c) Standard Terms.
+
+
+
+
2. Key Commercial Terms
+
+
+
+
+
+ Term
+ Value
+
+
+
+
+
+ Governing Law / Forum
+
+
+ Delaware law; exclusive jurisdiction and venue in the state or federal courts
+ located in Delaware
+
+
+
+
+ Plans & Subscription Periods
+
+
+ Free Plan: month-to-month.
+
+ Paid Plans: Monthly or Annual, as selected in an Order
+ Form or the online flow.
+
+
+
+
+ Auto-Renewal & Non-Renewal Notice
+
+
+ Free Plan: renews continuously until cancelled in the dashboard.
+
+ Paid Plans: renew for the same period unless either party gives 30
+ days' written notice before the current period ends.
+
+
+
+ Fees & Usage
+
+ Free Plan: Subscription Fee = $0.
+
+ Paid Plans: Fees stated in the Order Form or online checkout{" "}
+ plus usage-based fees, calculated and invoiced monthly.
+
+
+
+ Payment Terms
+
+ Monthly paid plans: credit-card charge on the billing date.
+
+ Annual paid plans: invoiced Net 30 (credit card optional).
+
+
+
+
+ General Liability Cap
+
+
+ The greater of (i) USD 100 and (ii) 1 × Fees paid or payable in the 12 months
+ before the event giving rise to liability.
+
+
+
+
+ Increased Cap / Unlimited Claims
+
+ None
+
+
+ Trial / Pilot
+ Not offered
+
+
+ Beta Features
+
+ None – only generally available features are provided
+
+
+
+ Security Standard
+
+ Roo Code maintains commercially reasonable administrative, physical, and
+ technical safeguards
+
+
+
+ Machine-Learning Use
+
+ Roo Code does not use Customer Content to train, fine-tune, or
+ improve any ML or AI models
+
+
+
+
+ Data Processing Addendum (DPA)
+
+
+ GDPR/CCPA-ready DPA available upon written request
+
+
+
+
+ Publicity / Logo Rights
+
+
+ Roo Code may identify Customer (name & logo) in marketing materials unless
+ Customer opts out in writing
+
+
+
+
+
+
+
3. Modifications to the Standard Terms
+
+
+ Section 1.6 (Machine Learning).
+
+ "Provider will not use Customer Content or Usage Data to train, fine-tune, or improve
+ any machine-learning or AI model, except with Customer's prior written consent."
+
+
+ Section 3 (Security).
+
+ Replace "reasonable" with "commercially reasonable."
+
+
+ Section 4 (Fees & Payment).
+
+ Add usage-billing language above and delete any provision allowing unilateral fee increases.
+
+
+ Section 5 (Term & Termination).
+
+ Insert auto-renewal and free-plan language above.
+
+
+ Sections 7 (Trials / Betas) and any SLA references.
+
+ Deleted – Roo Code offers no trials, pilots, betas, or SLA credits under these TOS.
+
+
+ Section 12.12 (Publicity).
+
+ As reflected in the "Publicity / Logo Rights" row above.
+
+
+
+
4. Use of the Service
+
+ Customer may access and use the Service solely for its internal business purposes and subject to
+ the Acceptable Use Policy in the Standard Terms.
+
+
+
5. Account Management & Termination
+
+
+ Self-service cancellation or downgrade.
+
+ Customer may cancel a Free Plan immediately, or cancel/downgrade a Paid Plan effective at
+ the end of the current billing cycle, via the web dashboard.
+
+
+ Either party may otherwise terminate the Agreement as allowed under Section 5 of the
+ Standard Terms.
+
+
+
+
6. Privacy & Data
+
+ Roo Code's Privacy Notice (
+
+ https://roocode.com/privacy
+
+ ) explains how Roo Code collects and handles personal information. If Customer requires a DPA,
+ email{" "}
+
+ support@roocode.com
+
+ .
+
+
+
7. Warranty Disclaimer
+
+ Except as expressly stated in the Agreement, the Service is provided{" "}
+ "as is," and all implied warranties are disclaimed to the maximum
+ extent allowed by law.
+
+
+
8. Limitation of Liability
+
+ The caps in Section 2 apply to all claims under the Agreement, whether in contract, tort, or
+ otherwise, except for Excluded Claims defined in the Standard Terms.
+
+
+
9. Miscellaneous
+
+
+ Assignment.
+
+ Customer may not assign the Agreement without Roo Code's prior written consent, except
+ to a successor in a merger or sale of substantially all assets.
+
+
+ Export Compliance.
+
+ Each party will comply with all applicable export-control laws and regulations and will not
+ export or re-export any software or technical data without the required government licences.
+
+
+ Entire Agreement.
+
+ The Agreement supersedes all prior or contemporaneous agreements for the Service.
+
+
+ Amendments.
+
+ Roo Code may update these TOS by posting a revised version at the same URL and emailing or
+ in-app notifying Customer at least 30 days before changes take effect. Continued use after
+ the effective date constitutes acceptance.
+
+
+
+
10. Contact
+
+ Roo Code, Inc.
+
+ 98 Graceland Dr, San Rafael, CA 94901 USA
+
+ Email:{" "}
+
+ support@roocode.com
+
+
+
+
+ >
+ )
+}
diff --git a/apps/web-roo-code/src/components/chromes/footer.tsx b/apps/web-roo-code/src/components/chromes/footer.tsx
index 850f5f3d3e..0d322f31e1 100644
--- a/apps/web-roo-code/src/components/chromes/footer.tsx
+++ b/apps/web-roo-code/src/components/chromes/footer.tsx
@@ -246,6 +246,13 @@ export function Footer() {
Careers
+
+
+ Terms of Service
+
+
setPrivacyDropdownOpen(false)}
className="rounded-md px-3 py-2 transition-colors hover:bg-accent/50 hover:text-foreground">
- Marketing Website
+ Roo Code Cloud
diff --git a/locales/ca/README.md b/locales/ca/README.md
index 32b916dcb8..c653f54fbb 100644
--- a/locales/ca/README.md
+++ b/locales/ca/README.md
@@ -50,13 +50,13 @@ Consulteu el [CHANGELOG](../../CHANGELOG.md) per a actualitzacions i correccions
---
-## 🎉 Roo Code 3.20 Llançat
+## 🎉 Roo Code 3.21 Llançat
-Roo Code 3.20 aporta noves funcionalitats majors i millores basades en els vostres comentaris!
+Roo Code 3.21 aporta noves funcionalitats majors i millores basades en els vostres comentaris!
-- **Marketplace Experimental** - Descobriu i instal·leu modes i MCPs des del nou marketplace (activeu-lo als Paràmetres Experimentals).
-- **Operacions de Fitxers Millorades** - Múltiples escriptures de fitxers simultànies ara disponibles als Paràmetres Experimentals, i múltiples lectures simultànies s'han graduat de l'experimental i ara viuen als Paràmetres de Context.
-- **Millores MCP i Més** - Suport MCP millorat, més controls Mermaid, suport de pensament a Amazon Bedrock, i molt més!
+- **Llançament del Marketplace Roo** - El marketplace ja està en funcionament! El marketplace ja està en funcionament! Descobreix i instal·la modes i MCP més fàcilment que mai.
+- **Models Gemini 2.5** - S'ha afegit suport per als nous models Gemini 2.5 Pro, Flash i Flash Lite.
+- **Suport per a fitxers Excel i més** - S'ha afegit suport per a fitxers Excel (.xlsx) i nombroses correccions d'errors i millores!
---
@@ -184,35 +184,37 @@ Gràcies a tots els nostres col·laboradors que han ajudat a millorar Roo Code!
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Llicència
diff --git a/locales/de/README.md b/locales/de/README.md
index 2cf784c83a..24f1e4d69e 100644
--- a/locales/de/README.md
+++ b/locales/de/README.md
@@ -50,13 +50,13 @@ Sehen Sie sich das [CHANGELOG](../../CHANGELOG.md) für detaillierte Updates und
---
-## 🎉 Roo Code 3.20 veröffentlicht
+## 🎉 Roo Code 3.21 veröffentlicht
-Roo Code 3.20 bringt wichtige neue Funktionen und Verbesserungen basierend auf eurem Feedback!
+Roo Code 3.21 bringt wichtige neue Funktionen und Verbesserungen basierend auf eurem Feedback!
-- **Experimenteller Marketplace** - Entdecke und installiere Modi und MCPs aus dem neuen Marketplace (aktiviere ihn in den Experimentellen Einstellungen).
-- **Verbesserte Dateioperationen** - Mehrere gleichzeitige Dateischreibvorgänge sind jetzt in den Experimentellen Einstellungen verfügbar, und mehrere gleichzeitige Leseoperationen sind aus dem experimentellen Stadium graduiert und befinden sich nun in den Kontext-Einstellungen.
-- **MCP-Verbesserungen & Mehr** - Erweiterte MCP-Unterstützung, mehr Mermaid-Steuerelemente, Thinking-Unterstützung in Amazon Bedrock und vieles mehr!
+- **Roo Marketplace Launch** - Der Marketplace ist jetzt live! Der Marketplace ist jetzt live! Entdecke und installiere Modi und MCPs einfacher als je zuvor.
+- **Gemini 2.5 Modelle** - Unterstützung für neue Gemini 2.5 Pro, Flash und Flash Lite Modelle hinzugefügt.
+- **Excel-Datei-Unterstützung & Mehr** - Excel (.xlsx) Datei-Unterstützung hinzugefügt und zahlreiche Fehlerbehebungen und Verbesserungen!
---
@@ -184,35 +184,37 @@ Danke an alle unsere Mitwirkenden, die geholfen haben, Roo Code zu verbessern!
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Lizenz
diff --git a/locales/es/README.md b/locales/es/README.md
index 05083f12a3..adeca0a876 100644
--- a/locales/es/README.md
+++ b/locales/es/README.md
@@ -50,13 +50,13 @@ Consulta el [CHANGELOG](../../CHANGELOG.md) para ver actualizaciones detalladas
---
-## 🎉 Roo Code 3.20 Lanzado
+## 🎉 Roo Code 3.21 Lanzado
-¡Roo Code 3.20 trae importantes nuevas funciones y mejoras basadas en vuestros comentarios!
+¡Roo Code 3.21 trae importantes nuevas funciones y mejoras basadas en vuestros comentarios!
-- **Marketplace Experimental** - Descubre e instala modos y MCPs desde el nuevo marketplace (habilítalo en Configuraciones Experimentales).
-- **Operaciones de Archivo Mejoradas** - Múltiples escrituras de archivos concurrentes ahora disponibles en Configuraciones Experimentales, y múltiples lecturas concurrentes se ha graduado de experimental y ahora vive en las Configuraciones de Contexto.
-- **Mejoras de MCP y Más** - Soporte mejorado de MCP, más controles de Mermaid, soporte de pensamiento en Amazon Bedrock, ¡y mucho más!
+- **Lanzamiento del Marketplace de Roo** - ¡El marketplace ya está en funcionamiento! ¡El marketplace ya está en funcionamiento! Descubre e instala modos y MCPs más fácilmente que nunca.
+- **Modelos Gemini 2.5** - Se ha añadido soporte para los nuevos modelos Gemini 2.5 Pro, Flash y Flash Lite.
+- **Soporte de Archivos Excel y Más** - ¡Se ha añadido soporte para archivos Excel (.xlsx) y numerosas correcciones de errores y mejoras!
---
@@ -184,35 +184,37 @@ Usamos [changesets](https://github.com/changesets/changesets) para versionar y p
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licencia
diff --git a/locales/fr/README.md b/locales/fr/README.md
index 0aa7803fe0..80140b85fb 100644
--- a/locales/fr/README.md
+++ b/locales/fr/README.md
@@ -50,13 +50,13 @@ Consultez le [CHANGELOG](../../CHANGELOG.md) pour des mises à jour détaillées
---
-## 🎉 Roo Code 3.20 est sorti
+## 🎉 Roo Code 3.21 est sorti
-Roo Code 3.20 apporte de nouvelles fonctionnalités majeures et des améliorations basées sur vos retours !
+Roo Code 3.21 apporte de nouvelles fonctionnalités majeures et des améliorations basées sur vos retours !
-- **Marketplace Expérimental** - Découvrez et installez des modes et des MCPs depuis le nouveau marketplace (activez-le dans les Paramètres Expérimentaux).
-- **Opérations de Fichiers Améliorées** - Plusieurs écritures de fichiers simultanées maintenant disponibles dans les Paramètres Expérimentaux, et plusieurs lectures simultanées ont été promues de l'expérimental et vivent maintenant dans les Paramètres de Contexte.
-- **Améliorations MCP et Plus** - Support MCP amélioré, plus de contrôles Mermaid, support de réflexion dans Amazon Bedrock, et bien plus !
+- **Le marketplace est maintenant en ligne ! Le marketplace est maintenant en ligne !** Découvrez et installez des modes et des MCPs plus facilement que jamais.
+- **Ajout du support pour les nouveaux modèles Gemini 2.5 Pro, Flash et Flash Lite.**
+- **Support des Fichiers Excel et Plus !** - Support MCP amélioré, plus de contrôles Mermaid, support de réflexion dans Amazon Bedrock, et bien plus !
---
@@ -184,35 +184,37 @@ Merci à tous nos contributeurs qui ont aidé à améliorer Roo Code !
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licence
diff --git a/locales/hi/README.md b/locales/hi/README.md
index ea858d9103..9f20242d89 100644
--- a/locales/hi/README.md
+++ b/locales/hi/README.md
@@ -50,13 +50,13 @@
---
-## 🎉 Roo Code 3.20 जारी
+## 🎉 Roo Code 3.21 जारी
-Roo Code 3.20 आपकी प्रतिक्रियाओं के आधार पर प्रमुख नई सुविधाएँ और सुधार लाता है!
+Roo Code 3.21 आपकी प्रतिक्रियाओं के आधार पर प्रमुख नई सुविधाएँ और सुधार लाता है!
-- **प्रयोगात्मक मार्केटप्लेस** - नए मार्केटप्लेस से मोड्स और MCPs खोजें और इंस्टॉल करें (प्रयोगात्मक सेटिंग्स में सक्षम करें)।
-- **उन्नत फ़ाइल ऑपरेशन** - प्रयोगात्मक सेटिंग्स में अब मल्टिपल समकालिक फ़ाइल राइट उपलब्ध है, और मल्टिपल समकालिक रीड प्रयोगात्मक से स्नातक हो गया है और अब कॉन्टेक्स्ट सेटिंग्स में रहता है।
-- **MCP सुधार और अधिक** - उन्नत MCP समर्थन, अधिक Mermaid नियंत्रण, Amazon Bedrock में विचार समर्थन, और बहुत कुछ!
+- **मार्केटप्लेस अब लाइव है! मार्केटप्लेस अब लाइव है!** मोड्स और MCPs को पहले से कहीं आसान तरीके से खोजें और इंस्टॉल करें।
+- **नए Gemini 2.5 Pro, Flash और Flash Lite मॉडल्स के लिए समर्थन जोड़ा गया।**
+- **Excel (.xlsx) फ़ाइल समर्थन और अधिक!** - उन्नत MCP समर्थन, अधिक Mermaid नियंत्रण, Amazon Bedrock में विचार समर्थन, और बहुत कुछ!
---
@@ -184,35 +184,37 @@ Roo Code को बेहतर बनाने में मदद करने
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## लाइसेंस
diff --git a/locales/id/README.md b/locales/id/README.md
index 5e6cf614e0..3381b865b0 100644
--- a/locales/id/README.md
+++ b/locales/id/README.md
@@ -49,13 +49,13 @@ Lihat [CHANGELOG](../../CHANGELOG.md) untuk update dan perbaikan detail.
---
-## 🎉 Roo Code 3.20 Dirilis
+## 🎉 Roo Code 3.21 Dirilis
-Roo Code 3.20 menghadirkan fitur baru utama dan perbaikan berdasarkan feedback kamu!
+Roo Code 3.21 menghadirkan fitur baru utama dan perbaikan berdasarkan feedback kamu!
-- **Marketplace Eksperimental** - Temukan dan install mode serta MCP dari marketplace baru (aktifkan di Experimental Settings).
-- **Operasi File yang Ditingkatkan** - Multiple concurrent file writes kini tersedia di Experimental Settings, dan multiple concurrent reads telah lulus dari eksperimental dan sekarang berada di Context Settings.
-- **Perbaikan MCP & Lainnya** - Dukungan MCP yang ditingkatkan, kontrol Mermaid lebih banyak, dukungan thinking di Amazon Bedrock, dan masih banyak lagi!
+- **Marketplace sekarang live! Marketplace sekarang live!** Temukan dan install mode serta MCP lebih mudah dari sebelumnya.
+- **Ditambahkan dukungan untuk model Gemini 2.5 Pro, Flash, dan Flash Lite yang baru.**
+- **Dukungan File Excel (.xlsx) & Lainnya!** - Dukungan MCP yang ditingkatkan, kontrol Mermaid lebih banyak, dukungan thinking di Amazon Bedrock, dan masih banyak lagi!
---
@@ -178,35 +178,37 @@ Terima kasih kepada semua kontributor kami yang telah membantu membuat Roo Code
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## License
diff --git a/locales/it/README.md b/locales/it/README.md
index 4e0d019ca8..964db4ff34 100644
--- a/locales/it/README.md
+++ b/locales/it/README.md
@@ -50,13 +50,13 @@ Consulta il [CHANGELOG](../../CHANGELOG.md) per aggiornamenti dettagliati e corr
---
-## 🎉 Roo Code 3.20 Rilasciato
+## 🎉 Roo Code 3.21 Rilasciato
-Roo Code 3.20 porta nuove funzionalità principali e miglioramenti basati sui vostri feedback!
+Roo Code 3.21 porta nuove funzionalità principali e miglioramenti basati sui vostri feedback!
-- **Marketplace Sperimentale** - Scopri e installa mode e MCP dal nuovo marketplace (abilita nelle Impostazioni Sperimentali).
-- **Operazioni su File Migliorate** - Scritture multiple simultanee di file ora disponibili nelle Impostazioni Sperimentali, e letture multiple simultanee sono uscite dalla fase sperimentale e ora vivono nelle Impostazioni Contesto.
-- **Miglioramenti MCP e Altro** - Supporto MCP migliorato, più controlli Mermaid, supporto thinking in Amazon Bedrock, e molto altro!
+- **Il marketplace è ora live! Il marketplace è ora live!** Scopri e installa mode e MCP più facilmente che mai.
+- **Aggiunto supporto per i nuovi modelli Gemini 2.5 Pro, Flash e Flash Lite.**
+- **Supporto File Excel (.xlsx) e Altro!** - Supporto MCP migliorato, più controlli Mermaid, supporto thinking in Amazon Bedrock, e molto altro!
---
@@ -184,35 +184,37 @@ Grazie a tutti i nostri contributori che hanno aiutato a migliorare Roo Code!
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licenza
diff --git a/locales/ja/README.md b/locales/ja/README.md
index ba00310f79..90c32409fc 100644
--- a/locales/ja/README.md
+++ b/locales/ja/README.md
@@ -50,13 +50,13 @@
---
-## 🎉 Roo Code 3.20 リリース
+## 🎉 Roo Code 3.21 リリース
-Roo Code 3.20は、皆様のフィードバックに基づく新しい主要機能と改善をもたらします!
+Roo Code 3.21は、皆様のフィードバックに基づく新しい主要機能と改善をもたらします!
-- **実験的マーケットプレイス** - 新しいマーケットプレイスからモードとMCPを発見してインストール(実験的設定で有効化)。
-- **ファイル操作の改善** - ファイルの同時書き込み機能が実験的設定で利用可能になり、同時読み込み機能は実験的段階を卒業してコンテキスト設定に移動しました。
-- **MCP改善など** - MCP サポートの向上、Mermaid制御の追加、Amazon Bedrock thinking サポート、その他多数!
+- **マーケットプレイスが稼働開始!マーケットプレイスが稼働開始!** これまで以上に簡単にモードとMCPを発見してインストールできます。
+- **新しいGemini 2.5 Pro、Flash、Flash Liteモデルのサポートを追加。**
+- **Excel ファイルサポートなど** - MCP サポートの向上、Mermaid制御の追加、Amazon Bedrock thinking サポート、その他多数!
---
@@ -184,35 +184,37 @@ Roo Codeの改善に貢献してくれたすべての貢献者に感謝します
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## ライセンス
diff --git a/locales/ko/README.md b/locales/ko/README.md
index f439588142..dce892ffb9 100644
--- a/locales/ko/README.md
+++ b/locales/ko/README.md
@@ -50,13 +50,13 @@
---
-## 🎉 Roo Code 3.20 출시
+## 🎉 Roo Code 3.21 출시
-Roo Code 3.20이 여러분의 피드백을 바탕으로 한 새로운 주요 기능과 개선사항을 제공합니다!
+Roo Code 3.21이 여러분의 피드백을 바탕으로 한 새로운 주요 기능과 개선사항을 제공합니다!
-- **실험적 마켓플레이스** - 새로운 마켓플레이스에서 모드와 MCP를 발견하고 설치하세요 (실험적 설정에서 활성화).
-- **향상된 파일 작업** - 다중 동시 파일 쓰기가 실험적 설정에서 사용 가능하며, 다중 동시 읽기는 실험적 단계를 졸업하여 컨텍스트 설정으로 이동했습니다.
-- **MCP 개선 등** - 향상된 MCP 지원, 더 많은 Mermaid 제어, Amazon Bedrock thinking 지원 등!
+- **마켓플레이스가 이제 라이브입니다! 마켓플레이스가 이제 라이브입니다!** 그 어느 때보다 쉽게 모드와 MCP를 발견하고 설치하세요.
+- **새로운 Gemini 2.5 Pro, Flash, Flash Lite 모델 지원을 추가했습니다.**
+- **Excel 파일 지원 등** - 향상된 MCP 지원, 더 많은 Mermaid 제어, Amazon Bedrock thinking 지원 등!
---
@@ -184,35 +184,37 @@ Roo Code를 더 좋게 만드는 데 도움을 준 모든 기여자에게 감사
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## 라이선스
diff --git a/locales/nl/README.md b/locales/nl/README.md
index a52efdb1eb..7ca8251e73 100644
--- a/locales/nl/README.md
+++ b/locales/nl/README.md
@@ -50,13 +50,13 @@ Bekijk de [CHANGELOG](../../CHANGELOG.md) voor gedetailleerde updates en fixes.
---
-## 🎉 Roo Code 3.20.0 Uitgebracht
+## 🎉 Roo Code 3.21 Uitgebracht
-Roo Code 3.20.0 brengt krachtige nieuwe functies en verbeteringen op basis van jullie feedback!
+Roo Code 3.21 brengt krachtige nieuwe functies en verbeteringen op basis van jullie feedback!
-- **Experimentele marktplaats voor modi en MCP's** - Ontdek en deel aangepaste modi en MCP-integraties met de community via onze nieuwe experimentele marktplaats.
-- **Verbeterde bestandsoperaties** - Meerdere gelijktijdige schrijfacties nu beschikbaar in experimentele instellingen, plus meerdere gelijktijdige leesacties gepromoveerd naar contextinstellingen voor betere prestaties.
-- **MCP-verbeteringen** - Verbeterde Mermaid-controls voor betere diagramvisualisatie en nieuwe Amazon Bedrock thinking-ondersteuning voor meer geavanceerde AI-interacties.
+- **De marketplace is nu live! De marketplace is nu live!** Ontdek en installeer modi en MCP's eenvoudiger dan ooit tevoren.
+- **Ondersteuning toegevoegd voor nieuwe Gemini 2.5 Pro, Flash en Flash Lite modellen.**
+- **Excel Bestandsondersteuning & Meer** - Verbeterde Mermaid-controls voor betere diagramvisualisatie en nieuwe Amazon Bedrock thinking-ondersteuning voor meer geavanceerde AI-interacties!
---
@@ -184,35 +184,37 @@ Dank aan alle bijdragers die Roo Code beter hebben gemaakt!
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licentie
diff --git a/locales/pl/README.md b/locales/pl/README.md
index b074b34675..351d755a29 100644
--- a/locales/pl/README.md
+++ b/locales/pl/README.md
@@ -50,13 +50,13 @@ Sprawdź [CHANGELOG](../../CHANGELOG.md), aby uzyskać szczegółowe informacje
---
-## 🎉 Roo Code 3.20.0 został wydany
+## 🎉 Roo Code 3.21 został wydany
-Roo Code 3.20.0 wprowadza potężne nowe funkcje i usprawnienia na podstawie opinii użytkowników!
+Roo Code 3.21 wprowadza potężne nowe funkcje i usprawnienia na podstawie opinii użytkowników!
-- **Eksperymentalne marketplace dla trybów i MCP** - Odkrywaj i dziel się niestandardowymi trybami oraz integracjami MCP ze społecznością poprzez nasze nowe eksperymentalne marketplace.
-- **Ulepszone operacje na plikach** - Wiele równoczesnych operacji zapisu dostępnych w ustawieniach eksperymentalnych, plus wiele równoczesnych operacji czytania zaawansowanych do ustawień kontekstu dla lepszej wydajności.
-- **Ulepszenia MCP** - Ulepszone kontrolki Mermaid dla lepszej wizualizacji diagramów oraz nowe wsparcie Amazon Bedrock thinking dla bardziej zaawansowanych interakcji z AI.
+- **Marketplace jest teraz na żywo! Marketplace jest teraz na żywo!** Odkrywaj i instaluj tryby oraz MCP łatwiej niż kiedykolwiek wcześniej.
+- **Dodano wsparcie dla nowych modeli Gemini 2.5 Pro, Flash i Flash Lite.**
+- **Wsparcie plików Excel i więcej** - Ulepszone kontrolki Mermaid dla lepszej wizualizacji diagramów oraz nowe wsparcie Amazon Bedrock thinking dla bardziej zaawansowanych interakcji z AI!
---
@@ -184,35 +184,37 @@ Dziękujemy wszystkim naszym współtwórcom, którzy pomogli ulepszyć Roo Code
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licencja
diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md
index ce887b6aa5..d773d8fcca 100644
--- a/locales/pt-BR/README.md
+++ b/locales/pt-BR/README.md
@@ -50,13 +50,13 @@ Confira o [CHANGELOG](../../CHANGELOG.md) para atualizações e correções deta
---
-## 🎉 Roo Code 3.20.0 foi lançado
+## 🎉 Roo Code 3.21 foi lançado
-O Roo Code 3.20.0 introduz novos recursos poderosos e melhorias baseadas no feedback dos usuários!
+O Roo Code 3.21 introduz novos recursos poderosos e melhorias baseadas no feedback dos usuários!
-- **Marketplace experimental para modos e MCP** - Descubra e compartilhe modos personalizados e integrações MCP com a comunidade através do nosso novo marketplace experimental.
-- **Operações de arquivo aprimoradas** - Múltiplas operações de escrita simultâneas disponíveis nas configurações experimentais, além de múltiplas operações de leitura simultâneas promovidas para configurações de contexto para melhor performance.
-- **Melhorias no MCP** - Controles Mermaid aprimorados para melhor visualização de diagramas e novo suporte Amazon Bedrock thinking para interações de IA mais avançadas.
+- **O marketplace está agora disponível! O marketplace está agora disponível!** Descubra e instale modos e MCPs mais facilmente do que nunca.
+- **Adicionado suporte para os novos modelos Gemini 2.5 Pro, Flash e Flash Lite.**
+- **Suporte a Arquivos Excel e Mais** - Controles Mermaid aprimorados para melhor visualização de diagramas e novo suporte Amazon Bedrock thinking para interações de IA mais avançadas!
---
@@ -184,35 +184,37 @@ Obrigado a todos os nossos contribuidores que ajudaram a tornar o Roo Code melho
|
mrubens |
saoudrizwan |
cte |
samhvw8 |
daniel-lxs |
hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|
KJ7LNW |
a8trejo |
ColemanRoo |
canrobins13 |
stea9499 |
joemanley201 |
-|
System233 |
nissa-seru |
jquanton |
NyxJae |
MuriloFP |
jr |
-|
d-oit |
punkpeye |
wkordalski |
elianiva |
sachasayan |
Smartsheet-JB-Brown |
-|
monotykamary |
cannuri |
zhangtony239 |
qdaxb |
feifei325 |
xyOz-dev |
-|
pugazhendhi-m |
shariqriazz |
lloydchang |
vigneshsubbiah16 |
dtrugman |
Szpadel |
-|
diarmidmackenzie |
psv2522 |
Premshay |
lupuletic |
kiwina |
aheizi |
-|
PeterDaveHello |
olweraltuve |
chrarnoldus |
ChuKhaLi |
nbihan-mediware |
RaySinner |
-|
afshawnlotfi |
pdecat |
noritaka1166 |
kyle-apex |
emshvac |
Lunchb0ne |
-|
SmartManoj |
vagadiya |
slytechnical |
arthurauffray |
upamune |
NamesMT |
-|
taylorwilsdon |
StevenTCramer |
sammcj |
Ruakij |
p12tic |
gtaylor |
-|
hassoncs |
aitoroses |
anton-otee |
SannidhyaSah |
heyseth |
taisukeoe |
-|
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
teddyOOXX |
-|
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
yt3trees |
-|
benzntech |
axkirillov |
bramburn |
olearycrew |
snoyiatk |
GitlyHallows |
-|
jcbdev |
mr-ryan-james |
ross |
philfung |
napter |
Chenjiayuan195 |
-|
julionav |
SplittyDev |
mdp |
kohii |
kinandan |
jwcraig |
-|
shoopapa |
im47cn |
hongzio |
hatsu38 |
GOODBOY008 |
forestyoo |
-|
dqroid |
dairui1 |
tmsjngx0 |
bannzai |
axmo |
asychin |
-|
amittell |
vladstudio |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
nevermorec |
-|
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
shohei-ihaya |
-|
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
qingyuan1109 |
-|
pokutuna |
philipnext |
oprstchn |
nobu007 |
mosleyit |
moqimoqidea |
-|
mlopezr |
mecab |
olup |
lightrabbit |
linegel |
edwin-truthsearch-io |
-|
EamonNerbonne |
dbasclpy |
dflatline |
Deon588 |
dleen |
devxpain |
-|
chadgauth |
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
-|
QuinsZouls |
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
-|
adamhill |
AMHesch |
tgfjt |
maekawataiki |
samsilveira |
01Rian |
-|
RSO |
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
-|
mollux |
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
-|
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
celestial-vault |
+|
System233 |
jquanton |
nissa-seru |
NyxJae |
jr |
MuriloFP |
+|
elianiva |
d-oit |
punkpeye |
wkordalski |
sachasayan |
Smartsheet-JB-Brown |
+|
monotykamary |
cannuri |
xyOz-dev |
feifei325 |
zhangtony239 |
qdaxb |
+|
shariqriazz |
pugazhendhi-m |
vigneshsubbiah16 |
lloydchang |
dtrugman |
Szpadel |
+|
chrarnoldus |
diarmidmackenzie |
olweraltuve |
psv2522 |
Premshay |
lupuletic |
+|
kiwina |
aheizi |
PeterDaveHello |
afshawnlotfi |
RaySinner |
nbihan-mediware |
+|
ChuKhaLi |
hassoncs |
emshvac |
kyle-apex |
noritaka1166 |
pdecat |
+|
SannidhyaSah |
StevenTCramer |
Lunchb0ne |
SmartManoj |
vagadiya |
slytechnical |
+|
dleffel |
arthurauffray |
upamune |
NamesMT |
taylorwilsdon |
sammcj |
+|
Ruakij |
p12tic |
gtaylor |
aitoroses |
mr-ryan-james |
heyseth |
+|
taisukeoe |
avtc |
dlab-anton |
eonghk |
kcwhite |
ronyblum |
+|
teddyOOXX |
vincentsong |
yongjer |
zeozeozeo |
ashktn |
franekp |
+|
yt3trees |
benzntech |
axkirillov |
anton-otee |
bramburn |
olearycrew |
+|
snoyiatk |
GitlyHallows |
jcbdev |
Chenjiayuan195 |
julionav |
SplittyDev |
+|
mdp |
napter |
ross |
philfung |
dairui1 |
dqroid |
+|
forestyoo |
GOODBOY008 |
hatsu38 |
hongzio |
im47cn |
shoopapa |
+|
jwcraig |
kinandan |
nevermorec |
bannzai |
axmo |
asychin |
+|
amittell |
Yoshino-Yukitaro |
Yikai-Liao |
zxdvd |
vladstudio |
tmsjngx0 |
+|
tgfjt |
PretzelVector |
zetaloop |
cdlliuy |
user202729 |
student20880 |
+|
shohei-ihaya |
shaybc |
seedlord |
samir-nimbly |
robertheadley |
refactorthis |
+|
qingyuan1109 |
pokutuna |
philipnext |
village-way |
oprstchn |
nobu007 |
+|
mosleyit |
moqimoqidea |
mlopezr |
mecab |
olup |
lightrabbit |
+|
kohii |
linegel |
edwin-truthsearch-io |
EamonNerbonne |
dbasclpy |
dflatline |
+|
Deon588 |
dleen |
devxpain |
chadgauth |
brunobergher |
thecolorblue |
+|
bogdan0083 |
Atlogit |
atlasgong |
andreastempsch |
alasano |
QuinsZouls |
+|
HadesArchitect |
alarno |
nexon33 |
adilhafeez |
adamwlarson |
adamhill |
+|
AMHesch |
maekawataiki |
AlexandruSmirnov |
samsilveira |
01Rian |
RSO |
+|
SECKainersdorfer |
R-omk |
Sarke |
kvokka |
ecmasx |
mollux |
+|
marvijo-code |
mamertofabian |
monkeyDluffy6017 |
libertyteeth |
shtse8 |
Rexarrior |
+|
KanTakahiro |
ksze |
Jdo300 |
hesara |
DeXtroTip |
pfitz |
+|
celestial-vault | | | | | |
## Licença
diff --git a/locales/ru/README.md b/locales/ru/README.md
index 1c62495472..368a70a986 100644
--- a/locales/ru/README.md
+++ b/locales/ru/README.md
@@ -50,13 +50,13 @@
---
-## 🎉 Выпущен Roo Code 3.20
+## 🎉 Выпущен Roo Code 3.21
-Roo Code 3.20 представляет экспериментальный маркетплейс и улучшения файловых операций!
+Roo Code 3.21 представляет экспериментальный маркетплейс и улучшения файловых операций!
-- **Экспериментальный маркетплейс для режимов и MCP** - Откройте для себя и установите пользовательские режимы и MCP серверы из нашего экспериментального маркетплейса в настройках.
-- **Улучшенные файловые операции** - Множественная одновременная запись файлов теперь доступна в экспериментальных настройках, а множественное одновременное чтение перешло в настройки контекста.
-- **Улучшения MCP** - Новые элементы управления Mermaid и поддержка мышления Amazon Bedrock для расширенных возможностей MCP.
+- **Маркетплейс теперь доступен! Маркетплейс теперь доступен!** Открывайте и устанавливайте режимы и MCP проще, чем когда-либо.
+- **Добавлена поддержка новых моделей Gemini 2.5 Pro, Flash и Flash Lite.**
+- **Поддержка файлов Excel и многое другое!** - Новые элементы управления Mermaid и поддержка мышления Amazon Bedrock для расширенных возможностей MCP.
---
@@ -184,35 +184,37 @@ code --install-extension bin/roo-cline-
.vsix
|mrubens |saoudrizwan |cte |samhvw8 |daniel-lxs |hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|KJ7LNW |a8trejo |ColemanRoo |canrobins13 |stea9499 |joemanley201 |
-|System233 |nissa-seru |jquanton |NyxJae |MuriloFP |jr |
-|d-oit |punkpeye |wkordalski |elianiva |sachasayan |Smartsheet-JB-Brown |
-|monotykamary |cannuri |zhangtony239 |qdaxb |feifei325 |xyOz-dev |
-|pugazhendhi-m |shariqriazz |lloydchang |vigneshsubbiah16 |dtrugman |Szpadel |
-|diarmidmackenzie |psv2522 |Premshay |lupuletic |kiwina |aheizi |
-|PeterDaveHello |olweraltuve |chrarnoldus |ChuKhaLi |nbihan-mediware |RaySinner |
-|afshawnlotfi |pdecat |noritaka1166 |kyle-apex |emshvac |Lunchb0ne |
-|SmartManoj |vagadiya |slytechnical |arthurauffray |upamune |NamesMT |
-|taylorwilsdon |StevenTCramer |sammcj |Ruakij |p12tic |gtaylor |
-|hassoncs |aitoroses |anton-otee |SannidhyaSah |heyseth |taisukeoe |
-|avtc |dlab-anton |eonghk |kcwhite |ronyblum |teddyOOXX |
-|vincentsong |yongjer |zeozeozeo |ashktn |franekp |yt3trees |
-|benzntech |axkirillov |bramburn |olearycrew |snoyiatk |GitlyHallows |
-|jcbdev |mr-ryan-james |ross |philfung |napter |Chenjiayuan195 |
-|julionav |SplittyDev |mdp |kohii |kinandan |jwcraig |
-|shoopapa |im47cn |hongzio |hatsu38 |GOODBOY008 |forestyoo |
-|dqroid |dairui1 |tmsjngx0 |bannzai |axmo |asychin |
-|amittell |vladstudio |Yoshino-Yukitaro |Yikai-Liao |zxdvd |nevermorec |
-|PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |shohei-ihaya |
-|shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |qingyuan1109 |
-|pokutuna |philipnext |oprstchn |nobu007 |mosleyit |moqimoqidea |
-|mlopezr |mecab |olup |lightrabbit |linegel |edwin-truthsearch-io |
-|EamonNerbonne |dbasclpy |dflatline |Deon588 |dleen |devxpain |
-|chadgauth |bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |
-|QuinsZouls |HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |
-|adamhill |AMHesch |tgfjt |maekawataiki |samsilveira |01Rian |
-|RSO |SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |
-|mollux |marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |
-|ksze |Jdo300 |hesara |DeXtroTip |pfitz |celestial-vault |
+|System233 |jquanton |nissa-seru |NyxJae |jr |MuriloFP |
+|elianiva |d-oit |punkpeye |wkordalski |sachasayan |Smartsheet-JB-Brown |
+|monotykamary |cannuri |xyOz-dev |feifei325 |zhangtony239 |qdaxb |
+|shariqriazz |pugazhendhi-m |vigneshsubbiah16 |lloydchang |dtrugman |Szpadel |
+|chrarnoldus |diarmidmackenzie |olweraltuve |psv2522 |Premshay |lupuletic |
+|kiwina |aheizi |PeterDaveHello |afshawnlotfi |RaySinner |nbihan-mediware |
+|ChuKhaLi |hassoncs |emshvac |kyle-apex |noritaka1166 |pdecat |
+|SannidhyaSah |StevenTCramer |Lunchb0ne |SmartManoj |vagadiya |slytechnical |
+|dleffel |arthurauffray |upamune |NamesMT |taylorwilsdon |sammcj |
+|Ruakij |p12tic |gtaylor |aitoroses |mr-ryan-james |heyseth |
+|taisukeoe |avtc |dlab-anton |eonghk |kcwhite |ronyblum |
+|teddyOOXX |vincentsong |yongjer |zeozeozeo |ashktn |franekp |
+|yt3trees |benzntech |axkirillov |anton-otee |bramburn |olearycrew |
+|snoyiatk |GitlyHallows |jcbdev |Chenjiayuan195 |julionav |SplittyDev |
+|mdp |napter |ross |philfung |dairui1 |dqroid |
+|forestyoo |GOODBOY008 |hatsu38 |hongzio |im47cn |shoopapa |
+|jwcraig |kinandan |nevermorec |bannzai |axmo |asychin |
+|amittell |Yoshino-Yukitaro |Yikai-Liao |zxdvd |vladstudio |tmsjngx0 |
+|tgfjt |PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |
+|shohei-ihaya |shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |
+|qingyuan1109 |pokutuna |philipnext |village-way |oprstchn |nobu007 |
+|mosleyit |moqimoqidea |mlopezr |mecab |olup |lightrabbit |
+|kohii |linegel |edwin-truthsearch-io |EamonNerbonne |dbasclpy |dflatline |
+|Deon588 |dleen |devxpain |chadgauth |brunobergher |thecolorblue |
+|bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |QuinsZouls |
+|HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |adamhill |
+|AMHesch |maekawataiki |AlexandruSmirnov |samsilveira |01Rian |RSO |
+|SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |mollux |
+|marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |Rexarrior |
+|KanTakahiro |ksze |Jdo300 |hesara |DeXtroTip |pfitz |
+|celestial-vault | | | | | |
## Лицензия
diff --git a/locales/tr/README.md b/locales/tr/README.md
index b528fa31d8..6a039e79b1 100644
--- a/locales/tr/README.md
+++ b/locales/tr/README.md
@@ -50,13 +50,13 @@ Detaylı güncellemeler ve düzeltmeler için [CHANGELOG](../../CHANGELOG.md) do
---
-## 🎉 Roo Code 3.20 Yayınlandı
+## 🎉 Roo Code 3.21 Yayınlandı
-Roo Code 3.20 deneysel pazar yeri ve gelişmiş dosya işlemleri sunuyor!
+Roo Code 3.21 deneysel pazar yeri ve gelişmiş dosya işlemleri sunuyor!
-- **Modlar ve MCP için deneysel pazar yeri** - Ayarlarda deneysel pazar yerimizden özel modları ve MCP sunucularını keşfedin ve kurun.
-- **Gelişmiş dosya işlemleri** - Çoklu eşzamanlı dosya yazma artık deneysel ayarlarda mevcut, çoklu eşzamanlı okuma ise bağlam ayarlarına taşındı.
-- **MCP iyileştirmeleri** - Gelişmiş MCP yetenekleri için yeni Mermaid kontrolleri ve Amazon Bedrock düşünce desteği.
+- **Pazar yeri artık canlı! Pazar yeri artık canlı!** Modları ve MCP'leri her zamankinden daha kolay keşfedin ve kurun.
+- **Yeni Gemini 2.5 Pro, Flash ve Flash Lite modelleri için destek eklendi.**
+- **Excel Dosya Desteği ve Daha Fazlası!** - Gelişmiş MCP yetenekleri için yeni Mermaid kontrolleri ve Amazon Bedrock düşünce desteği.
---
@@ -184,35 +184,37 @@ Roo Code'u daha iyi hale getirmeye yardımcı olan tüm katkıda bulunanlara te
|mrubens |saoudrizwan |cte |samhvw8 |daniel-lxs |hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|KJ7LNW |a8trejo |ColemanRoo |canrobins13 |stea9499 |joemanley201 |
-|System233 |nissa-seru |jquanton |NyxJae |MuriloFP |jr |
-|d-oit |punkpeye |wkordalski |elianiva |sachasayan |Smartsheet-JB-Brown |
-|monotykamary |cannuri |zhangtony239 |qdaxb |feifei325 |xyOz-dev |
-|pugazhendhi-m |shariqriazz |lloydchang |vigneshsubbiah16 |dtrugman |Szpadel |
-|diarmidmackenzie |psv2522 |Premshay |lupuletic |kiwina |aheizi |
-|PeterDaveHello |olweraltuve |chrarnoldus |ChuKhaLi |nbihan-mediware |RaySinner |
-|afshawnlotfi |pdecat |noritaka1166 |kyle-apex |emshvac |Lunchb0ne |
-|SmartManoj |vagadiya |slytechnical |arthurauffray |upamune |NamesMT |
-|taylorwilsdon |StevenTCramer |sammcj |Ruakij |p12tic |gtaylor |
-|hassoncs |aitoroses |anton-otee |SannidhyaSah |heyseth |taisukeoe |
-|avtc |dlab-anton |eonghk |kcwhite |ronyblum |teddyOOXX |
-|vincentsong |yongjer |zeozeozeo |ashktn |franekp |yt3trees |
-|benzntech |axkirillov |bramburn |olearycrew |snoyiatk |GitlyHallows |
-|jcbdev |mr-ryan-james |ross |philfung |napter |Chenjiayuan195 |
-|julionav |SplittyDev |mdp |kohii |kinandan |jwcraig |
-|shoopapa |im47cn |hongzio |hatsu38 |GOODBOY008 |forestyoo |
-|dqroid |dairui1 |tmsjngx0 |bannzai |axmo |asychin |
-|amittell |vladstudio |Yoshino-Yukitaro |Yikai-Liao |zxdvd |nevermorec |
-|PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |shohei-ihaya |
-|shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |qingyuan1109 |
-|pokutuna |philipnext |oprstchn |nobu007 |mosleyit |moqimoqidea |
-|mlopezr |mecab |olup |lightrabbit |linegel |edwin-truthsearch-io |
-|EamonNerbonne |dbasclpy |dflatline |Deon588 |dleen |devxpain |
-|chadgauth |bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |
-|QuinsZouls |HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |
-|adamhill |AMHesch |tgfjt |maekawataiki |samsilveira |01Rian |
-|RSO |SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |
-|mollux |marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |
-|ksze |Jdo300 |hesara |DeXtroTip |pfitz |celestial-vault |
+|System233 |jquanton |nissa-seru |NyxJae |jr |MuriloFP |
+|elianiva |d-oit |punkpeye |wkordalski |sachasayan |Smartsheet-JB-Brown |
+|monotykamary |cannuri |xyOz-dev |feifei325 |zhangtony239 |qdaxb |
+|shariqriazz |pugazhendhi-m |vigneshsubbiah16 |lloydchang |dtrugman |Szpadel |
+|chrarnoldus |diarmidmackenzie |olweraltuve |psv2522 |Premshay |lupuletic |
+|kiwina |aheizi |PeterDaveHello |afshawnlotfi |RaySinner |nbihan-mediware |
+|ChuKhaLi |hassoncs |emshvac |kyle-apex |noritaka1166 |pdecat |
+|SannidhyaSah |StevenTCramer |Lunchb0ne |SmartManoj |vagadiya |slytechnical |
+|dleffel |arthurauffray |upamune |NamesMT |taylorwilsdon |sammcj |
+|Ruakij |p12tic |gtaylor |aitoroses |mr-ryan-james |heyseth |
+|taisukeoe |avtc |dlab-anton |eonghk |kcwhite |ronyblum |
+|teddyOOXX |vincentsong |yongjer |zeozeozeo |ashktn |franekp |
+|yt3trees |benzntech |axkirillov |anton-otee |bramburn |olearycrew |
+|snoyiatk |GitlyHallows |jcbdev |Chenjiayuan195 |julionav |SplittyDev |
+|mdp |napter |ross |philfung |dairui1 |dqroid |
+|forestyoo |GOODBOY008 |hatsu38 |hongzio |im47cn |shoopapa |
+|jwcraig |kinandan |nevermorec |bannzai |axmo |asychin |
+|amittell |Yoshino-Yukitaro |Yikai-Liao |zxdvd |vladstudio |tmsjngx0 |
+|tgfjt |PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |
+|shohei-ihaya |shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |
+|qingyuan1109 |pokutuna |philipnext |village-way |oprstchn |nobu007 |
+|mosleyit |moqimoqidea |mlopezr |mecab |olup |lightrabbit |
+|kohii |linegel |edwin-truthsearch-io |EamonNerbonne |dbasclpy |dflatline |
+|Deon588 |dleen |devxpain |chadgauth |brunobergher |thecolorblue |
+|bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |QuinsZouls |
+|HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |adamhill |
+|AMHesch |maekawataiki |AlexandruSmirnov |samsilveira |01Rian |RSO |
+|SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |mollux |
+|marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |Rexarrior |
+|KanTakahiro |ksze |Jdo300 |hesara |DeXtroTip |pfitz |
+|celestial-vault | | | | | |
## Lisans
diff --git a/locales/vi/README.md b/locales/vi/README.md
index b8e85d4250..2e59bb759f 100644
--- a/locales/vi/README.md
+++ b/locales/vi/README.md
@@ -50,13 +50,13 @@ Kiểm tra [CHANGELOG](../../CHANGELOG.md) để biết thông tin chi tiết v
---
-## 🎉 Đã Phát Hành Roo Code 3.20
+## 🎉 Đã Phát Hành Roo Code 3.21
-Roo Code 3.20 giới thiệu marketplace thử nghiệm và cải tiến các thao tác tập tin!
+Roo Code 3.21 giới thiệu marketplace thử nghiệm và cải tiến các thao tác tập tin!
-- **Marketplace thử nghiệm cho các chế độ và MCP** - Khám phá và cài đặt các chế độ tùy chỉnh và máy chủ MCP từ marketplace thử nghiệm của chúng tôi trong cài đặt.
-- **Cải tiến các thao tác tập tin** - Ghi đồng thời nhiều tập tin hiện có sẵn trong cài đặt thử nghiệm, và đọc đồng thời nhiều tập tin đã được chuyển sang cài đặt ngữ cảnh.
-- **Cải tiến MCP** - Các điều khiển Mermaid mới và hỗ trợ suy nghĩ Amazon Bedrock cho khả năng MCP nâng cao.
+- **Marketplace hiện đã hoạt động! Marketplace hiện đã hoạt động!** Khám phá và cài đặt các chế độ và MCP dễ dàng hơn bao giờ hết.
+- **Đã thêm hỗ trợ cho các mô hình Gemini 2.5 Pro, Flash và Flash Lite mới.**
+- **Hỗ trợ tập tin Excel và nhiều hơn nữa!** - Các điều khiển Mermaid mới và hỗ trợ suy nghĩ Amazon Bedrock cho khả năng MCP nâng cao.
---
@@ -184,35 +184,37 @@ Cảm ơn tất cả những người đóng góp đã giúp cải thiện Roo C
|mrubens |saoudrizwan |cte |samhvw8 |daniel-lxs |hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|KJ7LNW |a8trejo |ColemanRoo |canrobins13 |stea9499 |joemanley201 |
-|System233 |nissa-seru |jquanton |NyxJae |MuriloFP |jr |
-|d-oit |punkpeye |wkordalski |elianiva |sachasayan |Smartsheet-JB-Brown |
-|monotykamary |cannuri |zhangtony239 |qdaxb |feifei325 |xyOz-dev |
-|pugazhendhi-m |shariqriazz |lloydchang |vigneshsubbiah16 |dtrugman |Szpadel |
-|diarmidmackenzie |psv2522 |Premshay |lupuletic |kiwina |aheizi |
-|PeterDaveHello |olweraltuve |chrarnoldus |ChuKhaLi |nbihan-mediware |RaySinner |
-|afshawnlotfi |pdecat |noritaka1166 |kyle-apex |emshvac |Lunchb0ne |
-|SmartManoj |vagadiya |slytechnical |arthurauffray |upamune |NamesMT |
-|taylorwilsdon |StevenTCramer |sammcj |Ruakij |p12tic |gtaylor |
-|hassoncs |aitoroses |anton-otee |SannidhyaSah |heyseth |taisukeoe |
-|avtc |dlab-anton |eonghk |kcwhite |ronyblum |teddyOOXX |
-|vincentsong |yongjer |zeozeozeo |ashktn |franekp |yt3trees |
-|benzntech |axkirillov |bramburn |olearycrew |snoyiatk |GitlyHallows |
-|jcbdev |mr-ryan-james |ross |philfung |napter |Chenjiayuan195 |
-|julionav |SplittyDev |mdp |kohii |kinandan |jwcraig |
-|shoopapa |im47cn |hongzio |hatsu38 |GOODBOY008 |forestyoo |
-|dqroid |dairui1 |tmsjngx0 |bannzai |axmo |asychin |
-|amittell |vladstudio |Yoshino-Yukitaro |Yikai-Liao |zxdvd |nevermorec |
-|PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |shohei-ihaya |
-|shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |qingyuan1109 |
-|pokutuna |philipnext |oprstchn |nobu007 |mosleyit |moqimoqidea |
-|mlopezr |mecab |olup |lightrabbit |linegel |edwin-truthsearch-io |
-|EamonNerbonne |dbasclpy |dflatline |Deon588 |dleen |devxpain |
-|chadgauth |bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |
-|QuinsZouls |HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |
-|adamhill |AMHesch |tgfjt |maekawataiki |samsilveira |01Rian |
-|RSO |SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |
-|mollux |marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |
-|ksze |Jdo300 |hesara |DeXtroTip |pfitz |celestial-vault |
+|System233 |jquanton |nissa-seru |NyxJae |jr |MuriloFP |
+|elianiva |d-oit |punkpeye |wkordalski |sachasayan |Smartsheet-JB-Brown |
+|monotykamary |cannuri |xyOz-dev |feifei325 |zhangtony239 |qdaxb |
+|shariqriazz |pugazhendhi-m |vigneshsubbiah16 |lloydchang |dtrugman |Szpadel |
+|chrarnoldus |diarmidmackenzie |olweraltuve |psv2522 |Premshay |lupuletic |
+|kiwina |aheizi |PeterDaveHello |afshawnlotfi |RaySinner |nbihan-mediware |
+|ChuKhaLi |hassoncs |emshvac |kyle-apex |noritaka1166 |pdecat |
+|SannidhyaSah |StevenTCramer |Lunchb0ne |SmartManoj |vagadiya |slytechnical |
+|dleffel |arthurauffray |upamune |NamesMT |taylorwilsdon |sammcj |
+|Ruakij |p12tic |gtaylor |aitoroses |mr-ryan-james |heyseth |
+|taisukeoe |avtc |dlab-anton |eonghk |kcwhite |ronyblum |
+|teddyOOXX |vincentsong |yongjer |zeozeozeo |ashktn |franekp |
+|yt3trees |benzntech |axkirillov |anton-otee |bramburn |olearycrew |
+|snoyiatk |GitlyHallows |jcbdev |Chenjiayuan195 |julionav |SplittyDev |
+|mdp |napter |ross |philfung |dairui1 |dqroid |
+|forestyoo |GOODBOY008 |hatsu38 |hongzio |im47cn |shoopapa |
+|jwcraig |kinandan |nevermorec |bannzai |axmo |asychin |
+|amittell |Yoshino-Yukitaro |Yikai-Liao |zxdvd |vladstudio |tmsjngx0 |
+|tgfjt |PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |
+|shohei-ihaya |shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |
+|qingyuan1109 |pokutuna |philipnext |village-way |oprstchn |nobu007 |
+|mosleyit |moqimoqidea |mlopezr |mecab |olup |lightrabbit |
+|kohii |linegel |edwin-truthsearch-io |EamonNerbonne |dbasclpy |dflatline |
+|Deon588 |dleen |devxpain |chadgauth |brunobergher |thecolorblue |
+|bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |QuinsZouls |
+|HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |adamhill |
+|AMHesch |maekawataiki |AlexandruSmirnov |samsilveira |01Rian |RSO |
+|SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |mollux |
+|marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |Rexarrior |
+|KanTakahiro |ksze |Jdo300 |hesara |DeXtroTip |pfitz |
+|celestial-vault | | | | | |
## Giấy Phép
diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md
index 0d726f2fe2..dc8b338941 100644
--- a/locales/zh-CN/README.md
+++ b/locales/zh-CN/README.md
@@ -50,13 +50,13 @@
---
-## 🎉 Roo Code 3.20 已发布
+## 🎉 Roo Code 3.21 已发布
-Roo Code 3.20 根据您的反馈带来重要的新功能和改进!
+Roo Code 3.21 根据您的反馈带来重要的新功能和改进!
-- **实验性市场** - 从新市场发现和安装模式和 MCP(在实验性设置中启用)。
-- **增强的文件操作** - 多个并发文件写入现在在实验性设置中可用,多个并发读取已从实验性功能毕业,现在位于上下文设置中。
-- **MCP 改进与更多功能** - 增强的 MCP 支持、更多 Mermaid 控件、Amazon Bedrock 中的思考支持,以及更多功能!
+- **市场现已上线!市场现已上线!** 从新市场发现和安装模式和 MCP 比以往更容易(在实验性设置中启用)。
+- **新增 Gemini 2.5 Pro、Flash 和 Flash Lite 模型支持。** 多个并发文件写入现在在实验性设置中可用,多个并发读取已从实验性功能毕业,现在位于上下文设置中。
+- **Excel 文件支持及更多功能!** - 增强的 MCP 支持、更多 Mermaid 控件、Amazon Bedrock 中的思考支持,以及更多功能!
---
@@ -184,35 +184,37 @@ code --install-extension bin/roo-cline-.vsix
|mrubens |saoudrizwan |cte |samhvw8 |daniel-lxs |hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|KJ7LNW |a8trejo |ColemanRoo |canrobins13 |stea9499 |joemanley201 |
-|System233 |nissa-seru |jquanton |NyxJae |MuriloFP |jr |
-|d-oit |punkpeye |wkordalski |elianiva |sachasayan |Smartsheet-JB-Brown |
-|monotykamary |cannuri |zhangtony239 |qdaxb |feifei325 |xyOz-dev |
-|pugazhendhi-m |shariqriazz |lloydchang |vigneshsubbiah16 |dtrugman |Szpadel |
-|diarmidmackenzie |psv2522 |Premshay |lupuletic |kiwina |aheizi |
-|PeterDaveHello |olweraltuve |chrarnoldus |ChuKhaLi |nbihan-mediware |RaySinner |
-|afshawnlotfi |pdecat |noritaka1166 |kyle-apex |emshvac |Lunchb0ne |
-|SmartManoj |vagadiya |slytechnical |arthurauffray |upamune |NamesMT |
-|taylorwilsdon |StevenTCramer |sammcj |Ruakij |p12tic |gtaylor |
-|hassoncs |aitoroses |anton-otee |SannidhyaSah |heyseth |taisukeoe |
-|avtc |dlab-anton |eonghk |kcwhite |ronyblum |teddyOOXX |
-|vincentsong |yongjer |zeozeozeo |ashktn |franekp |yt3trees |
-|benzntech |axkirillov |bramburn |olearycrew |snoyiatk |GitlyHallows |
-|jcbdev |mr-ryan-james |ross |philfung |napter |Chenjiayuan195 |
-|julionav |SplittyDev |mdp |kohii |kinandan |jwcraig |
-|shoopapa |im47cn |hongzio |hatsu38 |GOODBOY008 |forestyoo |
-|dqroid |dairui1 |tmsjngx0 |bannzai |axmo |asychin |
-|amittell |vladstudio |Yoshino-Yukitaro |Yikai-Liao |zxdvd |nevermorec |
-|PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |shohei-ihaya |
-|shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |qingyuan1109 |
-|pokutuna |philipnext |oprstchn |nobu007 |mosleyit |moqimoqidea |
-|mlopezr |mecab |olup |lightrabbit |linegel |edwin-truthsearch-io |
-|EamonNerbonne |dbasclpy |dflatline |Deon588 |dleen |devxpain |
-|chadgauth |bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |
-|QuinsZouls |HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |
-|adamhill |AMHesch |tgfjt |maekawataiki |samsilveira |01Rian |
-|RSO |SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |
-|mollux |marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |
-|ksze |Jdo300 |hesara |DeXtroTip |pfitz |celestial-vault |
+|System233 |jquanton |nissa-seru |NyxJae |jr |MuriloFP |
+|elianiva |d-oit |punkpeye |wkordalski |sachasayan |Smartsheet-JB-Brown |
+|monotykamary |cannuri |xyOz-dev |feifei325 |zhangtony239 |qdaxb |
+|shariqriazz |pugazhendhi-m |vigneshsubbiah16 |lloydchang |dtrugman |Szpadel |
+|chrarnoldus |diarmidmackenzie |olweraltuve |psv2522 |Premshay |lupuletic |
+|kiwina |aheizi |PeterDaveHello |afshawnlotfi |RaySinner |nbihan-mediware |
+|ChuKhaLi |hassoncs |emshvac |kyle-apex |noritaka1166 |pdecat |
+|SannidhyaSah |StevenTCramer |Lunchb0ne |SmartManoj |vagadiya |slytechnical |
+|dleffel |arthurauffray |upamune |NamesMT |taylorwilsdon |sammcj |
+|Ruakij |p12tic |gtaylor |aitoroses |mr-ryan-james |heyseth |
+|taisukeoe |avtc |dlab-anton |eonghk |kcwhite |ronyblum |
+|teddyOOXX |vincentsong |yongjer |zeozeozeo |ashktn |franekp |
+|yt3trees |benzntech |axkirillov |anton-otee |bramburn |olearycrew |
+|snoyiatk |GitlyHallows |jcbdev |Chenjiayuan195 |julionav |SplittyDev |
+|mdp |napter |ross |philfung |dairui1 |dqroid |
+|forestyoo |GOODBOY008 |hatsu38 |hongzio |im47cn |shoopapa |
+|jwcraig |kinandan |nevermorec |bannzai |axmo |asychin |
+|amittell |Yoshino-Yukitaro |Yikai-Liao |zxdvd |vladstudio |tmsjngx0 |
+|tgfjt |PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |
+|shohei-ihaya |shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |
+|qingyuan1109 |pokutuna |philipnext |village-way |oprstchn |nobu007 |
+|mosleyit |moqimoqidea |mlopezr |mecab |olup |lightrabbit |
+|kohii |linegel |edwin-truthsearch-io |EamonNerbonne |dbasclpy |dflatline |
+|Deon588 |dleen |devxpain |chadgauth |brunobergher |thecolorblue |
+|bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |QuinsZouls |
+|HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |adamhill |
+|AMHesch |maekawataiki |AlexandruSmirnov |samsilveira |01Rian |RSO |
+|SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |mollux |
+|marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |Rexarrior |
+|KanTakahiro |ksze |Jdo300 |hesara |DeXtroTip |pfitz |
+|celestial-vault | | | | | |
## 许可证
diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md
index 30987c4fe8..85dfce876b 100644
--- a/locales/zh-TW/README.md
+++ b/locales/zh-TW/README.md
@@ -51,13 +51,13 @@
---
-## 🎉 Roo Code 3.20 已發布
+## 🎉 Roo Code 3.21 已發布
-Roo Code 3.20 推出實驗性市集和檔案操作改進!
+Roo Code 3.21 推出實驗性市集和檔案操作改進!
-- **模式和 MCP 的實驗性市集** - 在設定中從我們的實驗性市集探索並安裝自訂模式和 MCP 伺服器。
-- **改進的檔案操作** - 多重同時檔案寫入現在可在實驗性設定中使用,多重同時讀取已移至上下文設定。
-- **MCP 改進** - 新的 Mermaid 控制項和 Amazon Bedrock 思考支援,提供增強的 MCP 功能。
+- **市集現已上線!市集現已上線!** 從新市集探索並安裝模式和 MCP 比以往更容易(在實驗性設定中啟用)。
+- **新增 Gemini 2.5 Pro、Flash 和 Flash Lite 模型支援。** 多重同時檔案寫入現在可在實驗性設定中使用,多重同時讀取已移至上下文設定。
+- **Excel 檔案支援及更多功能!** - 新的 Mermaid 控制項和 Amazon Bedrock 思考支援,提供增強的 MCP 功能。
---
@@ -185,35 +185,37 @@ code --install-extension bin/roo-cline-.vsix
|mrubens |saoudrizwan |cte |samhvw8 |daniel-lxs |hannesrudolph |
|:---:|:---:|:---:|:---:|:---:|:---:|
|KJ7LNW |a8trejo |ColemanRoo |canrobins13 |stea9499 |joemanley201 |
-|System233 |nissa-seru |jquanton |NyxJae |MuriloFP |jr |
-|d-oit |punkpeye |wkordalski |elianiva |sachasayan |Smartsheet-JB-Brown |
-|monotykamary |cannuri |zhangtony239 |qdaxb |feifei325 |xyOz-dev |
-|pugazhendhi-m |shariqriazz |lloydchang |vigneshsubbiah16 |dtrugman |Szpadel |
-|diarmidmackenzie |psv2522 |Premshay |lupuletic |kiwina |aheizi |
-|PeterDaveHello |olweraltuve |chrarnoldus |ChuKhaLi |nbihan-mediware |RaySinner |
-|afshawnlotfi |pdecat |noritaka1166 |kyle-apex |emshvac |Lunchb0ne |
-|SmartManoj |vagadiya |slytechnical |arthurauffray |upamune |NamesMT |
-|taylorwilsdon |StevenTCramer |sammcj |Ruakij |p12tic |gtaylor |
-|hassoncs |aitoroses |anton-otee |SannidhyaSah |heyseth |taisukeoe |
-|avtc |dlab-anton |eonghk |kcwhite |ronyblum |teddyOOXX |
-|vincentsong |yongjer |zeozeozeo |ashktn |franekp |yt3trees |
-|benzntech |axkirillov |bramburn |olearycrew |snoyiatk |GitlyHallows |
-|jcbdev |mr-ryan-james |ross |philfung |napter |Chenjiayuan195 |
-|julionav |SplittyDev |mdp |kohii |kinandan |jwcraig |
-|shoopapa |im47cn |hongzio |hatsu38 |GOODBOY008 |forestyoo |
-|dqroid |dairui1 |tmsjngx0 |bannzai |axmo |asychin |
-|amittell |vladstudio |Yoshino-Yukitaro |Yikai-Liao |zxdvd |nevermorec |
-|PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |shohei-ihaya |
-|shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |qingyuan1109 |
-|pokutuna |philipnext |oprstchn |nobu007 |mosleyit |moqimoqidea |
-|mlopezr |mecab |olup |lightrabbit |linegel |edwin-truthsearch-io |
-|EamonNerbonne |dbasclpy |dflatline |Deon588 |dleen |devxpain |
-|chadgauth |bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |
-|QuinsZouls |HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |
-|adamhill |AMHesch |tgfjt |maekawataiki |samsilveira |01Rian |
-|RSO |SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |
-|mollux |marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |
-|ksze |Jdo300 |hesara |DeXtroTip |pfitz |celestial-vault |
+|System233 |jquanton |nissa-seru |NyxJae |jr |MuriloFP |
+|elianiva |d-oit |punkpeye |wkordalski |sachasayan |Smartsheet-JB-Brown |
+|monotykamary |cannuri |xyOz-dev |feifei325 |zhangtony239 |qdaxb |
+|shariqriazz |pugazhendhi-m |vigneshsubbiah16 |lloydchang |dtrugman |Szpadel |
+|chrarnoldus |diarmidmackenzie |olweraltuve |psv2522 |Premshay |lupuletic |
+|kiwina |aheizi |PeterDaveHello |afshawnlotfi |RaySinner |nbihan-mediware |
+|ChuKhaLi |hassoncs |emshvac |kyle-apex |noritaka1166 |pdecat |
+|SannidhyaSah |StevenTCramer |Lunchb0ne |SmartManoj |vagadiya |slytechnical |
+|dleffel |arthurauffray |upamune |NamesMT |taylorwilsdon |sammcj |
+|Ruakij |p12tic |gtaylor |aitoroses |mr-ryan-james |heyseth |
+|taisukeoe |avtc |dlab-anton |eonghk |kcwhite |ronyblum |
+|teddyOOXX |vincentsong |yongjer |zeozeozeo |ashktn |franekp |
+|yt3trees |benzntech |axkirillov |anton-otee |bramburn |olearycrew |
+|snoyiatk |GitlyHallows |jcbdev |Chenjiayuan195 |julionav |SplittyDev |
+|mdp |napter |ross |philfung |dairui1 |dqroid |
+|forestyoo |GOODBOY008 |hatsu38 |hongzio |im47cn |shoopapa |
+|jwcraig |kinandan |nevermorec |bannzai |axmo |asychin |
+|amittell |Yoshino-Yukitaro |Yikai-Liao |zxdvd |vladstudio |tmsjngx0 |
+|tgfjt |PretzelVector |zetaloop |cdlliuy |user202729 |student20880 |
+|shohei-ihaya |shaybc |seedlord |samir-nimbly |robertheadley |refactorthis |
+|qingyuan1109 |pokutuna |philipnext |village-way |oprstchn |nobu007 |
+|mosleyit |moqimoqidea |mlopezr |mecab |olup |lightrabbit |
+|kohii |linegel |edwin-truthsearch-io |EamonNerbonne |dbasclpy |dflatline |
+|Deon588 |dleen |devxpain |chadgauth |brunobergher |thecolorblue |
+|bogdan0083 |Atlogit |atlasgong |andreastempsch |alasano |QuinsZouls |
+|HadesArchitect |alarno |nexon33 |adilhafeez |adamwlarson |adamhill |
+|AMHesch |maekawataiki |AlexandruSmirnov |samsilveira |01Rian |RSO |
+|SECKainersdorfer |R-omk |Sarke |kvokka |ecmasx |mollux |
+|marvijo-code |mamertofabian |monkeyDluffy6017 |libertyteeth |shtse8 |Rexarrior |
+|KanTakahiro |ksze |Jdo300 |hesara |DeXtroTip |pfitz |
+|celestial-vault | | | | | |
## 授權
diff --git a/package.json b/package.json
index 0b6c07ce78..0741895029 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,10 @@
},
"pnpm": {
"overrides": {
- "tar-fs": ">=2.1.3"
+ "tar-fs": ">=2.1.3",
+ "esbuild": ">=0.25.0",
+ "undici": ">=5.29.0",
+ "brace-expansion": ">=2.0.2"
}
}
}
diff --git a/packages/cloud/src/AuthService.ts b/packages/cloud/src/AuthService.ts
index 68036ce3c9..f64007f0d2 100644
--- a/packages/cloud/src/AuthService.ts
+++ b/packages/cloud/src/AuthService.ts
@@ -1,17 +1,17 @@
import crypto from "crypto"
import EventEmitter from "events"
-import axios from "axios"
import * as vscode from "vscode"
import { z } from "zod"
import type { CloudUserInfo, CloudOrganizationMembership } from "@roo-code/types"
-import { getClerkBaseUrl, getRooCodeApiUrl } from "./Config"
+import { getClerkBaseUrl, getRooCodeApiUrl, PRODUCTION_CLERK_BASE_URL } from "./Config"
import { RefreshTimer } from "./RefreshTimer"
import { getUserAgent } from "./utils"
export interface AuthServiceEvents {
+ "attempting-session": [data: { previousState: AuthState }]
"inactive-session": [data: { previousState: AuthState }]
"active-session": [data: { previousState: AuthState }]
"logged-out": [data: { previousState: AuthState }]
@@ -25,20 +25,76 @@ const authCredentialsSchema = z.object({
type AuthCredentials = z.infer
-const AUTH_CREDENTIALS_KEY = "clerk-auth-credentials"
const AUTH_STATE_KEY = "clerk-auth-state"
-type AuthState = "initializing" | "logged-out" | "active-session" | "inactive-session"
+type AuthState = "initializing" | "logged-out" | "active-session" | "attempting-session" | "inactive-session"
+
+const clerkSignInResponseSchema = z.object({
+ response: z.object({
+ created_session_id: z.string(),
+ }),
+})
+
+const clerkCreateSessionTokenResponseSchema = z.object({
+ jwt: z.string(),
+})
+
+const clerkMeResponseSchema = z.object({
+ response: z.object({
+ first_name: z.string().optional(),
+ last_name: z.string().optional(),
+ image_url: z.string().optional(),
+ primary_email_address_id: z.string().optional(),
+ email_addresses: z
+ .array(
+ z.object({
+ id: z.string(),
+ email_address: z.string(),
+ }),
+ )
+ .optional(),
+ }),
+})
+
+const clerkOrganizationMembershipsSchema = z.object({
+ response: z.array(
+ z.object({
+ id: z.string(),
+ role: z.string(),
+ permissions: z.array(z.string()).optional(),
+ created_at: z.number().optional(),
+ updated_at: z.number().optional(),
+ organization: z.object({
+ id: z.string(),
+ name: z.string(),
+ slug: z.string().optional(),
+ image_url: z.string().optional(),
+ has_image: z.boolean().optional(),
+ created_at: z.number().optional(),
+ updated_at: z.number().optional(),
+ }),
+ }),
+ ),
+})
+
+class InvalidClientTokenError extends Error {
+ constructor() {
+ super("Invalid/Expired client token")
+ Object.setPrototypeOf(this, InvalidClientTokenError.prototype)
+ }
+}
export class AuthService extends EventEmitter {
private context: vscode.ExtensionContext
private timer: RefreshTimer
private state: AuthState = "initializing"
private log: (...args: unknown[]) => void
+ private readonly authCredentialsKey: string
private credentials: AuthCredentials | null = null
private sessionToken: string | null = null
private userInfo: CloudUserInfo | null = null
+ private isFirstRefreshAttempt: boolean = false
constructor(context: vscode.ExtensionContext, log?: (...args: unknown[]) => void) {
super()
@@ -46,6 +102,14 @@ export class AuthService extends EventEmitter {
this.context = context
this.log = log || console.log
+ // Calculate auth credentials key based on Clerk base URL
+ const clerkBaseUrl = getClerkBaseUrl()
+ if (clerkBaseUrl !== PRODUCTION_CLERK_BASE_URL) {
+ this.authCredentialsKey = `clerk-auth-credentials-${clerkBaseUrl}`
+ } else {
+ this.authCredentialsKey = "clerk-auth-credentials"
+ }
+
this.timer = new RefreshTimer({
callback: async () => {
await this.refreshSession()
@@ -67,7 +131,7 @@ export class AuthService extends EventEmitter {
this.credentials.clientToken !== credentials.clientToken ||
this.credentials.sessionId !== credentials.sessionId
) {
- this.transitionToInactiveSession(credentials)
+ this.transitionToAttemptingSession(credentials)
}
} else {
if (this.state !== "logged-out") {
@@ -94,9 +158,24 @@ export class AuthService extends EventEmitter {
this.log("[auth] Transitioned to logged-out state")
}
- private transitionToInactiveSession(credentials: AuthCredentials): void {
+ private transitionToAttemptingSession(credentials: AuthCredentials): void {
this.credentials = credentials
+ const previousState = this.state
+ this.state = "attempting-session"
+
+ this.sessionToken = null
+ this.userInfo = null
+ this.isFirstRefreshAttempt = true
+
+ this.emit("attempting-session", { previousState })
+
+ this.timer.start()
+
+ this.log("[auth] Transitioned to attempting-session state")
+ }
+
+ private transitionToInactiveSession(): void {
const previousState = this.state
this.state = "inactive-session"
@@ -105,8 +184,6 @@ export class AuthService extends EventEmitter {
this.emit("inactive-session", { previousState })
- this.timer.start()
-
this.log("[auth] Transitioned to inactive-session state")
}
@@ -126,7 +203,7 @@ export class AuthService extends EventEmitter {
this.context.subscriptions.push(
this.context.secrets.onDidChange((e) => {
- if (e.key === AUTH_CREDENTIALS_KEY) {
+ if (e.key === this.authCredentialsKey) {
this.handleCredentialsChange()
}
}),
@@ -134,11 +211,11 @@ export class AuthService extends EventEmitter {
}
private async storeCredentials(credentials: AuthCredentials): Promise {
- await this.context.secrets.store(AUTH_CREDENTIALS_KEY, JSON.stringify(credentials))
+ await this.context.secrets.store(this.authCredentialsKey, JSON.stringify(credentials))
}
private async loadCredentials(): Promise {
- const credentialsJson = await this.context.secrets.get(AUTH_CREDENTIALS_KEY)
+ const credentialsJson = await this.context.secrets.get(this.authCredentialsKey)
if (!credentialsJson) return null
try {
@@ -155,7 +232,7 @@ export class AuthService extends EventEmitter {
}
private async clearCredentials(): Promise {
- await this.context.secrets.delete(AUTH_CREDENTIALS_KEY)
+ await this.context.secrets.delete(this.authCredentialsKey)
}
/**
@@ -208,7 +285,7 @@ export class AuthService extends EventEmitter {
throw new Error("Invalid state parameter. Authentication request may have been tampered with.")
}
- const { credentials } = await this.clerkSignIn(code)
+ const credentials = await this.clerkSignIn(code)
await this.storeCredentials(credentials)
@@ -267,16 +344,27 @@ export class AuthService extends EventEmitter {
/**
* Check if the user is authenticated
*
- * @returns True if the user is authenticated (has an active or inactive session)
+ * @returns True if the user is authenticated (has an active, attempting, or inactive session)
*/
public isAuthenticated(): boolean {
- return this.state === "active-session" || this.state === "inactive-session"
+ return (
+ this.state === "active-session" || this.state === "attempting-session" || this.state === "inactive-session"
+ )
}
public hasActiveSession(): boolean {
return this.state === "active-session"
}
+ /**
+ * Check if the user has an active session or is currently attempting to acquire one
+ *
+ * @returns True if the user has an active session or is attempting to get one
+ */
+ public hasOrIsAcquiringActiveSession(): boolean {
+ return this.state === "active-session" || this.state === "attempting-session"
+ }
+
/**
* Refresh the session
*
@@ -285,7 +373,6 @@ export class AuthService extends EventEmitter {
private async refreshSession(): Promise {
if (!this.credentials) {
this.log("[auth] Cannot refresh session: missing credentials")
- this.state = "inactive-session"
return
}
@@ -300,6 +387,13 @@ export class AuthService extends EventEmitter {
this.fetchUserInfo()
}
} catch (error) {
+ if (error instanceof InvalidClientTokenError) {
+ this.log("[auth] Invalid/Expired client token: clearing credentials")
+ this.clearCredentials()
+ } else if (this.isFirstRefreshAttempt && this.state === "attempting-session") {
+ this.isFirstRefreshAttempt = false
+ this.transitionToInactiveSession()
+ }
this.log("[auth] Failed to refresh session", error)
throw error
}
@@ -323,103 +417,93 @@ export class AuthService extends EventEmitter {
return this.userInfo
}
- private async clerkSignIn(ticket: string): Promise<{ credentials: AuthCredentials; sessionToken: string }> {
+ private async clerkSignIn(ticket: string): Promise {
const formData = new URLSearchParams()
formData.append("strategy", "ticket")
formData.append("ticket", ticket)
- const response = await axios.post(`${getClerkBaseUrl()}/v1/client/sign_ins`, formData, {
+ const response = await fetch(`${getClerkBaseUrl()}/v1/client/sign_ins`, {
+ method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": this.userAgent(),
},
+ body: formData.toString(),
+ signal: AbortSignal.timeout(10000),
})
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
+ }
+
+ const {
+ response: { created_session_id: sessionId },
+ } = clerkSignInResponseSchema.parse(await response.json())
+
// 3. Extract the client token from the Authorization header.
- const clientToken = response.headers.authorization
+ const clientToken = response.headers.get("authorization")
if (!clientToken) {
throw new Error("No authorization header found in the response")
}
- // 4. Find the session using created_session_id and extract the JWT.
- const sessionId = response.data?.response?.created_session_id
-
- if (!sessionId) {
- throw new Error("No session ID found in the response")
- }
-
- // Find the session in the client sessions array.
- const session = response.data?.client?.sessions?.find((s: { id: string }) => s.id === sessionId)
-
- if (!session) {
- throw new Error("Session not found in the response")
- }
-
- // Extract the session token (JWT) and store it.
- const sessionToken = session.last_active_token?.jwt
-
- if (!sessionToken) {
- throw new Error("Session does not have a token")
- }
-
- const credentials = authCredentialsSchema.parse({ clientToken, sessionId })
-
- return { credentials, sessionToken }
+ return authCredentialsSchema.parse({ clientToken, sessionId })
}
private async clerkCreateSessionToken(): Promise {
const formData = new URLSearchParams()
formData.append("_is_native", "1")
- const response = await axios.post(
- `${getClerkBaseUrl()}/v1/client/sessions/${this.credentials!.sessionId}/tokens`,
- formData,
- {
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- Authorization: `Bearer ${this.credentials!.clientToken}`,
- "User-Agent": this.userAgent(),
- },
+ const response = await fetch(`${getClerkBaseUrl()}/v1/client/sessions/${this.credentials!.sessionId}/tokens`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ Authorization: `Bearer ${this.credentials!.clientToken}`,
+ "User-Agent": this.userAgent(),
},
- )
+ body: formData.toString(),
+ signal: AbortSignal.timeout(10000),
+ })
- const sessionToken = response.data?.jwt
-
- if (!sessionToken) {
- throw new Error("No JWT found in refresh response")
+ if (response.status >= 400 && response.status < 500) {
+ throw new InvalidClientTokenError()
+ } else if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
- return sessionToken
+ const data = clerkCreateSessionTokenResponseSchema.parse(await response.json())
+
+ return data.jwt
}
private async clerkMe(): Promise {
- const response = await axios.get(`${getClerkBaseUrl()}/v1/me`, {
+ const response = await fetch(`${getClerkBaseUrl()}/v1/me`, {
headers: {
Authorization: `Bearer ${this.credentials!.clientToken}`,
"User-Agent": this.userAgent(),
},
+ signal: AbortSignal.timeout(10000),
})
- const userData = response.data?.response
-
- if (!userData) {
- throw new Error("No response user data")
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
+ const { response: userData } = clerkMeResponseSchema.parse(await response.json())
+
const userInfo: CloudUserInfo = {}
- userInfo.name = `${userData?.first_name} ${userData?.last_name}`
- const primaryEmailAddressId = userData?.primary_email_address_id
- const emailAddresses = userData?.email_addresses
+ userInfo.name = `${userData.first_name} ${userData.last_name}`
+ const primaryEmailAddressId = userData.primary_email_address_id
+ const emailAddresses = userData.email_addresses
if (primaryEmailAddressId && emailAddresses) {
userInfo.email = emailAddresses.find(
- (email: { id: string }) => primaryEmailAddressId === email?.id,
+ (email: { id: string }) => primaryEmailAddressId === email.id,
)?.email_address
}
- userInfo.picture = userData?.image_url
+ userInfo.picture = userData.image_url
// Fetch organization memberships separately
try {
@@ -433,6 +517,7 @@ export class AuthService extends EventEmitter {
userInfo.organizationId = organization.id
userInfo.organizationName = organization.name
userInfo.organizationRole = primaryOrgMembership.role
+ userInfo.organizationImageUrl = organization.image_url
}
}
} catch (error) {
@@ -444,51 +529,38 @@ export class AuthService extends EventEmitter {
}
private async clerkGetOrganizationMemberships(): Promise {
- const response = await axios.get(`${getClerkBaseUrl()}/v1/me/organization_memberships`, {
+ const response = await fetch(`${getClerkBaseUrl()}/v1/me/organization_memberships`, {
headers: {
Authorization: `Bearer ${this.credentials!.clientToken}`,
"User-Agent": this.userAgent(),
},
+ signal: AbortSignal.timeout(10000),
})
- // The response structure is: { response: [...] }
- // Extract the organization memberships from the response.response array
- return response.data?.response || []
+ return clerkOrganizationMembershipsSchema.parse(await response.json()).response
}
private async clerkLogout(credentials: AuthCredentials): Promise {
const formData = new URLSearchParams()
formData.append("_is_native", "1")
- await axios.post(`${getClerkBaseUrl()}/v1/client/sessions/${credentials.sessionId}/remove`, formData, {
+ const response = await fetch(`${getClerkBaseUrl()}/v1/client/sessions/${credentials.sessionId}/remove`, {
+ method: "POST",
headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
Authorization: `Bearer ${credentials.clientToken}`,
"User-Agent": this.userAgent(),
},
+ body: formData.toString(),
+ signal: AbortSignal.timeout(10000),
})
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
+ }
}
private userAgent(): string {
return getUserAgent(this.context)
}
-
- private static _instance: AuthService | null = null
-
- static get instance() {
- if (!this._instance) {
- throw new Error("AuthService not initialized")
- }
-
- return this._instance
- }
-
- static async createInstance(context: vscode.ExtensionContext, log?: (...args: unknown[]) => void) {
- if (this._instance) {
- throw new Error("AuthService instance already created")
- }
-
- this._instance = new AuthService(context, log)
- await this._instance.initialize()
- return this._instance
- }
}
diff --git a/packages/cloud/src/CloudService.ts b/packages/cloud/src/CloudService.ts
index fe3bad970c..c53538f1bc 100644
--- a/packages/cloud/src/CloudService.ts
+++ b/packages/cloud/src/CloudService.ts
@@ -37,16 +37,19 @@ export class CloudService {
}
try {
- this.authService = await AuthService.createInstance(this.context, this.log)
+ this.authService = new AuthService(this.context, this.log)
+ await this.authService.initialize()
+ this.authService.on("attempting-session", this.authListener)
this.authService.on("inactive-session", this.authListener)
this.authService.on("active-session", this.authListener)
this.authService.on("logged-out", this.authListener)
this.authService.on("user-info", this.authListener)
- this.settingsService = await SettingsService.createInstance(this.context, () =>
+ this.settingsService = new SettingsService(this.context, this.authService, () =>
this.callbacks.stateChanged?.(),
)
+ this.settingsService.initialize()
this.telemetryClient = new TelemetryClient(this.authService, this.settingsService)
@@ -87,6 +90,11 @@ export class CloudService {
return this.authService!.hasActiveSession()
}
+ public hasOrIsAcquiringActiveSession(): boolean {
+ this.ensureInitialized()
+ return this.authService!.hasOrIsAcquiringActiveSession()
+ }
+
public getUserInfo(): CloudUserInfo | null {
this.ensureInitialized()
return this.authService!.getUserInfo()
@@ -136,9 +144,9 @@ export class CloudService {
// ShareService
- public async shareTask(taskId: string): Promise {
+ public async shareTask(taskId: string, visibility: "organization" | "public" = "organization") {
this.ensureInitialized()
- return this.shareService!.shareTask(taskId)
+ return this.shareService!.shareTask(taskId, visibility)
}
public async canShareTask(): Promise {
@@ -150,6 +158,8 @@ export class CloudService {
public dispose(): void {
if (this.authService) {
+ this.authService.off("attempting-session", this.authListener)
+ this.authService.off("inactive-session", this.authListener)
this.authService.off("active-session", this.authListener)
this.authService.off("logged-out", this.authListener)
this.authService.off("user-info", this.authListener)
@@ -162,13 +172,7 @@ export class CloudService {
}
private ensureInitialized(): void {
- if (
- !this.isInitialized ||
- !this.authService ||
- !this.settingsService ||
- !this.telemetryClient ||
- !this.shareService
- ) {
+ if (!this.isInitialized) {
throw new Error("CloudService not initialized.")
}
}
diff --git a/packages/cloud/src/SettingsService.ts b/packages/cloud/src/SettingsService.ts
index d849cc03ae..3ee56000e8 100644
--- a/packages/cloud/src/SettingsService.ts
+++ b/packages/cloud/src/SettingsService.ts
@@ -14,14 +14,12 @@ import { RefreshTimer } from "./RefreshTimer"
const ORGANIZATION_SETTINGS_CACHE_KEY = "organization-settings"
export class SettingsService {
- private static _instance: SettingsService | null = null
-
private context: vscode.ExtensionContext
private authService: AuthService
private settings: OrganizationSettings | undefined = undefined
private timer: RefreshTimer
- private constructor(context: vscode.ExtensionContext, authService: AuthService, callback: () => void) {
+ constructor(context: vscode.ExtensionContext, authService: AuthService, callback: () => void) {
this.context = context
this.authService = authService
@@ -44,6 +42,10 @@ export class SettingsService {
this.removeSettings()
}
+ this.authService.on("attempting-session", () => {
+ this.timer.start()
+ })
+
this.authService.on("active-session", () => {
this.timer.start()
})
@@ -53,7 +55,7 @@ export class SettingsService {
this.removeSettings()
})
- if (this.authService.hasActiveSession()) {
+ if (this.authService.hasOrIsAcquiringActiveSession()) {
this.timer.start()
}
}
@@ -121,22 +123,4 @@ export class SettingsService {
public dispose(): void {
this.timer.stop()
}
-
- static get instance() {
- if (!this._instance) {
- throw new Error("SettingsService not initialized")
- }
-
- return this._instance
- }
-
- static async createInstance(context: vscode.ExtensionContext, callback: () => void) {
- if (this._instance) {
- throw new Error("SettingsService instance already created")
- }
-
- this._instance = new SettingsService(context, AuthService.instance, callback)
- this._instance.initialize()
- return this._instance
- }
}
diff --git a/packages/cloud/src/ShareService.ts b/packages/cloud/src/ShareService.ts
index 96eb20963e..42ea9c9fcf 100644
--- a/packages/cloud/src/ShareService.ts
+++ b/packages/cloud/src/ShareService.ts
@@ -7,6 +7,8 @@ import type { AuthService } from "./AuthService"
import type { SettingsService } from "./SettingsService"
import { getUserAgent } from "./utils"
+export type ShareVisibility = "organization" | "public"
+
export class ShareService {
private authService: AuthService
private settingsService: SettingsService
@@ -19,19 +21,19 @@ export class ShareService {
}
/**
- * Share a task: Create link and copy to clipboard
- * Returns true if successful, false if failed
+ * Share a task with specified visibility
+ * Returns the share response data
*/
- async shareTask(taskId: string): Promise {
+ async shareTask(taskId: string, visibility: ShareVisibility = "organization") {
try {
const sessionToken = this.authService.getSessionToken()
if (!sessionToken) {
- return false
+ throw new Error("Authentication required")
}
const response = await axios.post(
`${getRooCodeApiUrl()}/api/extension/share`,
- { taskId },
+ { taskId, visibility },
{
headers: {
"Content-Type": "application/json",
@@ -47,14 +49,12 @@ export class ShareService {
if (data.success && data.shareUrl) {
// Copy to clipboard
await vscode.env.clipboard.writeText(data.shareUrl)
- return true
- } else {
- this.log("[share] Share failed:", data.error)
- return false
}
+
+ return data
} catch (error) {
this.log("[share] Error sharing task:", error)
- return false
+ throw error
}
}
diff --git a/packages/cloud/src/__mocks__/vscode.ts b/packages/cloud/src/__mocks__/vscode.ts
index c4261941c4..ac9082375e 100644
--- a/packages/cloud/src/__mocks__/vscode.ts
+++ b/packages/cloud/src/__mocks__/vscode.ts
@@ -18,14 +18,18 @@ export interface ExtensionContext {
get: (key: string) => Promise
store: (key: string, value: string) => Promise
delete: (key: string) => Promise
+ onDidChange: (listener: (e: { key: string }) => void) => { dispose: () => void }
}
globalState: {
get: (key: string) => T | undefined
update: (key: string, value: any) => Promise
}
+ subscriptions: any[]
extension?: {
packageJSON?: {
version?: string
+ publisher?: string
+ name?: string
}
}
}
@@ -36,14 +40,18 @@ export const mockExtensionContext: ExtensionContext = {
get: vi.fn().mockResolvedValue(undefined),
store: vi.fn().mockResolvedValue(undefined),
delete: vi.fn().mockResolvedValue(undefined),
+ onDidChange: vi.fn().mockReturnValue({ dispose: vi.fn() }),
},
globalState: {
get: vi.fn().mockReturnValue(undefined),
update: vi.fn().mockResolvedValue(undefined),
},
+ subscriptions: [],
extension: {
packageJSON: {
version: "1.0.0",
+ publisher: "RooVeterinaryInc",
+ name: "roo-cline",
},
},
}
diff --git a/packages/cloud/src/__tests__/AuthService.spec.ts b/packages/cloud/src/__tests__/AuthService.spec.ts
new file mode 100644
index 0000000000..f4d4e98510
--- /dev/null
+++ b/packages/cloud/src/__tests__/AuthService.spec.ts
@@ -0,0 +1,1048 @@
+// npx vitest run src/__tests__/AuthService.spec.ts
+
+import { vi, Mock, beforeEach, afterEach, describe, it, expect } from "vitest"
+import crypto from "crypto"
+import * as vscode from "vscode"
+
+import { AuthService } from "../AuthService"
+import { RefreshTimer } from "../RefreshTimer"
+import * as Config from "../Config"
+import * as utils from "../utils"
+
+// Mock external dependencies
+vi.mock("../RefreshTimer")
+vi.mock("../Config")
+vi.mock("../utils")
+vi.mock("crypto")
+
+// Mock fetch globally
+const mockFetch = vi.fn()
+global.fetch = mockFetch
+
+// Mock vscode module
+vi.mock("vscode", () => ({
+ window: {
+ showInformationMessage: vi.fn(),
+ showErrorMessage: vi.fn(),
+ },
+ env: {
+ openExternal: vi.fn(),
+ uriScheme: "vscode",
+ },
+ Uri: {
+ parse: vi.fn((uri: string) => ({ toString: () => uri })),
+ },
+}))
+
+describe("AuthService", () => {
+ let authService: AuthService
+ let mockTimer: {
+ start: Mock
+ stop: Mock
+ reset: Mock
+ }
+ let mockLog: Mock
+ let mockContext: {
+ subscriptions: { push: Mock }
+ secrets: {
+ get: Mock
+ store: Mock
+ delete: Mock
+ onDidChange: Mock
+ }
+ globalState: {
+ get: Mock
+ update: Mock
+ }
+ extension: {
+ packageJSON: {
+ version: string
+ publisher: string
+ name: string
+ }
+ }
+ }
+
+ beforeEach(() => {
+ // Reset all mocks
+ vi.clearAllMocks()
+
+ // Setup mock context with proper subscriptions array
+ mockContext = {
+ subscriptions: {
+ push: vi.fn(),
+ },
+ secrets: {
+ get: vi.fn().mockResolvedValue(undefined),
+ store: vi.fn().mockResolvedValue(undefined),
+ delete: vi.fn().mockResolvedValue(undefined),
+ onDidChange: vi.fn().mockReturnValue({ dispose: vi.fn() }),
+ },
+ globalState: {
+ get: vi.fn().mockReturnValue(undefined),
+ update: vi.fn().mockResolvedValue(undefined),
+ },
+ extension: {
+ packageJSON: {
+ version: "1.0.0",
+ publisher: "RooVeterinaryInc",
+ name: "roo-cline",
+ },
+ },
+ }
+
+ // Setup timer mock
+ mockTimer = {
+ start: vi.fn(),
+ stop: vi.fn(),
+ reset: vi.fn(),
+ }
+ vi.mocked(RefreshTimer).mockImplementation(() => mockTimer as unknown as RefreshTimer)
+
+ // Setup config mocks - use production URL by default to maintain existing test behavior
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue("https://clerk.roocode.com")
+ vi.mocked(Config.getRooCodeApiUrl).mockReturnValue("https://api.test.com")
+
+ // Setup utils mock
+ vi.mocked(utils.getUserAgent).mockReturnValue("Roo-Code 1.0.0")
+
+ // Setup crypto mock
+ vi.mocked(crypto.randomBytes).mockReturnValue(Buffer.from("test-random-bytes") as never)
+
+ // Setup log mock
+ mockLog = vi.fn()
+
+ authService = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ })
+
+ afterEach(() => {
+ vi.clearAllMocks()
+ })
+
+ describe("constructor", () => {
+ it("should initialize with correct default values", () => {
+ expect(authService.getState()).toBe("initializing")
+ expect(authService.isAuthenticated()).toBe(false)
+ expect(authService.hasActiveSession()).toBe(false)
+ expect(authService.getSessionToken()).toBeUndefined()
+ expect(authService.getUserInfo()).toBeNull()
+ })
+
+ it("should create RefreshTimer with correct configuration", () => {
+ expect(RefreshTimer).toHaveBeenCalledWith({
+ callback: expect.any(Function),
+ successInterval: 50_000,
+ initialBackoffMs: 1_000,
+ maxBackoffMs: 300_000,
+ })
+ })
+
+ it("should use console.log as default logger", () => {
+ const serviceWithoutLog = new AuthService(mockContext as unknown as vscode.ExtensionContext)
+ // Can't directly test console.log usage, but constructor should not throw
+ expect(serviceWithoutLog).toBeInstanceOf(AuthService)
+ })
+ })
+
+ describe("initialize", () => {
+ it("should handle credentials change and setup event listener", async () => {
+ await authService.initialize()
+
+ expect(mockContext.subscriptions.push).toHaveBeenCalled()
+ expect(mockContext.secrets.onDidChange).toHaveBeenCalled()
+ })
+
+ it("should not initialize twice", async () => {
+ await authService.initialize()
+ const firstCallCount = vi.mocked(mockContext.secrets.onDidChange).mock.calls.length
+
+ await authService.initialize()
+ expect(mockContext.secrets.onDidChange).toHaveBeenCalledTimes(firstCallCount)
+ expect(mockLog).toHaveBeenCalledWith("[auth] initialize() called after already initialized")
+ })
+
+ it("should transition to logged-out when no credentials exist", async () => {
+ mockContext.secrets.get.mockResolvedValue(undefined)
+
+ const loggedOutSpy = vi.fn()
+ authService.on("logged-out", loggedOutSpy)
+
+ await authService.initialize()
+
+ expect(authService.getState()).toBe("logged-out")
+ expect(loggedOutSpy).toHaveBeenCalledWith({ previousState: "initializing" })
+ })
+
+ it("should transition to attempting-session when valid credentials exist", async () => {
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ const attemptingSessionSpy = vi.fn()
+ authService.on("attempting-session", attemptingSessionSpy)
+
+ await authService.initialize()
+
+ expect(authService.getState()).toBe("attempting-session")
+ expect(attemptingSessionSpy).toHaveBeenCalledWith({ previousState: "initializing" })
+ expect(mockTimer.start).toHaveBeenCalled()
+ })
+
+ it("should handle invalid credentials gracefully", async () => {
+ mockContext.secrets.get.mockResolvedValue("invalid-json")
+
+ const loggedOutSpy = vi.fn()
+ authService.on("logged-out", loggedOutSpy)
+
+ await authService.initialize()
+
+ expect(authService.getState()).toBe("logged-out")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Failed to parse stored credentials:", expect.any(Error))
+ })
+
+ it("should handle credentials change events", async () => {
+ let onDidChangeCallback: (e: { key: string }) => void
+
+ mockContext.secrets.onDidChange.mockImplementation((callback: (e: { key: string }) => void) => {
+ onDidChangeCallback = callback
+ return { dispose: vi.fn() }
+ })
+
+ await authService.initialize()
+
+ // Simulate credentials change event
+ const newCredentials = { clientToken: "new-token", sessionId: "new-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(newCredentials))
+
+ const attemptingSessionSpy = vi.fn()
+ authService.on("attempting-session", attemptingSessionSpy)
+
+ onDidChangeCallback!({ key: "clerk-auth-credentials" })
+ await new Promise((resolve) => setTimeout(resolve, 0)) // Wait for async handling
+
+ expect(attemptingSessionSpy).toHaveBeenCalled()
+ })
+ })
+
+ describe("login", () => {
+ beforeEach(async () => {
+ await authService.initialize()
+ })
+
+ it("should generate state and open external URL", async () => {
+ const mockOpenExternal = vi.fn()
+ const vscode = await import("vscode")
+ vi.mocked(vscode.env.openExternal).mockImplementation(mockOpenExternal)
+
+ await authService.login()
+
+ expect(crypto.randomBytes).toHaveBeenCalledWith(16)
+ expect(mockContext.globalState.update).toHaveBeenCalledWith(
+ "clerk-auth-state",
+ "746573742d72616e646f6d2d6279746573",
+ )
+ expect(mockOpenExternal).toHaveBeenCalledWith(
+ expect.objectContaining({
+ toString: expect.any(Function),
+ }),
+ )
+ })
+
+ it("should use package.json values for redirect URI", async () => {
+ const mockOpenExternal = vi.fn()
+ const vscode = await import("vscode")
+ vi.mocked(vscode.env.openExternal).mockImplementation(mockOpenExternal)
+
+ await authService.login()
+
+ const expectedUrl =
+ "https://api.test.com/extension/sign-in?state=746573742d72616e646f6d2d6279746573&auth_redirect=vscode%3A%2F%2FRooVeterinaryInc.roo-cline"
+ expect(mockOpenExternal).toHaveBeenCalledWith(
+ expect.objectContaining({
+ toString: expect.any(Function),
+ }),
+ )
+
+ // Verify the actual URL
+ const calledUri = mockOpenExternal.mock.calls[0][0]
+ expect(calledUri.toString()).toBe(expectedUrl)
+ })
+
+ it("should handle errors during login", async () => {
+ vi.mocked(crypto.randomBytes).mockImplementation(() => {
+ throw new Error("Crypto error")
+ })
+
+ await expect(authService.login()).rejects.toThrow("Failed to initiate Roo Code Cloud authentication")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Error initiating Roo Code Cloud auth: Error: Crypto error")
+ })
+ })
+
+ describe("handleCallback", () => {
+ beforeEach(async () => {
+ await authService.initialize()
+ })
+
+ it("should handle invalid parameters", async () => {
+ const vscode = await import("vscode")
+ const mockShowInfo = vi.fn()
+ vi.mocked(vscode.window.showInformationMessage).mockImplementation(mockShowInfo)
+
+ await authService.handleCallback(null, "state")
+ expect(mockShowInfo).toHaveBeenCalledWith("Invalid Roo Code Cloud sign in url")
+
+ await authService.handleCallback("code", null)
+ expect(mockShowInfo).toHaveBeenCalledWith("Invalid Roo Code Cloud sign in url")
+ })
+
+ it("should validate state parameter", async () => {
+ mockContext.globalState.get.mockReturnValue("stored-state")
+
+ await expect(authService.handleCallback("code", "different-state")).rejects.toThrow(
+ "Failed to handle Roo Code Cloud callback",
+ )
+ expect(mockLog).toHaveBeenCalledWith("[auth] State mismatch in callback")
+ })
+
+ it("should successfully handle valid callback", async () => {
+ const storedState = "valid-state"
+ mockContext.globalState.get.mockReturnValue(storedState)
+
+ // Mock successful Clerk sign-in response
+ const mockResponse = {
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: { created_session_id: "session-123" },
+ }),
+ headers: {
+ get: (header: string) => (header === "authorization" ? "Bearer token-123" : null),
+ },
+ }
+ mockFetch.mockResolvedValue(mockResponse)
+
+ const vscode = await import("vscode")
+ const mockShowInfo = vi.fn()
+ vi.mocked(vscode.window.showInformationMessage).mockImplementation(mockShowInfo)
+
+ await authService.handleCallback("auth-code", storedState)
+
+ expect(mockContext.secrets.store).toHaveBeenCalledWith(
+ "clerk-auth-credentials",
+ JSON.stringify({ clientToken: "Bearer token-123", sessionId: "session-123" }),
+ )
+ expect(mockShowInfo).toHaveBeenCalledWith("Successfully authenticated with Roo Code Cloud")
+ })
+
+ it("should handle Clerk API errors", async () => {
+ const storedState = "valid-state"
+ mockContext.globalState.get.mockReturnValue(storedState)
+
+ mockFetch.mockResolvedValue({
+ ok: false,
+ status: 400,
+ statusText: "Bad Request",
+ })
+
+ const loggedOutSpy = vi.fn()
+ authService.on("logged-out", loggedOutSpy)
+
+ await expect(authService.handleCallback("auth-code", storedState)).rejects.toThrow(
+ "Failed to handle Roo Code Cloud callback",
+ )
+ expect(loggedOutSpy).toHaveBeenCalled()
+ })
+ })
+
+ describe("logout", () => {
+ beforeEach(async () => {
+ await authService.initialize()
+ })
+
+ it("should clear credentials and call Clerk logout", async () => {
+ // Set up credentials first by simulating a login state
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+
+ // Manually set the credentials in the service
+ authService["credentials"] = credentials
+
+ // Mock successful logout response
+ mockFetch.mockResolvedValue({ ok: true })
+
+ const vscode = await import("vscode")
+ const mockShowInfo = vi.fn()
+ vi.mocked(vscode.window.showInformationMessage).mockImplementation(mockShowInfo)
+
+ await authService.logout()
+
+ expect(mockContext.secrets.delete).toHaveBeenCalledWith("clerk-auth-credentials")
+ expect(mockContext.globalState.update).toHaveBeenCalledWith("clerk-auth-state", undefined)
+ expect(mockFetch).toHaveBeenCalledWith(
+ "https://clerk.roocode.com/v1/client/sessions/test-session/remove",
+ expect.objectContaining({
+ method: "POST",
+ headers: expect.objectContaining({
+ Authorization: "Bearer test-token",
+ }),
+ }),
+ )
+ expect(mockShowInfo).toHaveBeenCalledWith("Logged out from Roo Code Cloud")
+ })
+
+ it("should handle logout without credentials", async () => {
+ const vscode = await import("vscode")
+ const mockShowInfo = vi.fn()
+ vi.mocked(vscode.window.showInformationMessage).mockImplementation(mockShowInfo)
+
+ await authService.logout()
+
+ expect(mockContext.secrets.delete).toHaveBeenCalled()
+ expect(mockFetch).not.toHaveBeenCalled()
+ expect(mockShowInfo).toHaveBeenCalledWith("Logged out from Roo Code Cloud")
+ })
+
+ it("should handle Clerk logout errors gracefully", async () => {
+ // Set up credentials first by simulating a login state
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+
+ // Manually set the credentials in the service
+ authService["credentials"] = credentials
+
+ // Mock failed logout response
+ mockFetch.mockRejectedValue(new Error("Network error"))
+
+ const vscode = await import("vscode")
+ const mockShowInfo = vi.fn()
+ vi.mocked(vscode.window.showInformationMessage).mockImplementation(mockShowInfo)
+
+ await authService.logout()
+
+ expect(mockLog).toHaveBeenCalledWith("[auth] Error calling clerkLogout:", expect.any(Error))
+ expect(mockShowInfo).toHaveBeenCalledWith("Logged out from Roo Code Cloud")
+ })
+ })
+
+ describe("state management", () => {
+ it("should return correct state", () => {
+ expect(authService.getState()).toBe("initializing")
+ })
+
+ it("should return correct authentication status", async () => {
+ await authService.initialize()
+ expect(authService.isAuthenticated()).toBe(false)
+
+ // Create a new service instance with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ const authenticatedService = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ await authenticatedService.initialize()
+
+ expect(authenticatedService.isAuthenticated()).toBe(true)
+ expect(authenticatedService.hasActiveSession()).toBe(false)
+ })
+
+ it("should return session token only for active sessions", () => {
+ expect(authService.getSessionToken()).toBeUndefined()
+
+ // Manually set state to active-session for testing
+ // This would normally happen through refreshSession
+ authService["state"] = "active-session"
+ authService["sessionToken"] = "test-jwt"
+
+ expect(authService.getSessionToken()).toBe("test-jwt")
+ })
+
+ it("should return correct values for new methods", async () => {
+ await authService.initialize()
+ expect(authService.hasOrIsAcquiringActiveSession()).toBe(false)
+
+ // Create a new service instance with credentials (attempting-session)
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ const attemptingService = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ await attemptingService.initialize()
+
+ expect(attemptingService.hasOrIsAcquiringActiveSession()).toBe(true)
+ expect(attemptingService.hasActiveSession()).toBe(false)
+
+ // Manually set state to active-session for testing
+ attemptingService["state"] = "active-session"
+ expect(attemptingService.hasOrIsAcquiringActiveSession()).toBe(true)
+ expect(attemptingService.hasActiveSession()).toBe(true)
+ })
+ })
+
+ describe("session refresh", () => {
+ beforeEach(async () => {
+ // Set up with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+ await authService.initialize()
+ })
+
+ it("should refresh session successfully", async () => {
+ // Mock successful token creation and user info fetch
+ mockFetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () => Promise.resolve({ jwt: "new-jwt-token" }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: {
+ first_name: "John",
+ last_name: "Doe",
+ image_url: "https://example.com/avatar.jpg",
+ primary_email_address_id: "email-1",
+ email_addresses: [{ id: "email-1", email_address: "john@example.com" }],
+ },
+ }),
+ })
+
+ const activeSessionSpy = vi.fn()
+ const userInfoSpy = vi.fn()
+ authService.on("active-session", activeSessionSpy)
+ authService.on("user-info", userInfoSpy)
+
+ // Trigger refresh by calling the timer callback
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await timerCallback()
+
+ // Wait for async operations to complete
+ await new Promise((resolve) => setTimeout(resolve, 0))
+
+ expect(authService.getState()).toBe("active-session")
+ expect(authService.hasActiveSession()).toBe(true)
+ expect(authService.getSessionToken()).toBe("new-jwt-token")
+ expect(activeSessionSpy).toHaveBeenCalledWith({ previousState: "attempting-session" })
+ expect(userInfoSpy).toHaveBeenCalledWith({
+ userInfo: {
+ name: "John Doe",
+ email: "john@example.com",
+ picture: "https://example.com/avatar.jpg",
+ },
+ })
+ })
+
+ it("should handle invalid client token error", async () => {
+ // Mock 401 response (invalid token)
+ mockFetch.mockResolvedValue({
+ ok: false,
+ status: 401,
+ statusText: "Unauthorized",
+ })
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+
+ await expect(timerCallback()).rejects.toThrow()
+ expect(mockContext.secrets.delete).toHaveBeenCalledWith("clerk-auth-credentials")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Invalid/Expired client token: clearing credentials")
+ })
+
+ it("should handle network errors during refresh", async () => {
+ mockFetch.mockRejectedValue(new Error("Network error"))
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+
+ await expect(timerCallback()).rejects.toThrow("Network error")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Failed to refresh session", expect.any(Error))
+ })
+
+ it("should transition to inactive-session on first attempt failure", async () => {
+ // Mock failed token creation response
+ mockFetch.mockResolvedValue({
+ ok: false,
+ status: 500,
+ statusText: "Internal Server Error",
+ })
+
+ const inactiveSessionSpy = vi.fn()
+ authService.on("inactive-session", inactiveSessionSpy)
+
+ // Verify we start in attempting-session state
+ expect(authService.getState()).toBe("attempting-session")
+ expect(authService["isFirstRefreshAttempt"]).toBe(true)
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+
+ await expect(timerCallback()).rejects.toThrow()
+
+ // Should transition to inactive-session after first failure
+ expect(authService.getState()).toBe("inactive-session")
+ expect(authService["isFirstRefreshAttempt"]).toBe(false)
+ expect(inactiveSessionSpy).toHaveBeenCalledWith({ previousState: "attempting-session" })
+ })
+
+ it("should not transition to inactive-session on subsequent failures", async () => {
+ // First, transition to inactive-session by failing the first attempt
+ mockFetch.mockResolvedValue({
+ ok: false,
+ status: 500,
+ statusText: "Internal Server Error",
+ })
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await expect(timerCallback()).rejects.toThrow()
+
+ // Verify we're now in inactive-session
+ expect(authService.getState()).toBe("inactive-session")
+ expect(authService["isFirstRefreshAttempt"]).toBe(false)
+
+ const inactiveSessionSpy = vi.fn()
+ authService.on("inactive-session", inactiveSessionSpy)
+
+ // Subsequent failure should not trigger another transition
+ await expect(timerCallback()).rejects.toThrow()
+
+ expect(authService.getState()).toBe("inactive-session")
+ expect(inactiveSessionSpy).not.toHaveBeenCalled()
+ })
+
+ it("should clear credentials on 401 during first refresh attempt (bug fix)", async () => {
+ // Mock 401 response during first refresh attempt
+ mockFetch.mockResolvedValue({
+ ok: false,
+ status: 401,
+ statusText: "Unauthorized",
+ })
+
+ const loggedOutSpy = vi.fn()
+ authService.on("logged-out", loggedOutSpy)
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await expect(timerCallback()).rejects.toThrow()
+
+ // Should clear credentials (not just transition to inactive-session)
+ expect(mockContext.secrets.delete).toHaveBeenCalledWith("clerk-auth-credentials")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Invalid/Expired client token: clearing credentials")
+
+ // Simulate credentials cleared event
+ mockContext.secrets.get.mockResolvedValue(undefined)
+ await authService["handleCredentialsChange"]()
+
+ expect(authService.getState()).toBe("logged-out")
+ expect(loggedOutSpy).toHaveBeenCalledWith({ previousState: "attempting-session" })
+ })
+ })
+
+ describe("user info", () => {
+ it("should return null initially", () => {
+ expect(authService.getUserInfo()).toBeNull()
+ })
+
+ it("should parse user info correctly", async () => {
+ // Set up with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+ await authService.initialize()
+
+ // Clear previous mock calls
+ mockFetch.mockClear()
+
+ // Mock successful responses
+ mockFetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () => Promise.resolve({ jwt: "jwt-token" }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: {
+ first_name: "Jane",
+ last_name: "Smith",
+ image_url: "https://example.com/jane.jpg",
+ primary_email_address_id: "email-2",
+ email_addresses: [
+ { id: "email-1", email_address: "jane.old@example.com" },
+ { id: "email-2", email_address: "jane@example.com" },
+ ],
+ },
+ }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: [
+ {
+ id: "org_member_id_1",
+ role: "member",
+ organization: {
+ id: "org_1",
+ name: "Org 1",
+ },
+ },
+ ],
+ }),
+ })
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await timerCallback()
+
+ // Wait for async operations to complete
+ await new Promise((resolve) => setTimeout(resolve, 0))
+
+ const userInfo = authService.getUserInfo()
+ expect(userInfo).toEqual({
+ name: "Jane Smith",
+ email: "jane@example.com",
+ picture: "https://example.com/jane.jpg",
+ organizationId: "org_1",
+ organizationName: "Org 1",
+ organizationRole: "member",
+ })
+ })
+
+ it("should handle missing user info fields", async () => {
+ // Set up with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+ await authService.initialize()
+
+ // Clear previous mock calls
+ mockFetch.mockClear()
+
+ // Mock responses with minimal data
+ mockFetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () => Promise.resolve({ jwt: "jwt-token" }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: {
+ first_name: "John",
+ last_name: "Doe",
+ // Missing other fields
+ },
+ }),
+ })
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await timerCallback()
+
+ // Wait for async operations to complete
+ await new Promise((resolve) => setTimeout(resolve, 0))
+
+ const userInfo = authService.getUserInfo()
+ expect(userInfo).toEqual({
+ name: "John Doe",
+ email: undefined,
+ picture: undefined,
+ })
+ })
+ })
+
+ describe("event emissions", () => {
+ it("should emit logged-out event", async () => {
+ const loggedOutSpy = vi.fn()
+ authService.on("logged-out", loggedOutSpy)
+
+ await authService.initialize()
+
+ expect(loggedOutSpy).toHaveBeenCalledWith({ previousState: "initializing" })
+ })
+
+ it("should emit attempting-session event", async () => {
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ const attemptingSessionSpy = vi.fn()
+ authService.on("attempting-session", attemptingSessionSpy)
+
+ await authService.initialize()
+
+ expect(attemptingSessionSpy).toHaveBeenCalledWith({ previousState: "initializing" })
+ })
+
+ it("should emit active-session event", async () => {
+ // Set up with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+ await authService.initialize()
+
+ // Clear previous mock calls
+ mockFetch.mockClear()
+
+ // Mock both the token creation and user info fetch
+ mockFetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () => Promise.resolve({ jwt: "jwt-token" }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: {
+ first_name: "Test",
+ last_name: "User",
+ },
+ }),
+ })
+
+ const activeSessionSpy = vi.fn()
+ authService.on("active-session", activeSessionSpy)
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await timerCallback()
+
+ // Wait for async operations to complete
+ await new Promise((resolve) => setTimeout(resolve, 0))
+
+ expect(activeSessionSpy).toHaveBeenCalledWith({ previousState: "attempting-session" })
+ })
+
+ it("should emit user-info event", async () => {
+ // Set up with credentials
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+ await authService.initialize()
+
+ // Clear previous mock calls
+ mockFetch.mockClear()
+
+ mockFetch
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () => Promise.resolve({ jwt: "jwt-token" }),
+ })
+ .mockResolvedValueOnce({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: {
+ first_name: "Test",
+ last_name: "User",
+ },
+ }),
+ })
+
+ const userInfoSpy = vi.fn()
+ authService.on("user-info", userInfoSpy)
+
+ const timerCallback = vi.mocked(RefreshTimer).mock.calls[0][0].callback
+ await timerCallback()
+
+ // Wait for async operations to complete
+ await new Promise((resolve) => setTimeout(resolve, 0))
+
+ expect(userInfoSpy).toHaveBeenCalledWith({
+ userInfo: {
+ name: "Test User",
+ email: undefined,
+ picture: undefined,
+ },
+ })
+ })
+ })
+
+ describe("error handling", () => {
+ it("should handle credentials change errors", async () => {
+ mockContext.secrets.get.mockRejectedValue(new Error("Storage error"))
+
+ await authService.initialize()
+
+ expect(mockLog).toHaveBeenCalledWith("[auth] Error handling credentials change:", expect.any(Error))
+ })
+
+ it("should handle malformed JSON in credentials", async () => {
+ mockContext.secrets.get.mockResolvedValue("invalid-json{")
+
+ await authService.initialize()
+
+ expect(authService.getState()).toBe("logged-out")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Failed to parse stored credentials:", expect.any(Error))
+ })
+
+ it("should handle invalid credentials schema", async () => {
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify({ invalid: "data" }))
+
+ await authService.initialize()
+
+ expect(authService.getState()).toBe("logged-out")
+ expect(mockLog).toHaveBeenCalledWith("[auth] Invalid credentials format:", expect.any(Array))
+ })
+
+ it("should handle missing authorization header in sign-in response", async () => {
+ const storedState = "valid-state"
+ mockContext.globalState.get.mockReturnValue(storedState)
+
+ mockFetch.mockResolvedValue({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ response: { created_session_id: "session-123" },
+ }),
+ headers: {
+ get: () => null, // No authorization header
+ },
+ })
+
+ await expect(authService.handleCallback("auth-code", storedState)).rejects.toThrow(
+ "Failed to handle Roo Code Cloud callback",
+ )
+ })
+ })
+
+ describe("timer integration", () => {
+ it("should stop timer on logged-out transition", async () => {
+ await authService.initialize()
+
+ expect(mockTimer.stop).toHaveBeenCalled()
+ })
+
+ it("should start timer on attempting-session transition", async () => {
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ await authService.initialize()
+
+ expect(mockTimer.start).toHaveBeenCalled()
+ })
+ })
+
+ describe("auth credentials key scoping", () => {
+ it("should use default key when getClerkBaseUrl returns production URL", async () => {
+ // Mock getClerkBaseUrl to return production URL
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue("https://clerk.roocode.com")
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+
+ await service.initialize()
+ await service["storeCredentials"](credentials)
+
+ expect(mockContext.secrets.store).toHaveBeenCalledWith(
+ "clerk-auth-credentials",
+ JSON.stringify(credentials),
+ )
+ })
+
+ it("should use scoped key when getClerkBaseUrl returns custom URL", async () => {
+ const customUrl = "https://custom.clerk.com"
+ // Mock getClerkBaseUrl to return custom URL
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+
+ await service.initialize()
+ await service["storeCredentials"](credentials)
+
+ expect(mockContext.secrets.store).toHaveBeenCalledWith(
+ `clerk-auth-credentials-${customUrl}`,
+ JSON.stringify(credentials),
+ )
+ })
+
+ it("should load credentials using scoped key", async () => {
+ const customUrl = "https://custom.clerk.com"
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ const credentials = { clientToken: "test-token", sessionId: "test-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(credentials))
+
+ await service.initialize()
+ const loadedCredentials = await service["loadCredentials"]()
+
+ expect(mockContext.secrets.get).toHaveBeenCalledWith(`clerk-auth-credentials-${customUrl}`)
+ expect(loadedCredentials).toEqual(credentials)
+ })
+
+ it("should clear credentials using scoped key", async () => {
+ const customUrl = "https://custom.clerk.com"
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+
+ await service.initialize()
+ await service["clearCredentials"]()
+
+ expect(mockContext.secrets.delete).toHaveBeenCalledWith(`clerk-auth-credentials-${customUrl}`)
+ })
+
+ it("should listen for changes on scoped key", async () => {
+ const customUrl = "https://custom.clerk.com"
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ let onDidChangeCallback: (e: { key: string }) => void
+
+ mockContext.secrets.onDidChange.mockImplementation((callback: (e: { key: string }) => void) => {
+ onDidChangeCallback = callback
+ return { dispose: vi.fn() }
+ })
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ await service.initialize()
+
+ // Simulate credentials change event with scoped key
+ const newCredentials = { clientToken: "new-token", sessionId: "new-session" }
+ mockContext.secrets.get.mockResolvedValue(JSON.stringify(newCredentials))
+
+ const attemptingSessionSpy = vi.fn()
+ service.on("attempting-session", attemptingSessionSpy)
+
+ onDidChangeCallback!({ key: `clerk-auth-credentials-${customUrl}` })
+ await new Promise((resolve) => setTimeout(resolve, 0)) // Wait for async handling
+
+ expect(attemptingSessionSpy).toHaveBeenCalled()
+ })
+
+ it("should not respond to changes on different scoped keys", async () => {
+ const customUrl = "https://custom.clerk.com"
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ let onDidChangeCallback: (e: { key: string }) => void
+
+ mockContext.secrets.onDidChange.mockImplementation((callback: (e: { key: string }) => void) => {
+ onDidChangeCallback = callback
+ return { dispose: vi.fn() }
+ })
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ await service.initialize()
+
+ const inactiveSessionSpy = vi.fn()
+ service.on("inactive-session", inactiveSessionSpy)
+
+ // Simulate credentials change event with different scoped key
+ onDidChangeCallback!({ key: "clerk-auth-credentials-https://other.clerk.com" })
+ await new Promise((resolve) => setTimeout(resolve, 0)) // Wait for async handling
+
+ expect(inactiveSessionSpy).not.toHaveBeenCalled()
+ })
+
+ it("should not respond to changes on default key when using scoped key", async () => {
+ const customUrl = "https://custom.clerk.com"
+ vi.mocked(Config.getClerkBaseUrl).mockReturnValue(customUrl)
+
+ let onDidChangeCallback: (e: { key: string }) => void
+
+ mockContext.secrets.onDidChange.mockImplementation((callback: (e: { key: string }) => void) => {
+ onDidChangeCallback = callback
+ return { dispose: vi.fn() }
+ })
+
+ const service = new AuthService(mockContext as unknown as vscode.ExtensionContext, mockLog)
+ await service.initialize()
+
+ const inactiveSessionSpy = vi.fn()
+ service.on("inactive-session", inactiveSessionSpy)
+
+ // Simulate credentials change event with default key
+ onDidChangeCallback!({ key: "clerk-auth-credentials" })
+ await new Promise((resolve) => setTimeout(resolve, 0)) // Wait for async handling
+
+ expect(inactiveSessionSpy).not.toHaveBeenCalled()
+ })
+ })
+})
diff --git a/packages/cloud/src/__tests__/CloudService.test.ts b/packages/cloud/src/__tests__/CloudService.test.ts
index 03b28568d5..c7dc07fcae 100644
--- a/packages/cloud/src/__tests__/CloudService.test.ts
+++ b/packages/cloud/src/__tests__/CloudService.test.ts
@@ -79,7 +79,7 @@ describe("CloudService", () => {
} as unknown as vscode.ExtensionContext
mockAuthService = {
- initialize: vi.fn(),
+ initialize: vi.fn().mockResolvedValue(undefined),
login: vi.fn(),
logout: vi.fn(),
isAuthenticated: vi.fn().mockReturnValue(false),
@@ -108,11 +108,8 @@ describe("CloudService", () => {
},
}
- vi.mocked(AuthService.createInstance).mockResolvedValue(mockAuthService as unknown as AuthService)
- Object.defineProperty(AuthService, "instance", { get: () => mockAuthService, configurable: true })
-
- vi.mocked(SettingsService.createInstance).mockResolvedValue(mockSettingsService as unknown as SettingsService)
- Object.defineProperty(SettingsService, "instance", { get: () => mockSettingsService, configurable: true })
+ vi.mocked(AuthService).mockImplementation(() => mockAuthService as unknown as AuthService)
+ vi.mocked(SettingsService).mockImplementation(() => mockSettingsService as unknown as SettingsService)
vi.mocked(TelemetryService.hasInstance).mockReturnValue(true)
Object.defineProperty(TelemetryService, "instance", {
@@ -135,8 +132,8 @@ describe("CloudService", () => {
const cloudService = await CloudService.createInstance(mockContext, callbacks)
expect(cloudService).toBeInstanceOf(CloudService)
- expect(AuthService.createInstance).toHaveBeenCalledWith(mockContext, expect.any(Function))
- expect(SettingsService.createInstance).toHaveBeenCalledWith(mockContext, expect.any(Function))
+ expect(AuthService).toHaveBeenCalledWith(mockContext, expect.any(Function))
+ expect(SettingsService).toHaveBeenCalledWith(mockContext, mockAuthService, expect.any(Function))
})
it("should throw error if instance already exists", async () => {
diff --git a/packages/cloud/src/__tests__/ShareService.test.ts b/packages/cloud/src/__tests__/ShareService.test.ts
index b46cefa6a0..55fc4e7c38 100644
--- a/packages/cloud/src/__tests__/ShareService.test.ts
+++ b/packages/cloud/src/__tests__/ShareService.test.ts
@@ -17,6 +17,7 @@ vi.mock("vscode", () => ({
window: {
showInformationMessage: vi.fn(),
showErrorMessage: vi.fn(),
+ showQuickPick: vi.fn(),
},
env: {
clipboard: {
@@ -68,7 +69,7 @@ describe("ShareService", () => {
})
describe("shareTask", () => {
- it("should share task and copy to clipboard", async () => {
+ it("should share task with organization visibility and copy to clipboard", async () => {
const mockResponse = {
data: {
success: true,
@@ -76,16 +77,16 @@ describe("ShareService", () => {
},
}
- ;(mockAuthService.hasActiveSession as any).mockReturnValue(true)
;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
mockedAxios.post.mockResolvedValue(mockResponse)
- const result = await shareService.shareTask("task-123")
+ const result = await shareService.shareTask("task-123", "organization")
- expect(result).toBe(true)
+ expect(result.success).toBe(true)
+ expect(result.shareUrl).toBe("https://app.roocode.com/share/abc123")
expect(mockedAxios.post).toHaveBeenCalledWith(
"https://app.roocode.com/api/extension/share",
- { taskId: "task-123" },
+ { taskId: "task-123", visibility: "organization" },
{
headers: {
"Content-Type": "application/json",
@@ -97,6 +98,48 @@ describe("ShareService", () => {
expect(vscode.env.clipboard.writeText).toHaveBeenCalledWith("https://app.roocode.com/share/abc123")
})
+ it("should share task with public visibility", async () => {
+ const mockResponse = {
+ data: {
+ success: true,
+ shareUrl: "https://app.roocode.com/share/abc123",
+ },
+ }
+
+ ;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
+ mockedAxios.post.mockResolvedValue(mockResponse)
+
+ const result = await shareService.shareTask("task-123", "public")
+
+ expect(result.success).toBe(true)
+ expect(mockedAxios.post).toHaveBeenCalledWith(
+ "https://app.roocode.com/api/extension/share",
+ { taskId: "task-123", visibility: "public" },
+ expect.any(Object),
+ )
+ })
+
+ it("should default to organization visibility when not specified", async () => {
+ const mockResponse = {
+ data: {
+ success: true,
+ shareUrl: "https://app.roocode.com/share/abc123",
+ },
+ }
+
+ ;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
+ mockedAxios.post.mockResolvedValue(mockResponse)
+
+ const result = await shareService.shareTask("task-123")
+
+ expect(result.success).toBe(true)
+ expect(mockedAxios.post).toHaveBeenCalledWith(
+ "https://app.roocode.com/api/extension/share",
+ { taskId: "task-123", visibility: "organization" },
+ expect.any(Object),
+ )
+ })
+
it("should handle API error response", async () => {
const mockResponse = {
data: {
@@ -105,55 +148,26 @@ describe("ShareService", () => {
},
}
- ;(mockAuthService.hasActiveSession as any).mockReturnValue(true)
;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
mockedAxios.post.mockResolvedValue(mockResponse)
- const result = await shareService.shareTask("task-123")
+ const result = await shareService.shareTask("task-123", "organization")
- expect(result).toBe(false)
+ expect(result.success).toBe(false)
+ expect(result.error).toBe("Task not found")
})
it("should handle authentication errors", async () => {
- ;(mockAuthService.hasActiveSession as any).mockReturnValue(false)
+ ;(mockAuthService.getSessionToken as any).mockReturnValue(null)
- const result = await shareService.shareTask("task-123")
-
- expect(result).toBe(false)
- expect(mockedAxios.post).not.toHaveBeenCalled()
- })
-
- it("should handle 403 error for disabled sharing", async () => {
- ;(mockAuthService.hasActiveSession as any).mockReturnValue(true)
- ;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
-
- const error = {
- isAxiosError: true,
- response: {
- status: 403,
- data: {
- error: "Task sharing is not enabled for this organization",
- },
- },
- }
-
- mockedAxios.isAxiosError.mockReturnValue(true)
- mockedAxios.post.mockRejectedValue(error)
-
- const result = await shareService.shareTask("task-123")
-
- expect(result).toBe(false)
+ await expect(shareService.shareTask("task-123", "organization")).rejects.toThrow("Authentication required")
})
it("should handle unexpected errors", async () => {
- ;(mockAuthService.hasActiveSession as any).mockReturnValue(true)
;(mockAuthService.getSessionToken as any).mockReturnValue("session-token")
-
mockedAxios.post.mockRejectedValue(new Error("Network error"))
- const result = await shareService.shareTask("task-123")
-
- expect(result).toBe(false)
+ await expect(shareService.shareTask("task-123", "organization")).rejects.toThrow("Network error")
})
})
diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json
index 25c842089b..42d0df387c 100644
--- a/packages/telemetry/package.json
+++ b/packages/telemetry/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@roo-code/types": "workspace:^",
- "posthog-node": "^4.7.0",
+ "posthog-node": "^5.0.0",
"zod": "^3.25.61"
},
"devDependencies": {
diff --git a/packages/telemetry/src/TelemetryService.ts b/packages/telemetry/src/TelemetryService.ts
index 956f49313a..728809f8bd 100644
--- a/packages/telemetry/src/TelemetryService.ts
+++ b/packages/telemetry/src/TelemetryService.ts
@@ -173,7 +173,7 @@ export class TelemetryService {
itemType,
itemName,
target,
- ... (properties || {}),
+ ...(properties || {}),
})
}
diff --git a/packages/types/src/cloud.ts b/packages/types/src/cloud.ts
index 6f5547b3d5..dc5ef439dc 100644
--- a/packages/types/src/cloud.ts
+++ b/packages/types/src/cloud.ts
@@ -13,6 +13,7 @@ export interface CloudUserInfo {
organizationId?: string
organizationName?: string
organizationRole?: string
+ organizationImageUrl?: string
}
/**
@@ -139,6 +140,8 @@ export const shareResponseSchema = z.object({
success: z.boolean(),
shareUrl: z.string().optional(),
error: z.string().optional(),
+ isNewShare: z.boolean().optional(),
+ manageUrl: z.string().optional(),
})
export type ShareResponse = z.infer
diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts
index e48aeab4f5..10384db8ed 100644
--- a/packages/types/src/experiment.ts
+++ b/packages/types/src/experiment.ts
@@ -6,7 +6,7 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js"
* ExperimentId
*/
-export const experimentIds = ["powerSteering", "disableCompletionCommand", "multiFileApplyDiff"] as const
+export const experimentIds = ["powerSteering", "multiFileApplyDiff"] as const
export const experimentIdsSchema = z.enum(experimentIds)
@@ -18,7 +18,6 @@ export type ExperimentId = z.infer
export const experimentsSchema = z.object({
powerSteering: z.boolean().optional(),
- disableCompletionCommand: z.boolean().optional(),
multiFileApplyDiff: z.boolean().optional(),
})
diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts
index 5b729a125f..bfd071a755 100644
--- a/packages/types/src/global-settings.ts
+++ b/packages/types/src/global-settings.ts
@@ -103,6 +103,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/provider-settings.ts b/packages/types/src/provider-settings.ts
index 2238081ea4..adc474ddd8 100644
--- a/packages/types/src/provider-settings.ts
+++ b/packages/types/src/provider-settings.ts
@@ -9,6 +9,7 @@ import { codebaseIndexProviderSchema } from "./codebase-index.js"
export const providerNames = [
"anthropic",
+ "claude-code",
"glama",
"openrouter",
"bedrock",
@@ -76,6 +77,10 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({
anthropicUseAuthToken: z.boolean().optional(),
})
+const claudeCodeSchema = apiModelIdProviderModelSchema.extend({
+ claudeCodePath: z.string().optional(),
+})
+
const glamaSchema = baseProviderSettingsSchema.extend({
glamaModelId: z.string().optional(),
glamaApiKey: z.string().optional(),
@@ -214,6 +219,7 @@ const defaultSchema = z.object({
export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [
anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })),
+ claudeCodeSchema.merge(z.object({ apiProvider: z.literal("claude-code") })),
glamaSchema.merge(z.object({ apiProvider: z.literal("glama") })),
openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })),
bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })),
@@ -240,6 +246,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
export const providerSettingsSchema = z.object({
apiProvider: providerNamesSchema.optional(),
...anthropicSchema.shape,
+ ...claudeCodeSchema.shape,
...glamaSchema.shape,
...openRouterSchema.shape,
...bedrockSchema.shape,
diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts
new file mode 100644
index 0000000000..ebf053a532
--- /dev/null
+++ b/packages/types/src/providers/claude-code.ts
@@ -0,0 +1,13 @@
+import type { ModelInfo } from "../model.js"
+import { anthropicModels } from "./anthropic.js"
+
+// Claude Code
+export type ClaudeCodeModelId = keyof typeof claudeCodeModels
+export const claudeCodeDefaultModelId: ClaudeCodeModelId = "claude-sonnet-4-20250514"
+export const claudeCodeModels = {
+ "claude-sonnet-4-20250514": anthropicModels["claude-sonnet-4-20250514"],
+ "claude-opus-4-20250514": anthropicModels["claude-opus-4-20250514"],
+ "claude-3-7-sonnet-20250219": anthropicModels["claude-3-7-sonnet-20250219"],
+ "claude-3-5-sonnet-20241022": anthropicModels["claude-3-5-sonnet-20241022"],
+ "claude-3-5-haiku-20241022": anthropicModels["claude-3-5-haiku-20241022"],
+} as const satisfies Record
diff --git a/packages/types/src/providers/gemini.ts b/packages/types/src/providers/gemini.ts
index e2efdf3f08..a7225c7330 100644
--- a/packages/types/src/providers/gemini.ts
+++ b/packages/types/src/providers/gemini.ts
@@ -53,9 +53,9 @@ export const geminiModels = {
contextWindow: 1_048_576,
supportsImages: true,
supportsPromptCache: true,
- inputPrice: 0.15,
- outputPrice: 0.6,
- cacheReadsPrice: 0.0375,
+ inputPrice: 0.3,
+ outputPrice: 2.5,
+ cacheReadsPrice: 0.075,
cacheWritesPrice: 1.0,
maxThinkingTokens: 24_576,
supportsReasoningBudget: true,
diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts
index 5f1c08041f..267401bd91 100644
--- a/packages/types/src/providers/index.ts
+++ b/packages/types/src/providers/index.ts
@@ -1,6 +1,7 @@
export * from "./anthropic.js"
export * from "./bedrock.js"
export * from "./chutes.js"
+export * from "./claude-code.js"
export * from "./deepseek.js"
export * from "./gemini.js"
export * from "./glama.js"
@@ -8,6 +9,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 f83bbc1039..9e39ae5608 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 0000000000..d269da8f4d
--- /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/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts
index b264fc8175..b048c19403 100644
--- a/packages/types/src/providers/vertex.ts
+++ b/packages/types/src/providers/vertex.ts
@@ -30,8 +30,10 @@ export const vertexModels = {
contextWindow: 1_048_576,
supportsImages: true,
supportsPromptCache: true,
- inputPrice: 0.15,
- outputPrice: 0.6,
+ inputPrice: 0.3,
+ outputPrice: 2.5,
+ cacheReadsPrice: 0.075,
+ cacheWritesPrice: 1.0,
maxThinkingTokens: 24_576,
supportsReasoningBudget: true,
},
diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts
index 4f6dfbfa85..e6640e9bb6 100644
--- a/packages/types/src/vscode.ts
+++ b/packages/types/src/vscode.ts
@@ -51,6 +51,7 @@ export const commandIds = [
"focusInput",
"acceptInput",
+ "focusPanel",
] as const
export type CommandId = (typeof commandIds)[number]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 391b356d0f..7ab6e2821f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6,6 +6,9 @@ settings:
overrides:
tar-fs: '>=2.1.3'
+ esbuild: '>=0.25.0'
+ undici: '>=5.29.0'
+ brace-expansion: '>=2.0.2'
importers:
@@ -21,7 +24,7 @@ importers:
specifier: 3.3.2
version: 3.3.2
esbuild:
- specifier: ^0.25.0
+ specifier: '>=0.25.0'
version: 0.25.5
eslint:
specifier: ^9.27.0
@@ -165,8 +168,8 @@ importers:
specifier: ^3.1.0
version: 3.1.0
lucide-react:
- specifier: ^0.513.0
- version: 0.513.0(react@18.3.1)
+ specifier: ^0.518.0
+ version: 0.518.0(react@18.3.1)
next:
specifier: ^15.2.5
version: 15.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -230,7 +233,7 @@ importers:
version: 4.1.6
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@22.15.29)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
apps/web-roo-code:
dependencies:
@@ -268,8 +271,8 @@ importers:
specifier: ^12.15.0
version: 12.16.0(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
lucide-react:
- specifier: ^0.513.0
- version: 0.513.0(react@18.3.1)
+ specifier: ^0.518.0
+ version: 0.518.0(react@18.3.1)
next:
specifier: ^15.2.5
version: 15.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -346,7 +349,7 @@ importers:
version: 20.17.57
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages/cloud:
dependencies:
@@ -377,7 +380,7 @@ importers:
version: 1.100.0
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages/config-eslint:
devDependencies:
@@ -479,7 +482,7 @@ importers:
version: 4.19.4
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages/ipc:
dependencies:
@@ -504,7 +507,7 @@ importers:
version: 9.2.3
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages/telemetry:
dependencies:
@@ -512,8 +515,8 @@ importers:
specifier: workspace:^
version: link:../types
posthog-node:
- specifier: ^4.7.0
- version: 4.17.2
+ specifier: ^5.0.0
+ version: 5.1.1
zod:
specifier: ^3.25.61
version: 3.25.61
@@ -532,7 +535,7 @@ importers:
version: 1.100.0
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages/types:
dependencies:
@@ -554,7 +557,7 @@ importers:
version: 8.5.0(jiti@2.4.2)(postcss@8.5.4)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0)
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
src:
dependencies:
@@ -576,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)
@@ -676,8 +682,8 @@ importers:
specifier: ^12.0.0
version: 12.0.0
openai:
- specifier: ^4.78.1
- version: 4.103.0(ws@8.18.2)(zod@3.25.61)
+ specifier: ^5.0.0
+ version: 5.5.1(ws@8.18.2)(zod@3.25.61)
os-name:
specifier: ^6.0.0
version: 6.1.0
@@ -691,17 +697,17 @@ importers:
specifier: ^1.1.1
version: 1.1.1
pkce-challenge:
- specifier: ^4.1.0
- version: 4.1.0
+ 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
puppeteer-chromium-resolver:
- specifier: ^23.0.0
- version: 23.0.0
+ specifier: ^24.0.0
+ version: 24.0.1
puppeteer-core:
specifier: ^23.4.0
version: 23.11.1
@@ -715,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
@@ -821,8 +827,8 @@ importers:
specifier: 3.3.2
version: 3.3.2
esbuild:
- specifier: ^0.25.0
- version: 0.25.4
+ specifier: '>=0.25.0'
+ version: 0.25.5
execa:
specifier: ^9.5.2
version: 9.5.3
@@ -855,7 +861,7 @@ importers:
version: 5.8.3
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.50)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.50)(@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)
zod-to-ts:
specifier: ^1.2.0
version: 1.2.0(typescript@5.8.3)(zod@3.25.61)
@@ -949,6 +955,9 @@ importers:
i18next-http-backend:
specifier: ^3.0.2
version: 3.0.2
+ katex:
+ specifier: ^0.16.11
+ version: 0.16.22
knuth-shuffle-seeded:
specifier: ^1.0.6
version: 1.0.6
@@ -956,8 +965,8 @@ importers:
specifier: ^11.1.0
version: 11.1.0
lucide-react:
- specifier: ^0.513.0
- version: 0.513.0(react@18.3.1)
+ specifier: ^0.518.0
+ version: 0.518.0(react@18.3.1)
mermaid:
specifier: ^11.4.1
version: 11.6.0
@@ -965,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
@@ -994,9 +1003,15 @@ importers:
rehype-highlight:
specifier: ^7.0.0
version: 7.0.2
+ rehype-katex:
+ specifier: ^7.0.1
+ version: 7.0.1
remark-gfm:
specifier: ^4.0.1
version: 4.0.1
+ remark-math:
+ specifier: ^6.0.0
+ version: 6.0.0
remove-markdown:
specifier: ^0.6.0
version: 0.6.2
@@ -1013,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
@@ -1037,9 +1052,6 @@ importers:
specifier: ^3.25.61
version: 3.25.61
devDependencies:
- '@jest/globals':
- specifier: ^29.7.0
- version: 29.7.0
'@roo-code/config-eslint':
specifier: workspace:^
version: link:../packages/config-eslint
@@ -1058,6 +1070,9 @@ importers:
'@types/jest':
specifier: ^29.0.0
version: 29.5.14
+ '@types/katex':
+ specifier: ^0.16.7
+ version: 0.16.7
'@types/node':
specifier: 20.x
version: 20.17.57
@@ -1070,30 +1085,21 @@ importers:
'@types/shell-quote':
specifier: ^1.7.5
version: 1.7.5
- '@types/testing-library__jest-dom':
- specifier: ^5.14.5
- version: 5.14.9
'@types/vscode-webview':
specifier: ^1.57.5
version: 1.57.5
'@vitejs/plugin-react':
specifier: ^4.3.4
version: 4.4.1(vite@6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/ui':
+ specifier: ^3.2.3
+ version: 3.2.4(vitest@3.2.4)
identity-obj-proxy:
specifier: ^3.0.0
version: 3.0.0
- jest:
- specifier: ^29.7.0
- version: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- jest-environment-jsdom:
- specifier: ^29.7.0
- version: 29.7.0
- jest-simple-dot-reporter:
- specifier: ^1.0.5
- version: 1.0.5
- ts-jest:
- specifier: ^29.2.5
- version: 29.3.3(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.5)(jest@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0))(typescript@5.8.3)
+ jsdom:
+ specifier: ^26.0.0
+ version: 26.1.0
typescript:
specifier: 5.8.3
version: 5.8.3
@@ -1102,7 +1108,7 @@ importers:
version: 6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
vitest:
specifier: ^3.2.3
- version: 3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 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)
packages:
@@ -1132,6 +1138,9 @@ packages:
'@anthropic-ai/vertex-sdk@0.7.0':
resolution: {integrity: sha512-zNm3hUXgYmYDTyveIxOyxbcnh5VXFkrLo4bSnG6LAfGzW7k3k2iCNDSVKtR9qZrK2BCid7JtVu7jsEKaZ/9dSw==}
+ '@asamuzakjp/css-color@3.2.0':
+ resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
+
'@aws-crypto/crc32@3.0.0':
resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
@@ -1375,97 +1384,6 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/plugin-syntax-async-generators@7.8.4':
- resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-bigint@7.8.3':
- resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-properties@7.12.13':
- resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-class-static-block@7.14.5':
- resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-attributes@7.27.1':
- resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-import-meta@7.10.4':
- resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-json-strings@7.8.3':
- resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-jsx@7.27.1':
- resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
- resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
- resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-numeric-separator@7.10.4':
- resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3':
- resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3':
- resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-optional-chaining@7.8.3':
- resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5':
- resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-top-level-await@7.14.5':
- resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
- '@babel/plugin-syntax-typescript@7.27.1':
- resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-transform-react-jsx-self@7.27.1':
resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
engines: {node: '>=6.9.0'}
@@ -1578,6 +1496,34 @@ packages:
'@chevrotain/utils@11.0.3':
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
+ '@csstools/color-helpers@5.0.2':
+ resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-calc@2.1.4':
+ resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-color-parser@3.0.10':
+ resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5':
+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-tokenizer@3.0.4':
+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ engines: {node: '>=18'}
+
'@dotenvx/dotenvx@1.44.2':
resolution: {integrity: sha512-2C44+G2dch4cB6zw7+oGQ9VcFQuuVhc5xOzfVvY7iUEj2PRhiVMIB6SpNMK1V5TvpdqrAqCYFjclK18Mh9vwNQ==}
hasBin: true
@@ -1617,432 +1563,150 @@ packages:
resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==}
deprecated: 'Merged into tsx: https://tsx.is'
- '@esbuild/aix-ppc64@0.25.4':
- resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
'@esbuild/aix-ppc64@0.25.5':
resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.18.20':
- resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
-
- '@esbuild/android-arm64@0.25.4':
- resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
'@esbuild/android-arm64@0.25.5':
resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.18.20':
- resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
-
- '@esbuild/android-arm@0.25.4':
- resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
'@esbuild/android-arm@0.25.5':
resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.18.20':
- resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
-
- '@esbuild/android-x64@0.25.4':
- resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
'@esbuild/android-x64@0.25.5':
resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.18.20':
- resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
-
- '@esbuild/darwin-arm64@0.25.4':
- resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
'@esbuild/darwin-arm64@0.25.5':
resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.18.20':
- resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
-
- '@esbuild/darwin-x64@0.25.4':
- resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
'@esbuild/darwin-x64@0.25.5':
resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.18.20':
- resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
-
- '@esbuild/freebsd-arm64@0.25.4':
- resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
'@esbuild/freebsd-arm64@0.25.5':
resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.18.20':
- resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
-
- '@esbuild/freebsd-x64@0.25.4':
- resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
'@esbuild/freebsd-x64@0.25.5':
resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.18.20':
- resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
-
- '@esbuild/linux-arm64@0.25.4':
- resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
'@esbuild/linux-arm64@0.25.5':
resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.18.20':
- resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
-
- '@esbuild/linux-arm@0.25.4':
- resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
'@esbuild/linux-arm@0.25.5':
resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.18.20':
- resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
-
- '@esbuild/linux-ia32@0.25.4':
- resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
'@esbuild/linux-ia32@0.25.5':
resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.18.20':
- resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
-
- '@esbuild/linux-loong64@0.25.4':
- resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
'@esbuild/linux-loong64@0.25.5':
resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.18.20':
- resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
-
- '@esbuild/linux-mips64el@0.25.4':
- resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
'@esbuild/linux-mips64el@0.25.5':
resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.18.20':
- resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
-
- '@esbuild/linux-ppc64@0.25.4':
- resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
'@esbuild/linux-ppc64@0.25.5':
resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.18.20':
- resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
-
- '@esbuild/linux-riscv64@0.25.4':
- resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
'@esbuild/linux-riscv64@0.25.5':
resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.18.20':
- resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
-
- '@esbuild/linux-s390x@0.25.4':
- resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
'@esbuild/linux-s390x@0.25.5':
resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.18.20':
- resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
-
- '@esbuild/linux-x64@0.25.4':
- resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
'@esbuild/linux-x64@0.25.5':
resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.25.4':
- resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
'@esbuild/netbsd-arm64@0.25.5':
resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.18.20':
- resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
-
- '@esbuild/netbsd-x64@0.25.4':
- resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
'@esbuild/netbsd-x64@0.25.5':
resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.25.4':
- resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
'@esbuild/openbsd-arm64@0.25.5':
resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.18.20':
- resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
-
- '@esbuild/openbsd-x64@0.25.4':
- resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
'@esbuild/openbsd-x64@0.25.5':
resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/sunos-x64@0.18.20':
- resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
-
- '@esbuild/sunos-x64@0.25.4':
- resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
'@esbuild/sunos-x64@0.25.5':
resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.18.20':
- resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
-
- '@esbuild/win32-arm64@0.25.4':
- resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
'@esbuild/win32-arm64@0.25.5':
resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.18.20':
- resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
-
- '@esbuild/win32-ia32@0.25.4':
- resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
'@esbuild/win32-ia32@0.25.5':
resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.18.20':
- resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
-
- '@esbuild/win32-x64@0.25.4':
- resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
'@esbuild/win32-x64@0.25.5':
resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==}
engines: {node: '>=18'}
@@ -2097,10 +1761,6 @@ packages:
'@fast-csv/parse@4.3.6':
resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==}
- '@fastify/busboy@2.1.1':
- resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
- engines: {node: '>=14'}
-
'@floating-ui/core@1.7.0':
resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==}
@@ -2266,76 +1926,18 @@ packages:
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'}
- '@istanbuljs/load-nyc-config@1.1.0':
- resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
- engines: {node: '>=8'}
-
'@istanbuljs/schema@0.1.3':
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
- '@jest/console@29.7.0':
- resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/core@29.7.0':
- resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- '@jest/environment@29.7.0':
- resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
'@jest/expect-utils@29.7.0':
resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- '@jest/expect@29.7.0':
- resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/fake-timers@29.7.0':
- resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/globals@29.7.0':
- resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/reporters@29.7.0':
- resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
'@jest/schemas@29.6.3':
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- '@jest/source-map@29.6.3':
- resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-result@29.7.0':
- resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/test-sequencer@29.7.0':
- resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- '@jest/transform@29.7.0':
- resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
'@jest/types@29.6.3':
resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -2425,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==}
@@ -2723,6 +2331,9 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
+ '@polka/url@1.0.0-next.29':
+ resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
+
'@puppeteer/browsers@2.10.5':
resolution: {integrity: sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==}
engines: {node: '>=18'}
@@ -3470,12 +3081,6 @@ packages:
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
engines: {node: '>=18'}
- '@sinonjs/commons@3.0.1':
- resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
-
- '@sinonjs/fake-timers@10.3.0':
- resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
-
'@smithy/abort-controller@2.2.0':
resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==}
engines: {node: '>=14.0.0'}
@@ -4022,10 +3627,6 @@ packages:
peerDependencies:
'@testing-library/dom': '>=7.21.4'
- '@tootallnate/once@2.0.0':
- resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
- engines: {node: '>= 10'}
-
'@tootallnate/quickjs-emscripten@0.23.0':
resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
@@ -4173,9 +3774,6 @@ packages:
'@types/glob@8.1.0':
resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
- '@types/graceful-fs@4.1.9':
- resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
-
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
@@ -4194,12 +3792,12 @@ packages:
'@types/js-cookie@2.2.7':
resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==}
- '@types/jsdom@20.0.1':
- resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==}
-
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ '@types/katex@0.16.7':
+ resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
+
'@types/lodash.debounce@4.0.9':
resolution: {integrity: sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==}
@@ -4246,15 +3844,12 @@ 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==}
- '@types/parse-json@4.0.2':
- resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
-
'@types/prop-types@15.7.14':
resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
@@ -4281,15 +3876,9 @@ packages:
'@types/stylis@4.2.5':
resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==}
- '@types/testing-library__jest-dom@5.14.9':
- resolution: {integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==}
-
'@types/tmp@0.2.6':
resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==}
- '@types/tough-cookie@4.0.5':
- resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
-
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -4383,11 +3972,11 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
- '@vitest/expect@3.2.3':
- resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==}
+ '@vitest/expect@3.2.4':
+ resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
- '@vitest/mocker@3.2.3':
- resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==}
+ '@vitest/mocker@3.2.4':
+ resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
@@ -4397,20 +3986,25 @@ packages:
vite:
optional: true
- '@vitest/pretty-format@3.2.3':
- resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==}
+ '@vitest/pretty-format@3.2.4':
+ resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
- '@vitest/runner@3.2.3':
- resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==}
+ '@vitest/runner@3.2.4':
+ resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
- '@vitest/snapshot@3.2.3':
- resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==}
+ '@vitest/snapshot@3.2.4':
+ resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
- '@vitest/spy@3.2.3':
- resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==}
+ '@vitest/spy@3.2.4':
+ resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
- '@vitest/utils@3.2.3':
- resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==}
+ '@vitest/ui@3.2.4':
+ resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==}
+ peerDependencies:
+ vitest: 3.2.4
+
+ '@vitest/utils@3.2.4':
+ resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
'@vscode/codicons@0.0.36':
resolution: {integrity: sha512-wsNOvNMMJ2BY8rC2N2MNBG7yOowV3ov8KlvUE/AiVUlHKTfWsw3OgAOQduX7h0Un6GssKD3aoTVH+TF3DSQwKQ==}
@@ -4490,10 +4084,6 @@ packages:
'@xobotyi/scrollbar-width@1.9.5':
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
- abab@2.0.6:
- resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
- deprecated: Use your platform's native atob() and btoa() methods instead
-
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
@@ -4502,18 +4092,11 @@ packages:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'}
- acorn-globals@7.0.1:
- resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
-
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn-walk@8.3.4:
- resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
- engines: {node: '>=0.4.0'}
-
acorn@8.14.1:
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
engines: {node: '>=0.4.0'}
@@ -4524,10 +4107,6 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
- agent-base@6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
-
agent-base@7.1.3:
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
engines: {node: '>= 14'}
@@ -4543,10 +4122,6 @@ packages:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
- ansi-escapes@4.3.2:
- resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
- engines: {node: '>=8'}
-
ansi-escapes@7.0.0:
resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==}
engines: {node: '>=18'}
@@ -4690,43 +4265,15 @@ packages:
b4a@1.6.7:
resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
- babel-jest@29.7.0:
- resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.8.0
-
- babel-plugin-istanbul@6.1.1:
- resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
- engines: {node: '>=8'}
-
- babel-plugin-jest-hoist@29.6.3:
- resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- babel-plugin-macros@3.1.0:
- resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
- engines: {node: '>=10', npm: '>=6'}
-
- babel-preset-current-node-syntax@1.1.0:
- resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- babel-preset-jest@29.6.3:
- resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@babel/core': ^7.0.0
-
bail@1.0.5:
resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==}
bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
- balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ balanced-match@3.0.1:
+ resolution: {integrity: sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==}
+ engines: {node: '>= 16'}
bare-events@2.5.4:
resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==}
@@ -4805,11 +4352,9 @@ packages:
bowser@2.11.0:
resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
-
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ brace-expansion@4.0.1:
+ resolution: {integrity: sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==}
+ engines: {node: '>= 18'}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
@@ -4823,13 +4368,6 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
- bs-logger@0.2.6:
- resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
- engines: {node: '>= 6'}
-
- bser@2.1.1:
- resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
-
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
@@ -4858,7 +4396,7 @@ packages:
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
- esbuild: '>=0.18'
+ esbuild: '>=0.25.0'
busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
@@ -4897,10 +4435,6 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
-
camelcase@6.3.0:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
@@ -4937,10 +4471,6 @@ packages:
resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
- char-regex@1.0.2:
- resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
- engines: {node: '>=10'}
-
character-entities-html4@2.1.0:
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
@@ -5001,6 +4531,11 @@ packages:
peerDependencies:
devtools-protocol: '*'
+ chromium-bidi@5.1.0:
+ resolution: {integrity: sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==}
+ peerDependencies:
+ devtools-protocol: '*'
+
ci-info@2.0.0:
resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
@@ -5008,9 +4543,6 @@ packages:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'}
- cjs-module-lexer@1.4.3:
- resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}
-
class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
@@ -5061,17 +4593,10 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
- co@4.6.0:
- resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
- engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
-
cockatiel@3.2.1:
resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==}
engines: {node: '>=16'}
- collect-v8-coverage@1.0.2:
- resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
-
color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@@ -5141,9 +4666,6 @@ packages:
resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==}
engines: {node: '>= 10'}
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
-
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
@@ -5199,10 +4721,6 @@ packages:
cose-base@2.2.0:
resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==}
- cosmiconfig@7.1.0:
- resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
- engines: {node: '>=10'}
-
crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
@@ -5212,11 +4730,6 @@ packages:
resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==}
engines: {node: '>= 10'}
- create-jest@29.7.0:
- resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
-
cross-fetch@4.0.0:
resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
@@ -5253,15 +4766,9 @@ packages:
engines: {node: '>=4'}
hasBin: true
- cssom@0.3.8:
- resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
-
- cssom@0.5.0:
- resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
-
- cssstyle@2.3.0:
- resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
- engines: {node: '>=8'}
+ cssstyle@4.4.0:
+ resolution: {integrity: sha512-W0Y2HOXlPkb2yaKrCVRjinYKciu/qSLEmK0K9mcfDei3zwlnHFEHAs/Du3cIRwPqY+J4JsiBzUjoHyc8RsJ03A==}
+ engines: {node: '>=18'}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -5430,9 +4937,9 @@ packages:
resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
engines: {node: '>= 14'}
- data-urls@3.0.2:
- resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
- engines: {node: '>=12'}
+ data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
@@ -5490,14 +4997,6 @@ packages:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
- dedent@1.6.0:
- resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==}
- peerDependencies:
- babel-plugin-macros: ^3.1.0
- peerDependenciesMeta:
- babel-plugin-macros:
- optional: true
-
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
@@ -5509,10 +5008,6 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
- deepmerge@4.3.1:
- resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
- engines: {node: '>=0.10.0'}
-
default-browser-id@5.0.0:
resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
engines: {node: '>=18'}
@@ -5572,10 +5067,6 @@ packages:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
- detect-newline@3.1.0:
- resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
- engines: {node: '>=8'}
-
detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
@@ -5585,6 +5076,9 @@ packages:
devtools-protocol@0.0.1367902:
resolution: {integrity: sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==}
+ devtools-protocol@0.0.1452169:
+ resolution: {integrity: sha512-FOFDVMGrAUNp0dDKsAU1TorWJUx2JOU1k9xdgBKKJF3IBh/Uhl2yswG5r3TEAOrCiGY2QRp1e6LVDQrCsTKO4g==}
+
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
@@ -5628,11 +5122,6 @@ packages:
domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
- domexception@4.0.0:
- resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
- engines: {node: '>=12'}
- deprecated: Use your platform's native DOMException instead
-
domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
@@ -5780,11 +5269,6 @@ packages:
eight-colors@1.3.1:
resolution: {integrity: sha512-7nXPYDeKh6DgJDR/mpt2G7N/hCNSGwwoPVmoI3+4TEwOb07VFN1WMPG0DFf6nMEjrkgdj8Og7l7IaEEk3VE6Zg==}
- ejs@3.1.10:
- resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
- engines: {node: '>=0.10.0'}
- hasBin: true
-
electron-to-chromium@1.5.152:
resolution: {integrity: sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==}
@@ -5811,10 +5295,6 @@ packages:
embla-carousel@8.6.0:
resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==}
- emittery@0.13.1:
- resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
- engines: {node: '>=12'}
-
emoji-regex@10.4.0:
resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
@@ -5858,9 +5338,6 @@ packages:
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
engines: {node: '>=18'}
- error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
-
error-stack-parser@2.1.4:
resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==}
@@ -5902,17 +5379,7 @@ packages:
esbuild-register@3.6.0:
resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==}
peerDependencies:
- esbuild: '>=0.12 <1'
-
- esbuild@0.18.20:
- resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
- engines: {node: '>=12'}
- hasBin: true
-
- esbuild@0.25.4:
- resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
- engines: {node: '>=18'}
- hasBin: true
+ esbuild: '>=0.25.0'
esbuild@0.25.5:
resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==}
@@ -6102,10 +5569,6 @@ packages:
exenv-es6@1.1.1:
resolution: {integrity: sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==}
- exit@0.1.2:
- resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
- engines: {node: '>= 0.8.0'}
-
expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
@@ -6195,9 +5658,6 @@ packages:
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
- fb-watchman@2.0.2:
- resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
-
fd-package-json@2.0.0:
resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==}
@@ -6227,6 +5687,9 @@ packages:
fflate@0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
+ fflate@0.8.2:
+ resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
+
figures@6.1.0:
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
engines: {node: '>=18'}
@@ -6238,9 +5701,6 @@ packages:
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
- filelist@1.0.4:
- resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
-
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
@@ -6419,10 +5879,6 @@ packages:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
- get-package-type@0.1.0:
- resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
- engines: {node: '>=8.0.0'}
-
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
@@ -6567,9 +6023,24 @@ packages:
hast-to-hyperscript@9.0.1:
resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==}
+ hast-util-from-dom@5.0.1:
+ resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==}
+
+ hast-util-from-html-isomorphic@2.0.0:
+ resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==}
+
+ hast-util-from-html@2.0.3:
+ resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
+
+ hast-util-from-parse5@8.0.3:
+ resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
+
hast-util-is-element@3.0.0:
resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
+ hast-util-parse-selector@4.0.0:
+ resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
+
hast-util-to-html@9.0.5:
resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
@@ -6582,6 +6053,9 @@ packages:
hast-util-whitespace@3.0.0:
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+ hastscript@9.0.1:
+ resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
+
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
@@ -6597,9 +6071,9 @@ packages:
howler@2.2.4:
resolution: {integrity: sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==}
- html-encoding-sniffer@3.0.0:
- resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
- engines: {node: '>=12'}
+ html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
@@ -6620,18 +6094,10 @@ packages:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
- http-proxy-agent@5.0.0:
- resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
- engines: {node: '>= 6'}
-
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
- https-proxy-agent@5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
-
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
@@ -6708,11 +6174,6 @@ packages:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
- import-local@3.2.0:
- resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
- engines: {node: '>=8'}
- hasBin: true
-
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -6775,9 +6236,6 @@ packages:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
- is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
-
is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
@@ -6852,10 +6310,6 @@ packages:
resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
engines: {node: '>=18'}
- is-generator-fn@2.1.0:
- resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
- engines: {node: '>=6'}
-
is-generator-function@1.1.0:
resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
engines: {node: '>= 0.4'}
@@ -7016,22 +6470,10 @@ packages:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
- istanbul-lib-instrument@5.2.1:
- resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
- engines: {node: '>=8'}
-
- istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
-
istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
- istanbul-lib-source-maps@4.0.1:
- resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
- engines: {node: '>=10'}
-
istanbul-reports@3.1.7:
resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
engines: {node: '>=8'}
@@ -7047,78 +6489,14 @@ packages:
resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==}
engines: {node: 20 || >=22}
- jake@10.9.2:
- resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
- engines: {node: '>=10'}
- hasBin: true
-
- jest-changed-files@29.7.0:
- resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-circus@29.7.0:
- resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-cli@29.7.0:
- resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
- jest-config@29.7.0:
- resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- '@types/node': '*'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- '@types/node':
- optional: true
- ts-node:
- optional: true
-
jest-diff@29.7.0:
resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jest-docblock@29.7.0:
- resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-each@29.7.0:
- resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-environment-jsdom@29.7.0:
- resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- peerDependencies:
- canvas: ^2.5.0
- peerDependenciesMeta:
- canvas:
- optional: true
-
- jest-environment-node@29.7.0:
- resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
jest-get-type@29.6.3:
resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jest-haste-map@29.7.0:
- resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-leak-detector@29.7.0:
- resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
jest-matcher-utils@29.7.0:
resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -7127,72 +6505,10 @@ packages:
resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jest-mock@29.7.0:
- resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-pnp-resolver@1.2.3:
- resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
- engines: {node: '>=6'}
- peerDependencies:
- jest-resolve: '*'
- peerDependenciesMeta:
- jest-resolve:
- optional: true
-
- jest-regex-util@29.6.3:
- resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve-dependencies@29.7.0:
- resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-resolve@29.7.0:
- resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runner@29.7.0:
- resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-runtime@29.7.0:
- resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-simple-dot-reporter@1.0.5:
- resolution: {integrity: sha512-cZLFG/C7k0+WYoIGGuGXKm0vmJiXlWG/m3uCZ4RaMPYxt8lxjdXMLHYkxXaQ7gVWaSPe7uAPCEUcRxthC5xskg==}
-
- jest-snapshot@29.7.0:
- resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
jest-util@29.7.0:
resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jest-validate@29.7.0:
- resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-watcher@29.7.0:
- resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest-worker@29.7.0:
- resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
- jest@29.7.0:
- resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- hasBin: true
- peerDependencies:
- node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
- peerDependenciesMeta:
- node-notifier:
- optional: true
-
jiti@1.21.7:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
@@ -7236,11 +6552,11 @@ packages:
jsbn@1.1.0:
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
- jsdom@20.0.3:
- resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==}
- engines: {node: '>=14'}
+ jsdom@26.1.0:
+ resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
+ engines: {node: '>=18'}
peerDependencies:
- canvas: ^2.5.0
+ canvas: ^3.0.0
peerDependenciesMeta:
canvas:
optional: true
@@ -7256,9 +6572,6 @@ packages:
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
- json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
-
json-parse-even-better-errors@4.0.0:
resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -7283,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'}
@@ -7323,10 +6639,6 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
- kleur@3.0.3:
- resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
- engines: {node: '>=6'}
-
knip@5.60.2:
resolution: {integrity: sha512-TsYqEsoL3802RmhGL5MN7RLI6/03kocMYx/4BpMmwo3dSwEJxmzV7HqRxMVZr6c1llbd25+MqjgA86bv1IwsPA==}
engines: {node: '>=18.18.0'}
@@ -7592,9 +6904,6 @@ packages:
lodash.isundefined@3.0.1:
resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==}
- lodash.memoize@4.1.2:
- resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
-
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
@@ -7641,6 +6950,9 @@ packages:
loupe@3.1.3:
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
+ loupe@3.1.4:
+ resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
+
lowlight@3.3.0:
resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==}
@@ -7662,8 +6974,8 @@ packages:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
- lucide-react@0.513.0:
- resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==}
+ lucide-react@0.518.0:
+ resolution: {integrity: sha512-kFg34uQqnVl/7HwAiigxPSpj//43VIVHQbMygQPtS1yT4btMXHCWUipHcgcXHD2pm1Z2nUBA/M+Vnh/YmWXQUw==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -7682,12 +6994,6 @@ packages:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
- make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
- makeerror@1.0.12:
- resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
-
mammoth@1.9.0:
resolution: {integrity: sha512-F+0NxzankQV9XSUAuVKvkdQK0GbtGGuqVnND9aVf9VSeUA82LQa29GjLqYU6Eez8LHqSJG3eGiDW3224OKdpZg==}
engines: {node: '>=12.0.0'}
@@ -7742,6 +7048,9 @@ packages:
mdast-util-gfm@3.1.0:
resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
+ mdast-util-math@3.0.0:
+ resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==}
+
mdast-util-mdx-expression@2.0.1:
resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
@@ -7824,6 +7133,9 @@ packages:
micromark-extension-gfm@3.0.0:
resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
+ micromark-extension-math@3.1.0:
+ resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==}
+
micromark-factory-destination@2.0.1:
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
@@ -8002,6 +7314,10 @@ packages:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
+ mrmime@2.0.1:
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+ engines: {node: '>=10'}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -8103,9 +7419,6 @@ packages:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- node-int64@0.4.0:
- resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
-
node-ipc@12.0.0:
resolution: {integrity: sha512-QHJ2gAJiqA3cM7cQiRjLsfCOBRB0TwQ6axYD4FSllQWipEbP6i7Se1dP8EzPKk5J1nCe27W69eqPmCoKyQ61Vg==}
engines: {node: '>=14'}
@@ -8223,8 +7536,8 @@ packages:
resolution: {integrity: sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==}
engines: {node: '>=18'}
- openai@4.103.0:
- resolution: {integrity: sha512-eWcz9kdurkGOFDtd5ySS5y251H2uBgq9+1a2lTBnjMMzlexJ40Am5t6Mu76SSE87VvitPa0dkIAp75F+dZVC0g==}
+ openai@5.5.1:
+ resolution: {integrity: sha512-5i19097mGotHA1eFsM6Tjd/tJ8uo9sa5Ysv4Q6bKJ2vtN6rc0MzMrUefXnLXYAJcmMQrC1Efhj0AvfIkXrQamw==}
hasBin: true
peerDependencies:
ws: ^8.18.0
@@ -8350,10 +7663,6 @@ packages:
parse-entities@4.0.2:
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
- parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
-
parse-ms@4.0.0:
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
engines: {node: '>=18'}
@@ -8457,18 +7766,10 @@ packages:
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
engines: {node: '>= 6'}
- pkce-challenge@4.1.0:
- resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==}
- engines: {node: '>=16.20.0'}
-
pkce-challenge@5.0.0:
resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==}
engines: {node: '>=16.20.0'}
- pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
-
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
@@ -8586,9 +7887,9 @@ packages:
rrweb-snapshot:
optional: true
- posthog-node@4.17.2:
- resolution: {integrity: sha512-bFmwOTk4QdYavopeHVXtyFGQ9vyLMVaNWkWocwjix+0n6sQgv7Zq5nYjYulz7ThmK18zsvNJ337ahuMLv3ulow==}
- engines: {node: '>=15.0.0'}
+ posthog-node@5.1.1:
+ resolution: {integrity: sha512-6VISkNdxO24ehXiDA4dugyCSIV7lpGVaEu5kn/dlAj+SJ1lgcDru9PQ8p/+GSXsXVxohd1t7kHL2JKc9NoGb0w==}
+ engines: {node: '>=20'}
preact@10.26.6:
resolution: {integrity: sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==}
@@ -8612,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==}
@@ -8638,10 +7939,6 @@ packages:
promise-limit@2.7.0:
resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==}
- prompts@2.4.2:
- resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
- engines: {node: '>= 6'}
-
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -8671,9 +7968,6 @@ packages:
engines: {node: '>= 0.10'}
hasBin: true
- psl@1.15.0:
- resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
-
pump@3.0.2:
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
@@ -8685,15 +7979,16 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- puppeteer-chromium-resolver@23.0.0:
- resolution: {integrity: sha512-PbSXK4ERPwp+eYm+SVY5vMWCxsdeJcddwz4avXvDx7kE9DLE+L86Xg027sypw2oan5yi6557brzVsbajcMmy2g==}
+ puppeteer-chromium-resolver@24.0.1:
+ resolution: {integrity: sha512-whu9e5qmnZekCP5hvlYMe7rWe4cU9seCISRlfT0vXGlCsy7psbeXHdGW6QdXrwyadvCTiD1Ft62jPaqia8ZQaA==}
puppeteer-core@23.11.1:
resolution: {integrity: sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==}
engines: {node: '>=18'}
- pure-rand@6.1.0:
- resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+ puppeteer-core@24.10.2:
+ resolution: {integrity: sha512-CnzhOgrZj8DvkDqI+Yx+9or33i3Y9uUYbKyYpP4C13jWwXx/keQ38RMTMmxuLCWQlxjZrOH0Foq7P2fGP7adDQ==}
+ engines: {node: '>=18'}
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
@@ -8702,9 +7997,6 @@ packages:
quansync@0.2.10:
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
- querystringify@2.2.0:
- resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
-
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -8928,12 +8220,18 @@ packages:
rehype-highlight@7.0.2:
resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==}
+ rehype-katex@7.0.1:
+ resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==}
+
rehype-react@6.2.1:
resolution: {integrity: sha512-f9KIrjktvLvmbGc7si25HepocOg4z0MuNOtweigKzBcDjiGSTGhyz6VSgaV5K421Cq1O+z4/oxRJ5G9owo0KVg==}
remark-gfm@4.0.1:
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
+ remark-math@6.0.0:
+ resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==}
+
remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
@@ -8956,16 +8254,9 @@ packages:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
- requires-port@1.0.0:
- resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
-
resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
- resolve-cwd@3.0.0:
- resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
- engines: {node: '>=8'}
-
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -8977,10 +8268,6 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
- resolve.exports@2.0.3:
- resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
- engines: {node: '>=10'}
-
resolve@1.22.10:
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
engines: {node: '>= 0.4'}
@@ -9026,6 +8313,9 @@ packages:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
+ rrweb-cssom@0.8.0:
+ resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
+
rtl-css-js@1.16.1:
resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
@@ -9105,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==}
@@ -9210,8 +8500,9 @@ packages:
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
- sisteransi@1.0.5:
- resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ sirv@3.0.1:
+ resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
+ engines: {node: '>=18'}
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
@@ -9254,9 +8545,6 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
- source-map-support@0.5.13:
- resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
-
source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
@@ -9341,10 +8629,6 @@ packages:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
engines: {node: '>=0.6.19'}
- string-length@4.0.2:
- resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
- engines: {node: '>=10'}
-
string-similarity@4.0.4:
resolution: {integrity: sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
@@ -9401,10 +8685,6 @@ packages:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
- strip-bom@4.0.0:
- resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
- engines: {node: '>=8'}
-
strip-bom@5.0.0:
resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==}
engines: {node: '>=12'}
@@ -9520,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==}
@@ -9611,8 +8888,8 @@ packages:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
- tinypool@1.1.0:
- resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==}
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@2.0.0:
@@ -9623,6 +8900,13 @@ packages:
resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==}
engines: {node: '>=14.0.0'}
+ tldts-core@6.1.86:
+ resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
+
+ tldts@6.1.86:
+ resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==}
+ hasBin: true
+
tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@@ -9631,9 +8915,6 @@ packages:
resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
engines: {node: '>=14.14'}
- tmpl@1.0.5:
- resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
-
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -9645,19 +8926,23 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
- tough-cookie@4.1.4:
- resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ totalist@3.0.1:
+ resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
+ tough-cookie@5.1.2:
+ resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
+ engines: {node: '>=16'}
+
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
- tr46@3.0.0:
- resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
- engines: {node: '>=12'}
+ tr46@5.1.1:
+ resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
+ engines: {node: '>=18'}
traverse@0.3.9:
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
@@ -9697,30 +8982,6 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- ts-jest@29.3.3:
- resolution: {integrity: sha512-y6jLm19SL4GroiBmHwFK4dSHUfDNmOrJbRfp6QmDIlI9p5tT5Q8ItccB4pTIslCIqOZuQnBwpTR0bQ5eUMYwkw==}
- engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@babel/core': '>=7.0.0-beta.0 <8'
- '@jest/transform': ^29.0.0
- '@jest/types': ^29.0.0
- babel-jest: ^29.0.0
- esbuild: '*'
- jest: ^29.0.0
- typescript: '>=4.3 <6'
- peerDependenciesMeta:
- '@babel/core':
- optional: true
- '@jest/transform':
- optional: true
- '@jest/types':
- optional: true
- babel-jest:
- optional: true
- esbuild:
- optional: true
-
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@@ -9802,18 +9063,6 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
-
- type-fest@0.21.3:
- resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
- engines: {node: '>=10'}
-
- 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'}
@@ -9881,10 +9130,6 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
- undici@5.28.5:
- resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==}
- engines: {node: '>=14.0'}
-
undici@6.21.3:
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
engines: {node: '>=18.17'}
@@ -9923,6 +9168,9 @@ packages:
unist-util-position@5.0.0:
resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+ unist-util-remove-position@5.0.0:
+ resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==}
+
unist-util-stringify-position@2.0.3:
resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==}
@@ -9951,10 +9199,6 @@ packages:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
- universalify@0.2.0:
- resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
- engines: {node: '>= 4.0.0'}
-
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
@@ -9978,9 +9222,6 @@ packages:
url-join@4.0.1:
resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
- url-parse@1.5.10:
- resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
-
use-callback-ref@1.3.3:
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
engines: {node: '>=10'}
@@ -10065,6 +9306,9 @@ packages:
react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc
+ vfile-location@5.0.3:
+ resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
+
vfile-message@2.0.4:
resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==}
@@ -10080,8 +9324,8 @@ packages:
victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
- vite-node@3.2.3:
- resolution: {integrity: sha512-gc8aAifGuDIpZHrPjuHyP4dpQmYXqWw7D1GmDnWeNWP654UEXzVfQ5IHPSK5HaHkwB/+p1atpYpSdw/2kOv8iQ==}
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
@@ -10125,16 +9369,16 @@ packages:
yaml:
optional: true
- vitest@3.2.3:
- resolution: {integrity: sha512-E6U2ZFXe3N/t4f5BwUaVCKRLHqUpk1CBWeMh78UT4VaTPH/2dyvH6ALl29JTovEPu9dVKr/K/J4PkXgrMbw4Ww==}
+ vitest@3.2.4:
+ resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/debug': ^4.1.12
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- '@vitest/browser': 3.2.3
- '@vitest/ui': 3.2.3
+ '@vitest/browser': 3.2.4
+ '@vitest/ui': 3.2.4
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -10186,20 +9430,20 @@ packages:
'@types/react': '*'
react: ^17 || ^18 || ^19
- w3c-xmlserializer@4.0.0:
- resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
- engines: {node: '>=14'}
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
walk-up-path@4.0.0:
resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==}
engines: {node: 20 || >=22}
- walker@1.0.8:
- resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
-
web-namespaces@1.1.4:
resolution: {integrity: sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==}
+ web-namespaces@2.0.1:
+ resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
+
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
@@ -10224,25 +9468,17 @@ packages:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
- whatwg-encoding@2.0.0:
- resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
- engines: {node: '>=12'}
-
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
- whatwg-mimetype@3.0.0:
- resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
- engines: {node: '>=12'}
-
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
- whatwg-url@11.0.0:
- resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
- engines: {node: '>=12'}
+ whatwg-url@14.2.0:
+ resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
+ engines: {node: '>=18'}
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
@@ -10322,10 +9558,6 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- write-file-atomic@4.0.2:
- resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-
ws@8.18.2:
resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
engines: {node: '>=10.0.0'}
@@ -10338,9 +9570,9 @@ packages:
utf-8-validate:
optional: true
- xml-name-validator@4.0.0:
- resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
- engines: {node: '>=12'}
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
xml2js@0.5.0:
resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
@@ -10375,10 +9607,6 @@ packages:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
- yaml@1.10.2:
- resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
- engines: {node: '>= 6'}
-
yaml@2.8.0:
resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==}
engines: {node: '>= 14.6'}
@@ -10511,6 +9739,14 @@ snapshots:
- encoding
- supports-color
+ '@asamuzakjp/css-color@3.2.0':
+ dependencies:
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ lru-cache: 10.4.3
+
'@aws-crypto/crc32@3.0.0':
dependencies:
'@aws-crypto/util': 3.0.0
@@ -11146,91 +10382,6 @@ snapshots:
dependencies:
'@babel/types': 7.27.1
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
- '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.1)':
- dependencies:
- '@babel/core': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
-
'@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
@@ -11433,6 +10584,26 @@ snapshots:
'@chevrotain/utils@11.0.3': {}
+ '@csstools/color-helpers@5.0.2': {}
+
+ '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/color-helpers': 5.0.2
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-tokenizer@3.0.4': {}
+
'@dotenvx/dotenvx@1.44.2':
dependencies:
commander: 11.1.0
@@ -11477,7 +10648,7 @@ snapshots:
'@esbuild-kit/core-utils@3.3.2':
dependencies:
- esbuild: 0.18.20
+ esbuild: 0.25.5
source-map-support: 0.5.21
'@esbuild-kit/esm-loader@2.6.5':
@@ -11485,219 +10656,78 @@ snapshots:
'@esbuild-kit/core-utils': 3.3.2
get-tsconfig: 4.10.0
- '@esbuild/aix-ppc64@0.25.4':
- optional: true
-
'@esbuild/aix-ppc64@0.25.5':
optional: true
- '@esbuild/android-arm64@0.18.20':
- optional: true
-
- '@esbuild/android-arm64@0.25.4':
- optional: true
-
'@esbuild/android-arm64@0.25.5':
optional: true
- '@esbuild/android-arm@0.18.20':
- optional: true
-
- '@esbuild/android-arm@0.25.4':
- optional: true
-
'@esbuild/android-arm@0.25.5':
optional: true
- '@esbuild/android-x64@0.18.20':
- optional: true
-
- '@esbuild/android-x64@0.25.4':
- optional: true
-
'@esbuild/android-x64@0.25.5':
optional: true
- '@esbuild/darwin-arm64@0.18.20':
- optional: true
-
- '@esbuild/darwin-arm64@0.25.4':
- optional: true
-
'@esbuild/darwin-arm64@0.25.5':
optional: true
- '@esbuild/darwin-x64@0.18.20':
- optional: true
-
- '@esbuild/darwin-x64@0.25.4':
- optional: true
-
'@esbuild/darwin-x64@0.25.5':
optional: true
- '@esbuild/freebsd-arm64@0.18.20':
- optional: true
-
- '@esbuild/freebsd-arm64@0.25.4':
- optional: true
-
'@esbuild/freebsd-arm64@0.25.5':
optional: true
- '@esbuild/freebsd-x64@0.18.20':
- optional: true
-
- '@esbuild/freebsd-x64@0.25.4':
- optional: true
-
'@esbuild/freebsd-x64@0.25.5':
optional: true
- '@esbuild/linux-arm64@0.18.20':
- optional: true
-
- '@esbuild/linux-arm64@0.25.4':
- optional: true
-
'@esbuild/linux-arm64@0.25.5':
optional: true
- '@esbuild/linux-arm@0.18.20':
- optional: true
-
- '@esbuild/linux-arm@0.25.4':
- optional: true
-
'@esbuild/linux-arm@0.25.5':
optional: true
- '@esbuild/linux-ia32@0.18.20':
- optional: true
-
- '@esbuild/linux-ia32@0.25.4':
- optional: true
-
'@esbuild/linux-ia32@0.25.5':
optional: true
- '@esbuild/linux-loong64@0.18.20':
- optional: true
-
- '@esbuild/linux-loong64@0.25.4':
- optional: true
-
'@esbuild/linux-loong64@0.25.5':
optional: true
- '@esbuild/linux-mips64el@0.18.20':
- optional: true
-
- '@esbuild/linux-mips64el@0.25.4':
- optional: true
-
'@esbuild/linux-mips64el@0.25.5':
optional: true
- '@esbuild/linux-ppc64@0.18.20':
- optional: true
-
- '@esbuild/linux-ppc64@0.25.4':
- optional: true
-
'@esbuild/linux-ppc64@0.25.5':
optional: true
- '@esbuild/linux-riscv64@0.18.20':
- optional: true
-
- '@esbuild/linux-riscv64@0.25.4':
- optional: true
-
'@esbuild/linux-riscv64@0.25.5':
optional: true
- '@esbuild/linux-s390x@0.18.20':
- optional: true
-
- '@esbuild/linux-s390x@0.25.4':
- optional: true
-
'@esbuild/linux-s390x@0.25.5':
optional: true
- '@esbuild/linux-x64@0.18.20':
- optional: true
-
- '@esbuild/linux-x64@0.25.4':
- optional: true
-
'@esbuild/linux-x64@0.25.5':
optional: true
- '@esbuild/netbsd-arm64@0.25.4':
- optional: true
-
'@esbuild/netbsd-arm64@0.25.5':
optional: true
- '@esbuild/netbsd-x64@0.18.20':
- optional: true
-
- '@esbuild/netbsd-x64@0.25.4':
- optional: true
-
'@esbuild/netbsd-x64@0.25.5':
optional: true
- '@esbuild/openbsd-arm64@0.25.4':
- optional: true
-
'@esbuild/openbsd-arm64@0.25.5':
optional: true
- '@esbuild/openbsd-x64@0.18.20':
- optional: true
-
- '@esbuild/openbsd-x64@0.25.4':
- optional: true
-
'@esbuild/openbsd-x64@0.25.5':
optional: true
- '@esbuild/sunos-x64@0.18.20':
- optional: true
-
- '@esbuild/sunos-x64@0.25.4':
- optional: true
-
'@esbuild/sunos-x64@0.25.5':
optional: true
- '@esbuild/win32-arm64@0.18.20':
- optional: true
-
- '@esbuild/win32-arm64@0.25.4':
- optional: true
-
'@esbuild/win32-arm64@0.25.5':
optional: true
- '@esbuild/win32-ia32@0.18.20':
- optional: true
-
- '@esbuild/win32-ia32@0.25.4':
- optional: true
-
'@esbuild/win32-ia32@0.25.5':
optional: true
- '@esbuild/win32-x64@0.18.20':
- optional: true
-
- '@esbuild/win32-x64@0.25.4':
- optional: true
-
'@esbuild/win32-x64@0.25.5':
optional: true
@@ -11771,8 +10801,6 @@ snapshots:
lodash.isundefined: 3.0.1
lodash.uniq: 4.5.0
- '@fastify/busboy@2.1.1': {}
-
'@floating-ui/core@1.7.0':
dependencies:
'@floating-ui/utils': 0.2.9
@@ -11924,169 +10952,16 @@ snapshots:
dependencies:
minipass: 7.1.2
- '@istanbuljs/load-nyc-config@1.1.0':
- dependencies:
- camelcase: 5.3.1
- find-up: 4.1.0
- get-package-type: 0.1.0
- js-yaml: 3.14.1
- resolve-from: 5.0.0
-
'@istanbuljs/schema@0.1.3': {}
- '@jest/console@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- chalk: 4.1.2
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
-
- '@jest/core@29.7.0(babel-plugin-macros@3.1.0)':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/reporters': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- ci-info: 3.9.0
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-resolve-dependencies: 29.7.0
- jest-runner: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- jest-watcher: 29.7.0
- micromatch: 4.0.8
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- '@jest/environment@29.7.0':
- dependencies:
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- jest-mock: 29.7.0
-
'@jest/expect-utils@29.7.0':
dependencies:
jest-get-type: 29.6.3
- '@jest/expect@29.7.0':
- dependencies:
- expect: 29.7.0
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/fake-timers@29.7.0':
- dependencies:
- '@jest/types': 29.6.3
- '@sinonjs/fake-timers': 10.3.0
- '@types/node': 20.17.57
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
- '@jest/globals@29.7.0':
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/types': 29.6.3
- jest-mock: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- '@jest/reporters@29.7.0':
- dependencies:
- '@bcoe/v8-coverage': 0.2.3
- '@jest/console': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- '@types/node': 20.17.57
- chalk: 4.1.2
- collect-v8-coverage: 1.0.2
- exit: 0.1.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- istanbul-lib-coverage: 3.2.2
- istanbul-lib-instrument: 6.0.3
- istanbul-lib-report: 3.0.1
- istanbul-lib-source-maps: 4.0.1
- istanbul-reports: 3.1.7
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- jest-worker: 29.7.0
- slash: 3.0.0
- string-length: 4.0.2
- strip-ansi: 6.0.1
- v8-to-istanbul: 9.3.0
- transitivePeerDependencies:
- - supports-color
-
'@jest/schemas@29.6.3':
dependencies:
'@sinclair/typebox': 0.27.8
- '@jest/source-map@29.6.3':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- callsites: 3.1.0
- graceful-fs: 4.2.11
-
- '@jest/test-result@29.7.0':
- dependencies:
- '@jest/console': 29.7.0
- '@jest/types': 29.6.3
- '@types/istanbul-lib-coverage': 2.0.6
- collect-v8-coverage: 1.0.2
-
- '@jest/test-sequencer@29.7.0':
- dependencies:
- '@jest/test-result': 29.7.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- slash: 3.0.0
-
- '@jest/transform@29.7.0':
- dependencies:
- '@babel/core': 7.27.1
- '@jest/types': 29.6.3
- '@jridgewell/trace-mapping': 0.3.25
- babel-plugin-istanbul: 6.1.1
- chalk: 4.1.2
- convert-source-map: 2.0.0
- fast-json-stable-stringify: 2.1.0
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- micromatch: 4.0.8
- pirates: 4.0.7
- slash: 3.0.0
- write-file-atomic: 4.0.2
- transitivePeerDependencies:
- - supports-color
-
'@jest/types@29.6.3':
dependencies:
'@jest/schemas': 29.6.3
@@ -12188,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
@@ -12447,6 +11340,8 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
+ '@polka/url@1.0.0-next.29': {}
+
'@puppeteer/browsers@2.10.5':
dependencies:
debug: 4.4.1(supports-color@8.1.1)
@@ -12479,7 +11374,7 @@ snapshots:
'@qdrant/openapi-typescript-fetch': 1.2.6
'@sevinf/maybe': 0.5.0
typescript: 5.8.3
- undici: 5.28.5
+ undici: 6.21.3
'@qdrant/openapi-typescript-fetch@1.2.6': {}
@@ -13186,14 +12081,6 @@ snapshots:
'@sindresorhus/merge-streams@4.0.0': {}
- '@sinonjs/commons@3.0.1':
- dependencies:
- type-detect: 4.0.8
-
- '@sinonjs/fake-timers@10.3.0':
- dependencies:
- '@sinonjs/commons': 3.0.1
-
'@smithy/abort-controller@2.2.0':
dependencies:
'@smithy/types': 2.12.0
@@ -13883,8 +12770,6 @@ snapshots:
dependencies:
'@testing-library/dom': 10.4.0
- '@tootallnate/once@2.0.0': {}
-
'@tootallnate/quickjs-emscripten@0.23.0': {}
'@tybys/wasm-util@0.9.0':
@@ -14063,10 +12948,6 @@ snapshots:
'@types/minimatch': 5.1.2
'@types/node': 20.17.57
- '@types/graceful-fs@4.1.9':
- dependencies:
- '@types/node': 20.17.57
-
'@types/hast@3.0.4':
dependencies:
'@types/unist': 3.0.3
@@ -14088,14 +12969,10 @@ snapshots:
'@types/js-cookie@2.2.7': {}
- '@types/jsdom@20.0.1':
- dependencies:
- '@types/node': 20.17.57
- '@types/tough-cookie': 4.0.5
- parse5: 7.3.0
-
'@types/json-schema@7.0.15': {}
+ '@types/katex@0.16.7': {}
+
'@types/lodash.debounce@4.0.9':
dependencies:
'@types/lodash': 4.17.17
@@ -14145,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
@@ -14154,9 +13031,6 @@ snapshots:
dependencies:
undici-types: 6.21.0
- '@types/parse-json@4.0.2':
- optional: true
-
'@types/prop-types@15.7.14': {}
'@types/ps-tree@1.1.6': {}
@@ -14178,14 +13052,8 @@ snapshots:
'@types/stylis@4.2.5': {}
- '@types/testing-library__jest-dom@5.14.9':
- dependencies:
- '@types/jest': 29.5.14
-
'@types/tmp@0.2.6': {}
- '@types/tough-cookie@4.0.5': {}
-
'@types/trusted-types@2.0.7':
optional: true
@@ -14203,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': {}
@@ -14315,62 +13183,73 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitest/expect@3.2.3':
+ '@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.2
- '@vitest/spy': 3.2.3
- '@vitest/utils': 3.2.3
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
chai: 5.2.0
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.3(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
+ '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
dependencies:
- '@vitest/spy': 3.2.3
+ '@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
vite: 6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- '@vitest/mocker@3.2.3(vite@6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
+ '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
dependencies:
- '@vitest/spy': 3.2.3
+ '@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
vite: 6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- '@vitest/mocker@3.2.3(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
+ '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
dependencies:
- '@vitest/spy': 3.2.3
+ '@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- '@vitest/pretty-format@3.2.3':
+ '@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
- '@vitest/runner@3.2.3':
+ '@vitest/runner@3.2.4':
dependencies:
- '@vitest/utils': 3.2.3
+ '@vitest/utils': 3.2.4
pathe: 2.0.3
strip-literal: 3.0.0
- '@vitest/snapshot@3.2.3':
+ '@vitest/snapshot@3.2.4':
dependencies:
- '@vitest/pretty-format': 3.2.3
+ '@vitest/pretty-format': 3.2.4
magic-string: 0.30.17
pathe: 2.0.3
- '@vitest/spy@3.2.3':
+ '@vitest/spy@3.2.4':
dependencies:
tinyspy: 4.0.3
- '@vitest/utils@3.2.3':
+ '@vitest/ui@3.2.4(vitest@3.2.4)':
dependencies:
- '@vitest/pretty-format': 3.2.3
- loupe: 3.1.3
+ '@vitest/utils': 3.2.4
+ fflate: 0.8.2
+ flatted: 3.3.3
+ pathe: 2.0.3
+ sirv: 3.0.1
+ tinyglobby: 0.2.14
+ tinyrainbow: 2.0.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:
+ '@vitest/pretty-format': 3.2.4
+ loupe: 3.1.4
tinyrainbow: 2.0.0
'@vscode/codicons@0.0.36': {}
@@ -14480,8 +13359,6 @@ snapshots:
'@xobotyi/scrollbar-width@1.9.5': {}
- abab@2.0.6: {}
-
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
@@ -14491,11 +13368,6 @@ snapshots:
mime-types: 3.0.1
negotiator: 1.0.0
- acorn-globals@7.0.1:
- dependencies:
- acorn: 8.14.1
- acorn-walk: 8.3.4
-
acorn-jsx@5.3.2(acorn@8.14.1):
dependencies:
acorn: 8.14.1
@@ -14504,20 +13376,10 @@ snapshots:
dependencies:
acorn: 8.15.0
- acorn-walk@8.3.4:
- dependencies:
- acorn: 8.14.1
-
acorn@8.14.1: {}
acorn@8.15.0: {}
- agent-base@6.0.2:
- dependencies:
- debug: 4.4.1(supports-color@8.1.1)
- transitivePeerDependencies:
- - supports-color
-
agent-base@7.1.3: {}
agentkeepalive@4.6.0:
@@ -14533,10 +13395,6 @@ snapshots:
ansi-colors@4.1.3: {}
- ansi-escapes@4.3.2:
- dependencies:
- type-fest: 0.21.3
-
ansi-escapes@7.0.0:
dependencies:
environment: 1.1.0
@@ -14722,73 +13580,11 @@ snapshots:
b4a@1.6.7: {}
- babel-jest@29.7.0(@babel/core@7.27.1):
- dependencies:
- '@babel/core': 7.27.1
- '@jest/transform': 29.7.0
- '@types/babel__core': 7.20.5
- babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.27.1)
- chalk: 4.1.2
- graceful-fs: 4.2.11
- slash: 3.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-istanbul@6.1.1:
- dependencies:
- '@babel/helper-plugin-utils': 7.27.1
- '@istanbuljs/load-nyc-config': 1.1.0
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-instrument: 5.2.1
- test-exclude: 6.0.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-jest-hoist@29.6.3:
- dependencies:
- '@babel/template': 7.27.2
- '@babel/types': 7.27.1
- '@types/babel__core': 7.20.5
- '@types/babel__traverse': 7.20.7
-
- babel-plugin-macros@3.1.0:
- dependencies:
- '@babel/runtime': 7.27.6
- cosmiconfig: 7.1.0
- resolve: 1.22.10
- optional: true
-
- babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.1):
- dependencies:
- '@babel/core': 7.27.1
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.1)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.1)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.1)
- '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.1)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.1)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.1)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.1)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.1)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.1)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.1)
-
- babel-preset-jest@29.6.3(@babel/core@7.27.1):
- dependencies:
- '@babel/core': 7.27.1
- babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1)
-
bail@1.0.5: {}
bail@2.0.2: {}
- balanced-match@1.0.2: {}
+ balanced-match@3.0.1: {}
bare-events@2.5.4:
optional: true
@@ -14873,14 +13669,9 @@ snapshots:
bowser@2.11.0: {}
- brace-expansion@1.1.11:
+ brace-expansion@4.0.1:
dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
-
- brace-expansion@2.0.1:
- dependencies:
- balanced-match: 1.0.2
+ balanced-match: 3.0.1
braces@3.0.3:
dependencies:
@@ -14895,14 +13686,6 @@ snapshots:
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.5)
- bs-logger@0.2.6:
- dependencies:
- fast-json-stable-stringify: 2.1.0
-
- bser@2.1.1:
- dependencies:
- node-int64: 0.4.0
-
buffer-crc32@0.2.13: {}
buffer-equal-constant-time@1.0.1: {}
@@ -14970,8 +13753,6 @@ snapshots:
camelcase-css@2.0.1: {}
- camelcase@5.3.1: {}
-
camelcase@6.3.0: {}
camelize@1.0.1: {}
@@ -15010,8 +13791,6 @@ snapshots:
chalk@5.4.1: {}
- char-regex@1.0.2: {}
-
character-entities-html4@2.1.0: {}
character-entities-legacy@1.1.4: {}
@@ -15091,12 +13870,16 @@ snapshots:
mitt: 3.0.1
zod: 3.23.8
+ chromium-bidi@5.1.0(devtools-protocol@0.0.1452169):
+ dependencies:
+ devtools-protocol: 0.0.1452169
+ mitt: 3.0.1
+ zod: 3.25.61
+
ci-info@2.0.0: {}
ci-info@3.9.0: {}
- cjs-module-lexer@1.4.3: {}
-
class-variance-authority@0.7.1:
dependencies:
clsx: 2.1.1
@@ -15159,12 +13942,8 @@ snapshots:
- '@types/react'
- '@types/react-dom'
- co@4.6.0: {}
-
cockatiel@3.2.1: {}
- collect-v8-coverage@1.0.2: {}
-
color-convert@1.9.3:
dependencies:
color-name: 1.1.3
@@ -15222,8 +14001,6 @@ snapshots:
normalize-path: 3.0.0
readable-stream: 3.6.2
- concat-map@0.0.1: {}
-
confbox@0.1.8: {}
confbox@0.2.2: {}
@@ -15275,15 +14052,6 @@ snapshots:
dependencies:
layout-base: 2.0.1
- cosmiconfig@7.1.0:
- dependencies:
- '@types/parse-json': 4.0.2
- import-fresh: 3.3.1
- parse-json: 5.2.0
- path-type: 4.0.0
- yaml: 1.10.2
- optional: true
-
crc-32@1.2.2: {}
crc32-stream@4.0.3:
@@ -15291,21 +14059,6 @@ snapshots:
crc-32: 1.2.2
readable-stream: 3.6.2
- create-jest@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
cross-fetch@4.0.0:
dependencies:
node-fetch: 2.7.0
@@ -15349,13 +14102,10 @@ snapshots:
cssesc@3.0.0: {}
- cssom@0.3.8: {}
-
- cssom@0.5.0: {}
-
- cssstyle@2.3.0:
+ cssstyle@4.4.0:
dependencies:
- cssom: 0.3.8
+ '@asamuzakjp/css-color': 3.2.0
+ rrweb-cssom: 0.8.0
csstype@3.1.3: {}
@@ -15548,11 +14298,10 @@ snapshots:
data-uri-to-buffer@6.0.2: {}
- data-urls@3.0.2:
+ data-urls@5.0.0:
dependencies:
- abab: 2.0.6
- whatwg-mimetype: 3.0.0
- whatwg-url: 11.0.0
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
data-view-buffer@1.0.2:
dependencies:
@@ -15603,10 +14352,6 @@ snapshots:
mimic-response: 3.1.0
optional: true
- dedent@1.6.0(babel-plugin-macros@3.1.0):
- optionalDependencies:
- babel-plugin-macros: 3.1.0
-
deep-eql@5.0.2: {}
deep-extend@0.6.0:
@@ -15614,8 +14359,6 @@ snapshots:
deep-is@0.1.4: {}
- deepmerge@4.3.1: {}
-
default-browser-id@5.0.0: {}
default-browser@5.2.1:
@@ -15664,8 +14407,6 @@ snapshots:
detect-libc@2.0.4: {}
- detect-newline@3.1.0: {}
-
detect-node-es@1.1.0: {}
devlop@1.1.0:
@@ -15674,6 +14415,8 @@ snapshots:
devtools-protocol@0.0.1367902: {}
+ devtools-protocol@0.0.1452169: {}
+
didyoumean@1.2.2: {}
diff-match-patch@1.0.5: {}
@@ -15711,10 +14454,6 @@ snapshots:
domelementtype@2.3.0: {}
- domexception@4.0.0:
- dependencies:
- webidl-conversions: 7.0.0
-
domhandler@5.0.3:
dependencies:
domelementtype: 2.3.0
@@ -15784,10 +14523,6 @@ snapshots:
eight-colors@1.3.1: {}
- ejs@3.1.10:
- dependencies:
- jake: 10.9.2
-
electron-to-chromium@1.5.152: {}
embla-carousel-auto-scroll@8.6.0(embla-carousel@8.6.0):
@@ -15810,8 +14545,6 @@ snapshots:
embla-carousel@8.6.0: {}
- emittery@0.13.1: {}
-
emoji-regex@10.4.0: {}
emoji-regex@8.0.0: {}
@@ -15848,10 +14581,6 @@ snapshots:
environment@1.1.0: {}
- error-ex@1.3.2:
- dependencies:
- is-arrayish: 0.2.1
-
error-stack-parser@2.1.4:
dependencies:
stackframe: 1.3.4
@@ -15963,59 +14692,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- esbuild@0.18.20:
- optionalDependencies:
- '@esbuild/android-arm': 0.18.20
- '@esbuild/android-arm64': 0.18.20
- '@esbuild/android-x64': 0.18.20
- '@esbuild/darwin-arm64': 0.18.20
- '@esbuild/darwin-x64': 0.18.20
- '@esbuild/freebsd-arm64': 0.18.20
- '@esbuild/freebsd-x64': 0.18.20
- '@esbuild/linux-arm': 0.18.20
- '@esbuild/linux-arm64': 0.18.20
- '@esbuild/linux-ia32': 0.18.20
- '@esbuild/linux-loong64': 0.18.20
- '@esbuild/linux-mips64el': 0.18.20
- '@esbuild/linux-ppc64': 0.18.20
- '@esbuild/linux-riscv64': 0.18.20
- '@esbuild/linux-s390x': 0.18.20
- '@esbuild/linux-x64': 0.18.20
- '@esbuild/netbsd-x64': 0.18.20
- '@esbuild/openbsd-x64': 0.18.20
- '@esbuild/sunos-x64': 0.18.20
- '@esbuild/win32-arm64': 0.18.20
- '@esbuild/win32-ia32': 0.18.20
- '@esbuild/win32-x64': 0.18.20
-
- esbuild@0.25.4:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.25.4
- '@esbuild/android-arm': 0.25.4
- '@esbuild/android-arm64': 0.25.4
- '@esbuild/android-x64': 0.25.4
- '@esbuild/darwin-arm64': 0.25.4
- '@esbuild/darwin-x64': 0.25.4
- '@esbuild/freebsd-arm64': 0.25.4
- '@esbuild/freebsd-x64': 0.25.4
- '@esbuild/linux-arm': 0.25.4
- '@esbuild/linux-arm64': 0.25.4
- '@esbuild/linux-ia32': 0.25.4
- '@esbuild/linux-loong64': 0.25.4
- '@esbuild/linux-mips64el': 0.25.4
- '@esbuild/linux-ppc64': 0.25.4
- '@esbuild/linux-riscv64': 0.25.4
- '@esbuild/linux-s390x': 0.25.4
- '@esbuild/linux-x64': 0.25.4
- '@esbuild/netbsd-arm64': 0.25.4
- '@esbuild/netbsd-x64': 0.25.4
- '@esbuild/openbsd-arm64': 0.25.4
- '@esbuild/openbsd-x64': 0.25.4
- '@esbuild/sunos-x64': 0.25.4
- '@esbuild/win32-arm64': 0.25.4
- '@esbuild/win32-ia32': 0.25.4
- '@esbuild/win32-x64': 0.25.4
-
esbuild@0.25.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.5
@@ -16331,8 +15007,6 @@ snapshots:
exenv-es6@1.1.1: {}
- exit@0.1.2: {}
-
expand-template@2.0.3:
optional: true
@@ -16453,10 +15127,6 @@ snapshots:
dependencies:
reusify: 1.1.0
- fb-watchman@2.0.2:
- dependencies:
- bser: 2.1.1
-
fd-package-json@2.0.0:
dependencies:
walk-up-path: 4.0.0
@@ -16481,6 +15151,8 @@ snapshots:
fflate@0.4.8: {}
+ fflate@0.8.2: {}
+
figures@6.1.0:
dependencies:
is-unicode-supported: 2.1.0
@@ -16492,10 +15164,6 @@ snapshots:
file-uri-to-path@1.0.0:
optional: true
- filelist@1.0.4:
- dependencies:
- minimatch: 5.1.6
-
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
@@ -16697,8 +15365,6 @@ snapshots:
get-nonce@1.0.1: {}
- get-package-type@0.1.0: {}
-
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
@@ -16863,10 +15529,47 @@ snapshots:
unist-util-is: 4.1.0
web-namespaces: 1.1.4
+ hast-util-from-dom@5.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hastscript: 9.0.1
+ web-namespaces: 2.0.1
+
+ hast-util-from-html-isomorphic@2.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-from-dom: 5.0.1
+ hast-util-from-html: 2.0.3
+ unist-util-remove-position: 5.0.0
+
+ hast-util-from-html@2.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ devlop: 1.1.0
+ hast-util-from-parse5: 8.0.3
+ parse5: 7.3.0
+ vfile: 6.0.3
+ vfile-message: 4.0.2
+
+ hast-util-from-parse5@8.0.3:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ devlop: 1.1.0
+ hastscript: 9.0.1
+ property-information: 7.1.0
+ vfile: 6.0.3
+ vfile-location: 5.0.3
+ web-namespaces: 2.0.1
+
hast-util-is-element@3.0.0:
dependencies:
'@types/hast': 3.0.4
+ hast-util-parse-selector@4.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
hast-util-to-html@9.0.5:
dependencies:
'@types/hast': 3.0.4
@@ -16912,6 +15615,14 @@ snapshots:
dependencies:
'@types/hast': 3.0.4
+ hastscript@9.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ comma-separated-tokens: 2.0.3
+ hast-util-parse-selector: 4.0.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+
he@1.2.0: {}
highlight.js@11.11.1: {}
@@ -16922,9 +15633,9 @@ snapshots:
howler@2.2.4: {}
- html-encoding-sniffer@3.0.0:
+ html-encoding-sniffer@4.0.0:
dependencies:
- whatwg-encoding: 2.0.0
+ whatwg-encoding: 3.1.1
html-escaper@2.0.2: {}
@@ -16951,14 +15662,6 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
- http-proxy-agent@5.0.0:
- dependencies:
- '@tootallnate/once': 2.0.0
- agent-base: 6.0.2
- debug: 4.4.1(supports-color@8.1.1)
- transitivePeerDependencies:
- - supports-color
-
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.3
@@ -16966,13 +15669,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- https-proxy-agent@5.0.1:
- dependencies:
- agent-base: 6.0.2
- debug: 4.4.1(supports-color@8.1.1)
- transitivePeerDependencies:
- - supports-color
-
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.3
@@ -17035,11 +15731,6 @@ snapshots:
parent-module: 1.0.1
resolve-from: 4.0.0
- import-local@3.2.0:
- dependencies:
- pkg-dir: 4.2.0
- resolve-cwd: 3.0.0
-
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
@@ -17099,8 +15790,6 @@ snapshots:
call-bound: 1.0.4
get-intrinsic: 1.3.0
- is-arrayish@0.2.1: {}
-
is-arrayish@0.3.2:
optional: true
@@ -17168,8 +15857,6 @@ snapshots:
dependencies:
get-east-asian-width: 1.3.0
- is-generator-fn@2.1.0: {}
-
is-generator-function@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -17296,40 +15983,12 @@ snapshots:
istanbul-lib-coverage@3.2.2: {}
- istanbul-lib-instrument@5.2.1:
- dependencies:
- '@babel/core': 7.27.1
- '@babel/parser': 7.27.2
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- istanbul-lib-instrument@6.0.3:
- dependencies:
- '@babel/core': 7.27.1
- '@babel/parser': 7.27.2
- '@istanbuljs/schema': 0.1.3
- istanbul-lib-coverage: 3.2.2
- semver: 7.7.2
- transitivePeerDependencies:
- - supports-color
-
istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
- istanbul-lib-source-maps@4.0.1:
- dependencies:
- debug: 4.4.1(supports-color@8.1.1)
- istanbul-lib-coverage: 3.2.2
- source-map: 0.6.1
- transitivePeerDependencies:
- - supports-color
-
istanbul-reports@3.1.7:
dependencies:
html-escaper: 2.0.2
@@ -17354,94 +16013,6 @@ snapshots:
dependencies:
'@isaacs/cliui': 8.0.2
- jake@10.9.2:
- dependencies:
- async: 3.2.6
- chalk: 4.1.2
- filelist: 1.0.4
- minimatch: 3.1.2
-
- jest-changed-files@29.7.0:
- dependencies:
- execa: 5.1.1
- jest-util: 29.7.0
- p-limit: 3.1.0
-
- jest-circus@29.7.0(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/expect': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- chalk: 4.1.2
- co: 4.6.0
- dedent: 1.6.0(babel-plugin-macros@3.1.0)
- is-generator-fn: 2.1.0
- jest-each: 29.7.0
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-runtime: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- p-limit: 3.1.0
- pretty-format: 29.7.0
- pure-rand: 6.1.0
- slash: 3.0.0
- stack-utils: 2.0.6
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
- jest-cli@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
- jest-config@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0):
- dependencies:
- '@babel/core': 7.27.1
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.27.1)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0(babel-plugin-macros@3.1.0)
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 20.17.57
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
jest-diff@29.7.0:
dependencies:
chalk: 4.1.2
@@ -17449,65 +16020,8 @@ snapshots:
jest-get-type: 29.6.3
pretty-format: 29.7.0
- jest-docblock@29.7.0:
- dependencies:
- detect-newline: 3.1.0
-
- jest-each@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- jest-get-type: 29.6.3
- jest-util: 29.7.0
- pretty-format: 29.7.0
-
- jest-environment-jsdom@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/jsdom': 20.0.1
- '@types/node': 20.17.57
- jest-mock: 29.7.0
- jest-util: 29.7.0
- jsdom: 20.0.3
- transitivePeerDependencies:
- - bufferutil
- - supports-color
- - utf-8-validate
-
- jest-environment-node@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- jest-mock: 29.7.0
- jest-util: 29.7.0
-
jest-get-type@29.6.3: {}
- jest-haste-map@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/graceful-fs': 4.1.9
- '@types/node': 20.17.57
- anymatch: 3.1.3
- fb-watchman: 2.0.2
- graceful-fs: 4.2.11
- jest-regex-util: 29.6.3
- jest-util: 29.7.0
- jest-worker: 29.7.0
- micromatch: 4.0.8
- walker: 1.0.8
- optionalDependencies:
- fsevents: 2.3.3
-
- jest-leak-detector@29.7.0:
- dependencies:
- jest-get-type: 29.6.3
- pretty-format: 29.7.0
-
jest-matcher-utils@29.7.0:
dependencies:
chalk: 4.1.2
@@ -17527,117 +16041,6 @@ snapshots:
slash: 3.0.0
stack-utils: 2.0.6
- jest-mock@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- jest-util: 29.7.0
-
- jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
- optionalDependencies:
- jest-resolve: 29.7.0
-
- jest-regex-util@29.6.3: {}
-
- jest-resolve-dependencies@29.7.0:
- dependencies:
- jest-regex-util: 29.6.3
- jest-snapshot: 29.7.0
- transitivePeerDependencies:
- - supports-color
-
- jest-resolve@29.7.0:
- dependencies:
- chalk: 4.1.2
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- resolve: 1.22.10
- resolve.exports: 2.0.3
- slash: 3.0.0
-
- jest-runner@29.7.0:
- dependencies:
- '@jest/console': 29.7.0
- '@jest/environment': 29.7.0
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- chalk: 4.1.2
- emittery: 0.13.1
- graceful-fs: 4.2.11
- jest-docblock: 29.7.0
- jest-environment-node: 29.7.0
- jest-haste-map: 29.7.0
- jest-leak-detector: 29.7.0
- jest-message-util: 29.7.0
- jest-resolve: 29.7.0
- jest-runtime: 29.7.0
- jest-util: 29.7.0
- jest-watcher: 29.7.0
- jest-worker: 29.7.0
- p-limit: 3.1.0
- source-map-support: 0.5.13
- transitivePeerDependencies:
- - supports-color
-
- jest-runtime@29.7.0:
- dependencies:
- '@jest/environment': 29.7.0
- '@jest/fake-timers': 29.7.0
- '@jest/globals': 29.7.0
- '@jest/source-map': 29.6.3
- '@jest/test-result': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- chalk: 4.1.2
- cjs-module-lexer: 1.4.3
- collect-v8-coverage: 1.0.2
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-haste-map: 29.7.0
- jest-message-util: 29.7.0
- jest-mock: 29.7.0
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-snapshot: 29.7.0
- jest-util: 29.7.0
- slash: 3.0.0
- strip-bom: 4.0.0
- transitivePeerDependencies:
- - supports-color
-
- jest-simple-dot-reporter@1.0.5: {}
-
- jest-snapshot@29.7.0:
- dependencies:
- '@babel/core': 7.27.1
- '@babel/generator': 7.27.1
- '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1)
- '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.1)
- '@babel/types': 7.27.1
- '@jest/expect-utils': 29.7.0
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1)
- chalk: 4.1.2
- expect: 29.7.0
- graceful-fs: 4.2.11
- jest-diff: 29.7.0
- jest-get-type: 29.6.3
- jest-matcher-utils: 29.7.0
- jest-message-util: 29.7.0
- jest-util: 29.7.0
- natural-compare: 1.4.0
- pretty-format: 29.7.0
- semver: 7.7.2
- transitivePeerDependencies:
- - supports-color
-
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
@@ -17647,45 +16050,6 @@ snapshots:
graceful-fs: 4.2.11
picomatch: 2.3.1
- jest-validate@29.7.0:
- dependencies:
- '@jest/types': 29.6.3
- camelcase: 6.3.0
- chalk: 4.1.2
- jest-get-type: 29.6.3
- leven: 3.1.0
- pretty-format: 29.7.0
-
- jest-watcher@29.7.0:
- dependencies:
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- '@types/node': 20.17.57
- ansi-escapes: 4.3.2
- chalk: 4.1.2
- emittery: 0.13.1
- jest-util: 29.7.0
- string-length: 4.0.2
-
- jest-worker@29.7.0:
- dependencies:
- '@types/node': 20.17.57
- jest-util: 29.7.0
- merge-stream: 2.0.0
- supports-color: 8.1.1
-
- jest@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jiti@1.21.7: {}
jiti@2.4.2: {}
@@ -17718,34 +16082,28 @@ snapshots:
jsbn@1.1.0: {}
- jsdom@20.0.3:
+ jsdom@26.1.0:
dependencies:
- abab: 2.0.6
- acorn: 8.14.1
- acorn-globals: 7.0.1
- cssom: 0.5.0
- cssstyle: 2.3.0
- data-urls: 3.0.2
+ cssstyle: 4.4.0
+ data-urls: 5.0.0
decimal.js: 10.5.0
- domexception: 4.0.0
- escodegen: 2.1.0
- form-data: 4.0.2
- html-encoding-sniffer: 3.0.0
- http-proxy-agent: 5.0.0
- https-proxy-agent: 5.0.1
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.20
parse5: 7.3.0
+ rrweb-cssom: 0.8.0
saxes: 6.0.0
symbol-tree: 3.2.4
- tough-cookie: 4.1.4
- w3c-xmlserializer: 4.0.0
+ tough-cookie: 5.1.2
+ w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
- whatwg-encoding: 2.0.0
- whatwg-mimetype: 3.0.0
- whatwg-url: 11.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
ws: 8.18.2
- xml-name-validator: 4.0.0
+ xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -17759,8 +16117,6 @@ snapshots:
json-buffer@3.0.1: {}
- json-parse-even-better-errors@2.3.1: {}
-
json-parse-even-better-errors@4.0.0: {}
json-schema-traverse@0.4.1: {}
@@ -17777,6 +16133,8 @@ snapshots:
optionalDependencies:
graceful-fs: 4.2.11
+ jsonschema@1.5.0: {}
+
jsonwebtoken@9.0.2:
dependencies:
jws: 3.2.2
@@ -17846,8 +16204,6 @@ snapshots:
kind-of@6.0.3: {}
- kleur@3.0.3: {}
-
knip@5.60.2(@types/node@22.15.29)(typescript@5.8.3):
dependencies:
'@nodelib/fs.walk': 1.2.8
@@ -18091,8 +16447,6 @@ snapshots:
lodash.isundefined@3.0.1: {}
- lodash.memoize@4.1.2: {}
-
lodash.merge@4.6.2: {}
lodash.once@4.1.1: {}
@@ -18139,6 +16493,8 @@ snapshots:
loupe@3.1.3: {}
+ loupe@3.1.4: {}
+
lowlight@3.3.0:
dependencies:
'@types/hast': 3.0.4
@@ -18159,7 +16515,7 @@ snapshots:
lru-cache@7.18.3: {}
- lucide-react@0.513.0(react@18.3.1):
+ lucide-react@0.518.0(react@18.3.1):
dependencies:
react: 18.3.1
@@ -18175,12 +16531,6 @@ snapshots:
dependencies:
semver: 7.7.2
- make-error@1.3.6: {}
-
- makeerror@1.0.12:
- dependencies:
- tmpl: 1.0.5
-
mammoth@1.9.0:
dependencies:
'@xmldom/xmldom': 0.8.10
@@ -18306,6 +16656,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ mdast-util-math@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ devlop: 1.1.0
+ longest-streak: 3.1.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-to-markdown: 2.1.2
+ unist-util-remove-position: 5.0.0
+ transitivePeerDependencies:
+ - supports-color
+
mdast-util-mdx-expression@2.0.1:
dependencies:
'@types/estree-jsx': 1.0.5
@@ -18509,6 +16871,16 @@ snapshots:
micromark-util-combine-extensions: 2.0.1
micromark-util-types: 2.0.2
+ micromark-extension-math@3.1.0:
+ dependencies:
+ '@types/katex': 0.16.7
+ devlop: 1.1.0
+ katex: 0.16.22
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
micromark-factory-destination@2.0.1:
dependencies:
micromark-util-character: 2.1.1
@@ -18662,19 +17034,19 @@ snapshots:
minimatch@10.0.1:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 4.0.1
minimatch@3.1.2:
dependencies:
- brace-expansion: 1.1.11
+ brace-expansion: 4.0.1
minimatch@5.1.6:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 4.0.1
minimatch@9.0.5:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 4.0.1
minimist@1.2.8: {}
@@ -18741,6 +17113,8 @@ snapshots:
mri@1.2.0: {}
+ mrmime@2.0.1: {}
+
ms@2.1.3: {}
mute-stream@0.0.8: {}
@@ -18840,8 +17214,6 @@ snapshots:
formdata-polyfill: 4.0.10
optional: true
- node-int64@0.4.0: {}
-
node-ipc@12.0.0:
dependencies:
event-pubsub: 5.0.3
@@ -18973,20 +17345,10 @@ snapshots:
is-inside-container: 1.0.0
is-wsl: 3.1.0
- openai@4.103.0(ws@8.18.2)(zod@3.25.61):
- dependencies:
- '@types/node': 18.19.100
- '@types/node-fetch': 2.6.12
- abort-controller: 3.0.0
- agentkeepalive: 4.6.0
- form-data-encoder: 1.7.2
- formdata-node: 4.4.1
- node-fetch: 2.7.0
+ openai@5.5.1(ws@8.18.2)(zod@3.25.61):
optionalDependencies:
ws: 8.18.2
zod: 3.25.61
- transitivePeerDependencies:
- - encoding
option@0.2.4: {}
@@ -19151,13 +17513,6 @@ snapshots:
is-decimal: 2.0.1
is-hexadecimal: 2.0.1
- parse-json@5.2.0:
- dependencies:
- '@babel/code-frame': 7.27.1
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
-
parse-ms@4.0.0: {}
parse-semver@1.1.1:
@@ -19236,14 +17591,8 @@ snapshots:
pirates@4.0.7: {}
- pkce-challenge@4.1.0: {}
-
pkce-challenge@5.0.0: {}
- pkg-dir@4.2.0:
- dependencies:
- find-up: 4.1.0
-
pkg-types@1.3.1:
dependencies:
confbox: 0.1.8
@@ -19350,11 +17699,7 @@ snapshots:
preact: 10.26.6
web-vitals: 4.2.4
- posthog-node@4.17.2:
- dependencies:
- axios: 1.9.0
- transitivePeerDependencies:
- - debug
+ posthog-node@5.1.1: {}
preact@10.26.6: {}
@@ -19382,7 +17727,7 @@ snapshots:
prettier@3.5.3: {}
- pretty-bytes@6.1.1: {}
+ pretty-bytes@7.0.0: {}
pretty-format@27.5.1:
dependencies:
@@ -19407,11 +17752,6 @@ snapshots:
promise-limit@2.7.0:
optional: true
- prompts@2.4.2:
- dependencies:
- kleur: 3.0.3
- sisteransi: 1.0.5
-
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -19450,10 +17790,6 @@ snapshots:
dependencies:
event-stream: 3.3.4
- psl@1.15.0:
- dependencies:
- punycode: 2.3.1
-
pump@3.0.2:
dependencies:
end-of-stream: 1.4.4
@@ -19463,12 +17799,12 @@ snapshots:
punycode@2.3.1: {}
- puppeteer-chromium-resolver@23.0.0:
+ puppeteer-chromium-resolver@24.0.1:
dependencies:
'@puppeteer/browsers': 2.10.5
eight-colors: 1.3.1
gauge: 5.0.2
- puppeteer-core: 23.11.1
+ puppeteer-core: 24.10.2
transitivePeerDependencies:
- bare-buffer
- bufferutil
@@ -19489,7 +17825,19 @@ snapshots:
- supports-color
- utf-8-validate
- pure-rand@6.1.0: {}
+ puppeteer-core@24.10.2:
+ dependencies:
+ '@puppeteer/browsers': 2.10.5
+ chromium-bidi: 5.1.0(devtools-protocol@0.0.1452169)
+ debug: 4.4.1(supports-color@8.1.1)
+ devtools-protocol: 0.0.1452169
+ typed-query-selector: 2.12.0
+ ws: 8.18.2
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - supports-color
+ - utf-8-validate
qs@6.14.0:
dependencies:
@@ -19497,8 +17845,6 @@ snapshots:
quansync@0.2.10: {}
- querystringify@2.2.0: {}
-
queue-microtask@1.2.3: {}
randombytes@2.1.0:
@@ -19791,6 +18137,16 @@ snapshots:
unist-util-visit: 5.0.0
vfile: 6.0.3
+ rehype-katex@7.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/katex': 0.16.7
+ hast-util-from-html-isomorphic: 2.0.0
+ hast-util-to-text: 4.0.2
+ katex: 0.16.22
+ unist-util-visit-parents: 6.0.1
+ vfile: 6.0.3
+
rehype-react@6.2.1:
dependencies:
'@mapbox/hast-util-table-cell-style': 0.2.1
@@ -19807,6 +18163,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ remark-math@6.0.0:
+ dependencies:
+ '@types/mdast': 4.0.4
+ mdast-util-math: 3.0.0
+ micromark-extension-math: 3.1.0
+ unified: 11.0.5
+ transitivePeerDependencies:
+ - supports-color
+
remark-parse@11.0.0:
dependencies:
'@types/mdast': 4.0.4
@@ -19844,22 +18209,14 @@ snapshots:
require-directory@2.1.1: {}
- requires-port@1.0.0: {}
-
resize-observer-polyfill@1.5.1: {}
- resolve-cwd@3.0.0:
- dependencies:
- resolve-from: 5.0.0
-
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
resolve-pkg-maps@1.0.0: {}
- resolve.exports@2.0.3: {}
-
resolve@1.22.10:
dependencies:
is-core-module: 2.16.1
@@ -19935,6 +18292,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ rrweb-cssom@0.8.0: {}
+
rtl-css-js@1.16.1:
dependencies:
'@babel/runtime': 7.27.4
@@ -20020,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:
@@ -20179,7 +18538,11 @@ snapshots:
is-arrayish: 0.3.2
optional: true
- sisteransi@1.0.5: {}
+ sirv@3.0.1:
+ dependencies:
+ '@polka/url': 1.0.0-next.29
+ mrmime: 2.0.1
+ totalist: 3.0.1
slash@3.0.0: {}
@@ -20219,11 +18582,6 @@ snapshots:
source-map-js@1.2.1: {}
- source-map-support@0.5.13:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
source-map-support@0.5.21:
dependencies:
buffer-from: 1.1.2
@@ -20302,11 +18660,6 @@ snapshots:
string-argv@0.3.2: {}
- string-length@4.0.2:
- dependencies:
- char-regex: 1.0.2
- strip-ansi: 6.0.1
-
string-similarity@4.0.4: {}
string-width@4.2.3:
@@ -20392,8 +18745,6 @@ snapshots:
strip-bom@3.0.0: {}
- strip-bom@4.0.0: {}
-
strip-bom@5.0.0: {}
strip-final-newline@2.0.0: {}
@@ -20490,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):
@@ -20617,20 +18966,24 @@ snapshots:
fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
- tinypool@1.1.0: {}
+ tinypool@1.1.1: {}
tinyrainbow@2.0.0: {}
tinyspy@4.0.3: {}
+ tldts-core@6.1.86: {}
+
+ tldts@6.1.86:
+ dependencies:
+ tldts-core: 6.1.86
+
tmp@0.0.33:
dependencies:
os-tmpdir: 1.0.2
tmp@0.2.3: {}
- tmpl@1.0.5: {}
-
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -20639,12 +18992,11 @@ snapshots:
toidentifier@1.0.1: {}
- tough-cookie@4.1.4:
+ totalist@3.0.1: {}
+
+ tough-cookie@5.1.2:
dependencies:
- psl: 1.15.0
- punycode: 2.3.1
- universalify: 0.2.0
- url-parse: 1.5.10
+ tldts: 6.1.86
tr46@0.0.3: {}
@@ -20652,7 +19004,7 @@ snapshots:
dependencies:
punycode: 2.3.1
- tr46@3.0.0:
+ tr46@5.1.1:
dependencies:
punycode: 2.3.1
@@ -20682,27 +19034,6 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-jest@29.3.3(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.5)(jest@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0))(typescript@5.8.3):
- dependencies:
- bs-logger: 0.2.6
- ejs: 3.1.10
- fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.7.2
- type-fest: 4.41.0
- typescript: 5.8.3
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.27.1
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.27.1)
- esbuild: 0.25.5
-
tslib@1.14.1: {}
tslib@2.6.2: {}
@@ -20739,7 +19070,7 @@ snapshots:
tsx@4.19.4:
dependencies:
- esbuild: 0.25.4
+ esbuild: 0.25.5
get-tsconfig: 4.10.0
optionalDependencies:
fsevents: 2.3.3
@@ -20786,12 +19117,6 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
- type-detect@4.0.8: {}
-
- type-fest@0.21.3: {}
-
- type-fest@2.19.0: {}
-
type-fest@4.41.0: {}
type-is@2.0.1:
@@ -20877,10 +19202,6 @@ snapshots:
undici-types@6.21.0: {}
- undici@5.28.5:
- dependencies:
- '@fastify/busboy': 2.1.1
-
undici@6.21.3: {}
unicorn-magic@0.3.0: {}
@@ -20928,6 +19249,11 @@ snapshots:
dependencies:
'@types/unist': 3.0.3
+ unist-util-remove-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-visit: 5.0.0
+
unist-util-stringify-position@2.0.3:
dependencies:
'@types/unist': 2.0.11
@@ -20968,8 +19294,6 @@ snapshots:
universalify@0.1.2: {}
- universalify@0.2.0: {}
-
unpipe@1.0.0: {}
untildify@4.0.0: {}
@@ -20999,11 +19323,6 @@ snapshots:
url-join@4.0.1: {}
- url-parse@1.5.10:
- dependencies:
- querystringify: 2.2.0
- requires-port: 1.0.0
-
use-callback-ref@1.3.3(@types/react@18.3.23)(react@18.3.1):
dependencies:
react: 18.3.1
@@ -21070,6 +19389,11 @@ snapshots:
- '@types/react'
- '@types/react-dom'
+ vfile-location@5.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile: 6.0.3
+
vfile-message@2.0.4:
dependencies:
'@types/unist': 2.0.11
@@ -21109,7 +19433,7 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-node@3.2.3(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ vite-node@3.2.4(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
cac: 6.7.14
debug: 4.4.1(supports-color@8.1.1)
@@ -21130,7 +19454,7 @@ snapshots:
- tsx
- yaml
- vite-node@3.2.3(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ vite-node@3.2.4(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
cac: 6.7.14
debug: 4.4.1(supports-color@8.1.1)
@@ -21151,7 +19475,7 @@ snapshots:
- tsx
- yaml
- vite-node@3.2.3(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ vite-node@3.2.4(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
cac: 6.7.14
debug: 4.4.1(supports-color@8.1.1)
@@ -21220,16 +19544,16 @@ snapshots:
tsx: 4.19.4
yaml: 2.8.0
- vitest@3.2.3(@types/debug@4.1.12)(@types/node@20.17.50)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.17.50)(@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):
dependencies:
'@types/chai': 5.2.2
- '@vitest/expect': 3.2.3
- '@vitest/mocker': 3.2.3(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
- '@vitest/pretty-format': 3.2.3
- '@vitest/runner': 3.2.3
- '@vitest/snapshot': 3.2.3
- '@vitest/spy': 3.2.3
- '@vitest/utils': 3.2.3
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
chai: 5.2.0
debug: 4.4.1(supports-color@8.1.1)
expect-type: 1.2.1
@@ -21240,15 +19564,16 @@ snapshots:
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.14
- tinypool: 1.1.0
+ tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- vite-node: 3.2.3(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ vite-node: 3.2.4(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 20.17.50
- jsdom: 20.0.3
+ '@vitest/ui': 3.2.4(vitest@3.2.4)
+ jsdom: 26.1.0
transitivePeerDependencies:
- jiti
- less
@@ -21263,16 +19588,16 @@ snapshots:
- tsx
- yaml
- vitest@3.2.3(@types/debug@4.1.12)(@types/node@20.17.57)(jiti@2.4.2)(jsdom@20.0.3)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.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):
dependencies:
'@types/chai': 5.2.2
- '@vitest/expect': 3.2.3
- '@vitest/mocker': 3.2.3(vite@6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
- '@vitest/pretty-format': 3.2.3
- '@vitest/runner': 3.2.3
- '@vitest/snapshot': 3.2.3
- '@vitest/spy': 3.2.3
- '@vitest/utils': 3.2.3
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
chai: 5.2.0
debug: 4.4.1(supports-color@8.1.1)
expect-type: 1.2.1
@@ -21283,15 +19608,16 @@ snapshots:
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.14
- tinypool: 1.1.0
+ tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- vite-node: 3.2.3(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ vite-node: 3.2.4(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 20.17.57
- jsdom: 20.0.3
+ '@vitest/ui': 3.2.4(vitest@3.2.4)
+ jsdom: 26.1.0
transitivePeerDependencies:
- jiti
- less
@@ -21306,16 +19632,16 @@ snapshots:
- tsx
- yaml
- vitest@3.2.3(@types/debug@4.1.12)(@types/node@22.15.29)(jiti@2.4.2)(jsdom@20.0.3)(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):
dependencies:
'@types/chai': 5.2.2
- '@vitest/expect': 3.2.3
- '@vitest/mocker': 3.2.3(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
- '@vitest/pretty-format': 3.2.3
- '@vitest/runner': 3.2.3
- '@vitest/snapshot': 3.2.3
- '@vitest/spy': 3.2.3
- '@vitest/utils': 3.2.3
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
chai: 5.2.0
debug: 4.4.1(supports-color@8.1.1)
expect-type: 1.2.1
@@ -21326,15 +19652,16 @@ snapshots:
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.14
- tinypool: 1.1.0
+ tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
- vite-node: 3.2.3(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ vite-node: 3.2.4(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 22.15.29
- jsdom: 20.0.3
+ '@vitest/ui': 3.2.4(vitest@3.2.4)
+ jsdom: 26.1.0
transitivePeerDependencies:
- jiti
- less
@@ -21375,18 +19702,16 @@ snapshots:
'@types/react': 18.3.23
react: 18.3.1
- w3c-xmlserializer@4.0.0:
+ w3c-xmlserializer@5.0.0:
dependencies:
- xml-name-validator: 4.0.0
+ xml-name-validator: 5.0.0
walk-up-path@4.0.0: {}
- walker@1.0.8:
- dependencies:
- makeerror: 1.0.12
-
web-namespaces@1.1.4: {}
+ web-namespaces@2.0.1: {}
+
web-streams-polyfill@3.3.3:
optional: true
@@ -21402,21 +19727,15 @@ snapshots:
webidl-conversions@7.0.0: {}
- whatwg-encoding@2.0.0:
- dependencies:
- iconv-lite: 0.6.3
-
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
- whatwg-mimetype@3.0.0: {}
-
whatwg-mimetype@4.0.0: {}
- whatwg-url@11.0.0:
+ whatwg-url@14.2.0:
dependencies:
- tr46: 3.0.0
+ tr46: 5.1.1
webidl-conversions: 7.0.0
whatwg-url@5.0.0:
@@ -21524,14 +19843,9 @@ snapshots:
wrappy@1.0.2: {}
- write-file-atomic@4.0.2:
- dependencies:
- imurmurhash: 0.1.4
- signal-exit: 3.0.7
-
ws@8.18.2: {}
- xml-name-validator@4.0.0: {}
+ xml-name-validator@5.0.0: {}
xml2js@0.5.0:
dependencies:
@@ -21554,9 +19868,6 @@ snapshots:
yallist@5.0.0: {}
- yaml@1.10.2:
- optional: true
-
yaml@2.8.0: {}
yargs-parser@20.2.9: {}
diff --git a/scripts/update-contributors.js b/scripts/update-contributors.js
old mode 100755
new mode 100644
index 32fd645f68..6bd4c35f0c
--- 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/.vscodeignore b/src/.vscodeignore
index 3aaf4b677b..8eed90df07 100644
--- a/src/.vscodeignore
+++ b/src/.vscodeignore
@@ -19,6 +19,9 @@
!webview-ui/build/assets/*.js
!webview-ui/build/assets/*.ttf
!webview-ui/build/assets/*.css
+!webview-ui/build/assets/fonts/*.woff
+!webview-ui/build/assets/fonts/*.woff2
+!webview-ui/build/assets/fonts/*.ttf
# Include default themes JSON files used in getTheme
!integrations/theme/default-themes/**
diff --git a/src/__mocks__/fs/promises.ts b/src/__mocks__/fs/promises.ts
index 91e686fb70..daed479d4a 100644
--- a/src/__mocks__/fs/promises.ts
+++ b/src/__mocks__/fs/promises.ts
@@ -168,6 +168,7 @@ const mockFs = {
args: ["test.js"],
disabled: false,
alwaysAllow: ["existing-tool"],
+ disabledTools: [],
},
},
}),
diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts
index 3ec5d151e1..fc30878c7b 100644
--- a/src/activate/registerCommands.ts
+++ b/src/activate/registerCommands.ts
@@ -8,6 +8,7 @@ import { Package } from "../shared/package"
import { getCommand } from "../utils/commands"
import { ClineProvider } from "../core/webview/ClineProvider"
import { ContextProxy } from "../core/config/ContextProxy"
+import { focusPanel } from "../utils/focusPanel"
import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay"
import { handleNewTask } from "./handleTask"
@@ -172,20 +173,23 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
},
focusInput: async () => {
try {
- const panel = getPanel()
+ await focusPanel(tabPanel, sidebarPanel)
- if (!panel) {
- await vscode.commands.executeCommand(`workbench.view.extension.${Package.name}-ActivityBar`)
- } else if (panel === tabPanel) {
- panel.reveal(vscode.ViewColumn.Active, false)
- } else if (panel === sidebarPanel) {
- await vscode.commands.executeCommand(`${ClineProvider.sideBarId}.focus`)
+ // Send focus input message only for sidebar panels
+ if (sidebarPanel && getPanel() === sidebarPanel) {
provider.postMessageToWebview({ type: "action", action: "focusInput" })
}
} catch (error) {
outputChannel.appendLine(`Error focusing input: ${error}`)
}
},
+ focusPanel: async () => {
+ try {
+ await focusPanel(tabPanel, sidebarPanel)
+ } catch (error) {
+ outputChannel.appendLine(`Error focusing panel: ${error}`)
+ }
+ },
acceptInput: () => {
const visibleProvider = getVisibleProviderOrLog(outputChannel)
diff --git a/src/api/index.ts b/src/api/index.ts
index 8b09bf4cf9..960209f714 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -27,6 +27,7 @@ import {
GroqHandler,
ChutesHandler,
LiteLLMHandler,
+ ClaudeCodeHandler,
} from "./providers"
export interface SingleCompletionHandler {
@@ -64,6 +65,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
switch (apiProvider) {
case "anthropic":
return new AnthropicHandler(options)
+ case "claude-code":
+ return new ClaudeCodeHandler(options)
case "glama":
return new GlamaHandler(options)
case "openrouter":
diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts
index 412f5de621..52dec1ae55 100644
--- a/src/api/providers/anthropic.ts
+++ b/src/api/providers/anthropic.ts
@@ -17,6 +17,7 @@ import { getModelParams } from "../transform/model-params"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
+import { calculateApiCostAnthropic } from "../../shared/cost"
export class AnthropicHandler extends BaseProvider implements SingleCompletionHandler {
private options: ApiHandlerOptions
@@ -132,20 +133,35 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
}
}
+ let inputTokens = 0
+ let outputTokens = 0
+ let cacheWriteTokens = 0
+ let cacheReadTokens = 0
+
for await (const chunk of stream) {
switch (chunk.type) {
case "message_start": {
// Tells us cache reads/writes/input/output.
- const usage = chunk.message.usage
+ const {
+ input_tokens = 0,
+ output_tokens = 0,
+ cache_creation_input_tokens,
+ cache_read_input_tokens,
+ } = chunk.message.usage
yield {
type: "usage",
- inputTokens: usage.input_tokens || 0,
- outputTokens: usage.output_tokens || 0,
- cacheWriteTokens: usage.cache_creation_input_tokens || undefined,
- cacheReadTokens: usage.cache_read_input_tokens || undefined,
+ inputTokens: input_tokens,
+ outputTokens: output_tokens,
+ cacheWriteTokens: cache_creation_input_tokens || undefined,
+ cacheReadTokens: cache_read_input_tokens || undefined,
}
+ inputTokens += input_tokens
+ outputTokens += output_tokens
+ cacheWriteTokens += cache_creation_input_tokens || 0
+ cacheReadTokens += cache_read_input_tokens || 0
+
break
}
case "message_delta":
@@ -198,6 +214,21 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
break
}
}
+
+ if (inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0) {
+ yield {
+ type: "usage",
+ inputTokens: 0,
+ outputTokens: 0,
+ totalCost: calculateApiCostAnthropic(
+ this.getModel().info,
+ inputTokens,
+ outputTokens,
+ cacheWriteTokens,
+ cacheReadTokens,
+ ),
+ }
+ }
}
getModel() {
diff --git a/src/api/providers/claude-code.ts b/src/api/providers/claude-code.ts
new file mode 100644
index 0000000000..f3e66604e4
--- /dev/null
+++ b/src/api/providers/claude-code.ts
@@ -0,0 +1,171 @@
+import type { Anthropic } from "@anthropic-ai/sdk"
+import { claudeCodeDefaultModelId, type ClaudeCodeModelId, claudeCodeModels } from "@roo-code/types"
+import { type ApiHandler } from ".."
+import { ApiStreamUsageChunk, type ApiStream } from "../transform/stream"
+import { runClaudeCode } from "../../integrations/claude-code/run"
+import { ClaudeCodeMessage } from "../../integrations/claude-code/types"
+import { BaseProvider } from "./base-provider"
+import { t } from "../../i18n"
+import { ApiHandlerOptions } from "../../shared/api"
+
+export class ClaudeCodeHandler extends BaseProvider implements ApiHandler {
+ private options: ApiHandlerOptions
+
+ constructor(options: ApiHandlerOptions) {
+ super()
+ this.options = options
+ }
+
+ override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ const claudeProcess = runClaudeCode({
+ systemPrompt,
+ messages,
+ path: this.options.claudeCodePath,
+ modelId: this.getModel().id,
+ })
+
+ const dataQueue: string[] = []
+ let processError = null
+ let errorOutput = ""
+ let exitCode: number | null = null
+
+ claudeProcess.stdout.on("data", (data) => {
+ const output = data.toString()
+ const lines = output.split("\n").filter((line: string) => line.trim() !== "")
+
+ for (const line of lines) {
+ dataQueue.push(line)
+ }
+ })
+
+ claudeProcess.stderr.on("data", (data) => {
+ errorOutput += data.toString()
+ })
+
+ claudeProcess.on("close", (code) => {
+ exitCode = code
+ })
+
+ claudeProcess.on("error", (error) => {
+ processError = error
+ })
+
+ // Usage is included with assistant messages,
+ // but cost is included in the result chunk
+ let usage: ApiStreamUsageChunk = {
+ type: "usage",
+ inputTokens: 0,
+ outputTokens: 0,
+ cacheReadTokens: 0,
+ cacheWriteTokens: 0,
+ }
+
+ while (exitCode !== 0 || dataQueue.length > 0) {
+ if (dataQueue.length === 0) {
+ await new Promise((resolve) => setImmediate(resolve))
+ }
+
+ if (exitCode !== null && exitCode !== 0) {
+ if (errorOutput) {
+ throw new Error(
+ t("common:errors.claudeCode.processExitedWithError", {
+ exitCode,
+ output: errorOutput.trim(),
+ }),
+ )
+ }
+ throw new Error(t("common:errors.claudeCode.processExited", { exitCode }))
+ }
+
+ const data = dataQueue.shift()
+ if (!data) {
+ continue
+ }
+
+ const chunk = this.attemptParseChunk(data)
+
+ if (!chunk) {
+ yield {
+ type: "text",
+ text: data || "",
+ }
+
+ continue
+ }
+
+ if (chunk.type === "system" && chunk.subtype === "init") {
+ continue
+ }
+
+ if (chunk.type === "assistant" && "message" in chunk) {
+ const message = chunk.message
+
+ if (message.stop_reason !== null && message.stop_reason !== "tool_use") {
+ const errorMessage =
+ message.content[0]?.text ||
+ t("common:errors.claudeCode.stoppedWithReason", { reason: message.stop_reason })
+
+ if (errorMessage.includes("Invalid model name")) {
+ throw new Error(errorMessage + `\n\n${t("common:errors.claudeCode.apiKeyModelPlanMismatch")}`)
+ }
+
+ throw new Error(errorMessage)
+ }
+
+ for (const content of message.content) {
+ if (content.type === "text") {
+ yield {
+ type: "text",
+ text: content.text,
+ }
+ } else {
+ console.warn("Unsupported content type:", content.type)
+ }
+ }
+
+ usage.inputTokens += message.usage.input_tokens
+ usage.outputTokens += message.usage.output_tokens
+ usage.cacheReadTokens = (usage.cacheReadTokens || 0) + (message.usage.cache_read_input_tokens || 0)
+ usage.cacheWriteTokens =
+ (usage.cacheWriteTokens || 0) + (message.usage.cache_creation_input_tokens || 0)
+
+ continue
+ }
+
+ if (chunk.type === "result" && "result" in chunk) {
+ // Only use the cost from the CLI if provided
+ // Don't calculate cost as it may be $0 for subscription users
+ usage.totalCost = chunk.cost_usd ?? 0
+
+ yield usage
+ }
+
+ if (processError) {
+ throw processError
+ }
+ }
+ }
+
+ getModel() {
+ const modelId = this.options.apiModelId
+ if (modelId && modelId in claudeCodeModels) {
+ const id = modelId as ClaudeCodeModelId
+ return { id, info: claudeCodeModels[id] }
+ }
+
+ return {
+ id: claudeCodeDefaultModelId,
+ info: claudeCodeModels[claudeCodeDefaultModelId],
+ }
+ }
+
+ // TODO: Validate instead of parsing
+ private attemptParseChunk(data: string): ClaudeCodeMessage | null {
+ try {
+ return JSON.parse(data)
+ } catch (error) {
+ console.error("Error parsing chunk:", error)
+ return null
+ }
+ }
+}
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 0000000000..43f5505710
--- /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 0000000000..e0b6ac03d9
--- /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 0000000000..59b4388785
--- /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 0000000000..bf1bf3c6b2
--- /dev/null
+++ b/src/api/providers/fetchers/__tests__/ollama.test.ts
@@ -0,0 +1,222 @@
+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",
+ })
+ })
+
+ it("should handle models with null families field", () => {
+ const modelDataWithNullFamilies = {
+ ...ollamaModelsData["qwen3-2to16:latest"],
+ details: {
+ ...ollamaModelsData["qwen3-2to16:latest"].details,
+ families: null,
+ },
+ }
+
+ const parsedModel = parseOllamaModel(modelDataWithNullFamilies as any)
+
+ 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
+ })
+
+ it("should handle models with null families field in API response", async () => {
+ const baseUrl = "http://localhost:11434"
+ const modelName = "test-model: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: null, // This is the case we're testing
+ 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: null, // This is the case we're testing
+ 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()
+
+ // Verify the model was parsed correctly despite null families
+ expect(result[modelName].description).toBe("Family: llama, Context: 4096, Size: 23.6B")
+ })
+ })
+})
diff --git a/src/api/providers/fetchers/lmstudio.ts b/src/api/providers/fetchers/lmstudio.ts
new file mode 100644
index 0000000000..ea1a590f1e
--- /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 12d636bc46..5956187e41 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 0000000000..8e1e3f7f07
--- /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()).nullable().optional(),
+ format: z.string().optional(),
+ parameter_size: z.string(),
+ parent_model: z.string().optional(),
+ quantization_level: z.string().optional(),
+})
+
+const OllamaModelSchema = z.object({
+ details: OllamaModelDetailsSchema,
+ digest: z.string().optional(),
+ model: z.string(),
+ modified_at: z.string().optional(),
+ name: z.string(),
+ size: z.number().optional(),
+})
+
+const OllamaModelInfoResponseSchema = z.object({
+ modelfile: z.string().optional(),
+ parameters: z.string().optional(),
+ template: z.string().optional(),
+ 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/index.ts b/src/api/providers/index.ts
index b305118188..93df5c58ff 100644
--- a/src/api/providers/index.ts
+++ b/src/api/providers/index.ts
@@ -2,6 +2,7 @@ export { AnthropicVertexHandler } from "./anthropic-vertex"
export { AnthropicHandler } from "./anthropic"
export { AwsBedrockHandler } from "./bedrock"
export { ChutesHandler } from "./chutes"
+export { ClaudeCodeHandler } from "./claude-code"
export { DeepSeekHandler } from "./deepseek"
export { FakeAIHandler } from "./fake-ai"
export { GeminiHandler } from "./gemini"
diff --git a/src/api/providers/ollama.ts b/src/api/providers/ollama.ts
index 7f384e9a98..a7713ba421 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/api/transform/stream.ts b/src/api/transform/stream.ts
index caa69a09fe..89655a3f56 100644
--- a/src/api/transform/stream.ts
+++ b/src/api/transform/stream.ts
@@ -1,6 +1,12 @@
export type ApiStream = AsyncGenerator
-export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk
+export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk | ApiStreamReasoningChunk | ApiStreamError
+
+export interface ApiStreamError {
+ type: "error"
+ error: string
+ message: string
+}
export interface ApiStreamTextChunk {
type: "text"
diff --git a/src/core/condense/index.ts b/src/core/condense/index.ts
index 8a8b57bb0c..3b73b1915c 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/diff/strategies/multi-file-search-replace.ts b/src/core/diff/strategies/multi-file-search-replace.ts
index 3450ae56bc..1554201675 100644
--- a/src/core/diff/strategies/multi-file-search-replace.ts
+++ b/src/core/diff/strategies/multi-file-search-replace.ts
@@ -485,7 +485,7 @@ Each file requires its own path, start_line, and diff elements.
const replacements = matches
.map((match) => ({
- startLine: Number(match[2] ?? 0),
+ startLine: _paramStartLine ?? Number(match[2] ?? 0),
searchContent: match[6],
replaceContent: match[7],
}))
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
index 4041e031f9..dd621b34b8 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
@@ -298,25 +298,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -449,7 +446,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
index 68c240c7c3..3b8f357e8c 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
@@ -195,25 +195,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -346,7 +343,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
index 749d4ec32b..719e7f0ea7 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
@@ -369,25 +369,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -533,7 +530,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
index 298f6473c4..9f3ad102e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
@@ -369,25 +369,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -539,7 +536,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
index 645e79ba22..2c7e9ec165 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
@@ -325,25 +325,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -476,7 +473,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
index f983669ffb..b4220ce2e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
@@ -320,25 +320,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -471,7 +468,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
index 55045311c2..6248770325 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
@@ -373,25 +373,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -527,7 +524,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
index f983669ffb..b4220ce2e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
@@ -320,25 +320,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -471,7 +468,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
index 6ca41856cf..1fce8bf785 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
@@ -408,25 +408,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -559,7 +556,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
index f983669ffb..b4220ce2e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
@@ -320,25 +320,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -471,7 +468,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
index 20d6ee8c78..d07dc1d874 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
@@ -373,25 +373,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -527,7 +524,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
index 298f6473c4..9f3ad102e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
@@ -369,25 +369,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -539,7 +536,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
index f983669ffb..b4220ce2e8 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
@@ -320,25 +320,22 @@ Example: Requesting to ask the user for the path to the frontend-config.json fil
## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use `open index.html` to display a created html website, or `open localhost:3000` to display a locally running development server. But DO NOT use commands like `echo` or `cat` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
Usage:
Your final result description here
-Command to demonstrate result (optional)
-Example: Requesting to attempt completion with a result and command
+Example: Requesting to attempt completion with a result
I've updated the CSS
-open index.html
## switch_mode
@@ -471,7 +468,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. `open index.html` to show the website you've built.
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.
diff --git a/src/core/prompts/instructions/create-mcp-server.ts b/src/core/prompts/instructions/create-mcp-server.ts
index 3d1d2a20cf..a63fad1de5 100644
--- a/src/core/prompts/instructions/create-mcp-server.ts
+++ b/src/core/prompts/instructions/create-mcp-server.ts
@@ -50,6 +50,7 @@ Common configuration options for both types:
- \`disabled\`: (optional) Set to true to temporarily disable the server
- \`timeout\`: (optional) Maximum time in seconds to wait for server responses (default: 60)
- \`alwaysAllow\`: (optional) Array of tool names that don't require user confirmation
+- \`disabledTools\`: (optional) Array of tool names that are not included in the system prompt and won't be used
### Example Local MCP Server
@@ -276,7 +277,7 @@ npm run build
5. Install the MCP Server by adding the MCP server configuration to the settings file located at '${await mcpHub.getMcpSettingsFilePath()}'. The settings file may have other MCP servers already configured, so you would read it first and then add your new server to the existing \`mcpServers\` object.
-IMPORTANT: Regardless of what else you see in the MCP settings file, you must default any new MCP servers you create to disabled=false and alwaysAllow=[].
+IMPORTANT: Regardless of what else you see in the MCP settings file, you must default any new MCP servers you create to disabled=false, alwaysAllow=[] and disabledTools=[].
\`\`\`json
{
diff --git a/src/core/prompts/sections/mcp-servers.ts b/src/core/prompts/sections/mcp-servers.ts
index 2a9b6d148a..0af850cbb1 100644
--- a/src/core/prompts/sections/mcp-servers.ts
+++ b/src/core/prompts/sections/mcp-servers.ts
@@ -17,6 +17,7 @@ export async function getMcpServersSection(
.filter((server) => server.status === "connected")
.map((server) => {
const tools = server.tools
+ ?.filter((tool) => tool.enabledForPrompt !== false)
?.map((tool) => {
const schemaStr = tool.inputSchema
? ` Input Schema:
diff --git a/src/core/prompts/sections/objective.ts b/src/core/prompts/sections/objective.ts
index db37495086..845db046a0 100644
--- a/src/core/prompts/sections/objective.ts
+++ b/src/core/prompts/sections/objective.ts
@@ -1,4 +1,3 @@
-import { EXPERIMENT_IDS, experiments } from "../../../shared/experiments"
import { CodeIndexManager } from "../../../services/code-index/manager"
export function getObjectiveSection(
@@ -15,13 +14,6 @@ export function getObjectiveSection(
? "First, if the task involves understanding existing code or functionality, you MUST use the `codebase_search` tool to search for relevant code based on the task's intent BEFORE using any other search or file exploration tools. Then, "
: "First, "
- // Check if command execution is disabled via experiment
- const isCommandDisabled = experimentsConfig && experimentsConfig[EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]
-
- const commandInstruction = !isCommandDisabled
- ? " You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. \`open index.html\` to show the website you've built."
- : ""
-
return `====
OBJECTIVE
@@ -31,6 +23,6 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis within tags. ${codebaseSearchInstruction}analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, close the thinking tag and proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
-4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.${commandInstruction}
+4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`
}
diff --git a/src/core/prompts/tools/__tests__/attempt-completion.spec.ts b/src/core/prompts/tools/__tests__/attempt-completion.spec.ts
index fe2d2c7225..026d73789f 100644
--- a/src/core/prompts/tools/__tests__/attempt-completion.spec.ts
+++ b/src/core/prompts/tools/__tests__/attempt-completion.spec.ts
@@ -1,129 +1,69 @@
import { getAttemptCompletionDescription } from "../attempt-completion"
-import { EXPERIMENT_IDS } from "../../../../shared/experiments"
-describe("getAttemptCompletionDescription - DISABLE_COMPLETION_COMMAND experiment", () => {
- describe("when experiment is disabled (default)", () => {
- it("should include command parameter in the description", () => {
- const args = {
- cwd: "/test/path",
- supportsComputerUse: false,
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: false,
- },
- }
+describe("getAttemptCompletionDescription", () => {
+ it("should NOT include command parameter in the description", () => {
+ const args = {
+ cwd: "/test/path",
+ supportsComputerUse: false,
+ }
- const description = getAttemptCompletionDescription(args)
+ const description = getAttemptCompletionDescription(args)
- // Check that command parameter is included
- expect(description).toContain("- command: (optional)")
- expect(description).toContain("A CLI command to execute to show a live demo")
- expect(description).toContain("Command to demonstrate result (optional) ")
- expect(description).toContain("open index.html ")
- })
+ // Check that command parameter is NOT included (permanently disabled)
+ expect(description).not.toContain("- command: (optional)")
+ expect(description).not.toContain("A CLI command to execute to show a live demo")
+ expect(description).not.toContain("Command to demonstrate result (optional) ")
+ expect(description).not.toContain("open index.html ")
- it("should include command parameter when experiments is undefined", () => {
- const args = {
- cwd: "/test/path",
- supportsComputerUse: false,
- }
-
- const description = getAttemptCompletionDescription(args)
-
- // Check that command parameter is included
- expect(description).toContain("- command: (optional)")
- expect(description).toContain("A CLI command to execute to show a live demo")
- expect(description).toContain("Command to demonstrate result (optional) ")
- expect(description).toContain("open index.html ")
- })
-
- it("should include command parameter when no args provided", () => {
- const description = getAttemptCompletionDescription()
-
- // Check that command parameter is included
- expect(description).toContain("- command: (optional)")
- expect(description).toContain("A CLI command to execute to show a live demo")
- expect(description).toContain("Command to demonstrate result (optional) ")
- expect(description).toContain("open index.html ")
- })
+ // But should still have the basic structure
+ expect(description).toContain("## attempt_completion")
+ expect(description).toContain("- result: (required)")
+ expect(description).toContain("")
+ expect(description).toContain(" ")
})
- describe("when experiment is enabled", () => {
- it("should NOT include command parameter in the description", () => {
- const args = {
- cwd: "/test/path",
- supportsComputerUse: false,
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: true,
- },
- }
+ it("should work when no args provided", () => {
+ const description = getAttemptCompletionDescription()
- const description = getAttemptCompletionDescription(args)
+ // Check that command parameter is NOT included (permanently disabled)
+ expect(description).not.toContain("- command: (optional)")
+ expect(description).not.toContain("A CLI command to execute to show a live demo")
+ expect(description).not.toContain("Command to demonstrate result (optional) ")
+ expect(description).not.toContain("open index.html ")
- // Check that command parameter is NOT included
- expect(description).not.toContain("- command: (optional)")
- expect(description).not.toContain("A CLI command to execute to show a live demo")
- expect(description).not.toContain("Command to demonstrate result (optional) ")
- expect(description).not.toContain("open index.html ")
-
- // But should still have the basic structure
- expect(description).toContain("## attempt_completion")
- expect(description).toContain("- result: (required)")
- expect(description).toContain("")
- expect(description).toContain(" ")
- })
-
- it("should show example without command", () => {
- const args = {
- cwd: "/test/path",
- supportsComputerUse: false,
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: true,
- },
- }
-
- const description = getAttemptCompletionDescription(args)
-
- // Check example format
- expect(description).toContain("Example: Requesting to attempt completion with a result")
- expect(description).toContain("I've updated the CSS")
- expect(description).not.toContain("Example: Requesting to attempt completion with a result and command")
- })
+ // But should still have the basic structure
+ expect(description).toContain("## attempt_completion")
+ expect(description).toContain("- result: (required)")
+ expect(description).toContain("")
+ expect(description).toContain(" ")
})
- describe("description content", () => {
- it("should maintain core functionality description regardless of experiment", () => {
- const argsWithExperimentDisabled = {
- cwd: "/test/path",
- supportsComputerUse: false,
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: false,
- },
- }
+ it("should show example without command", () => {
+ const args = {
+ cwd: "/test/path",
+ supportsComputerUse: false,
+ }
- const argsWithExperimentEnabled = {
- cwd: "/test/path",
- supportsComputerUse: false,
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: true,
- },
- }
+ const description = getAttemptCompletionDescription(args)
- const descriptionDisabled = getAttemptCompletionDescription(argsWithExperimentDisabled)
- const descriptionEnabled = getAttemptCompletionDescription(argsWithExperimentEnabled)
+ // Check example format
+ expect(description).toContain("Example: Requesting to attempt completion with a result")
+ expect(description).toContain("I've updated the CSS")
+ expect(description).not.toContain("Example: Requesting to attempt completion with a result and command")
+ })
- // Both should contain core functionality
- const coreText = "After each tool use, the user will respond with the result of that tool use"
- expect(descriptionDisabled).toContain(coreText)
- expect(descriptionEnabled).toContain(coreText)
+ it("should contain core functionality description", () => {
+ const description = getAttemptCompletionDescription()
- // Both should contain the important note
- const importantNote = "IMPORTANT NOTE: This tool CANNOT be used until you've confirmed"
- expect(descriptionDisabled).toContain(importantNote)
- expect(descriptionEnabled).toContain(importantNote)
+ // Should contain core functionality
+ const coreText = "After each tool use, the user will respond with the result of that tool use"
+ expect(description).toContain(coreText)
- // Both should contain result parameter
- expect(descriptionDisabled).toContain("- result: (required)")
- expect(descriptionEnabled).toContain("- result: (required)")
- })
+ // Should contain the important note
+ const importantNote = "IMPORTANT NOTE: This tool CANNOT be used until you've confirmed"
+ expect(description).toContain(importantNote)
+
+ // Should contain result parameter
+ expect(description).toContain("- result: (required)")
})
})
diff --git a/src/core/prompts/tools/attempt-completion.ts b/src/core/prompts/tools/attempt-completion.ts
index ef0f3b9dfd..904f9899e6 100644
--- a/src/core/prompts/tools/attempt-completion.ts
+++ b/src/core/prompts/tools/attempt-completion.ts
@@ -1,41 +1,17 @@
-import { EXPERIMENT_IDS, experiments } from "../../../shared/experiments"
import { ToolArgs } from "./types"
export function getAttemptCompletionDescription(args?: ToolArgs): string {
- // Check if command execution is disabled via experiment
- const isCommandDisabled =
- args?.experiments && experiments.isEnabled(args.experiments, EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND)
-
- const baseDescription = `## attempt_completion
-Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user.${!isCommandDisabled ? " Optionally you may provide a CLI command to showcase the result of your work." : ""} The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
+ return `## attempt_completion
+Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
Parameters:
-- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.`
-
- const commandParameter = !isCommandDisabled
- ? `
-- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use \`open index.html\` to display a created html website, or \`open localhost:3000\` to display a locally running development server. But DO NOT use commands like \`echo\` or \`cat\` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.`
- : ""
-
- const usage = `
+- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
Usage:
Your final result description here
- ${!isCommandDisabled ? "\nCommand to demonstrate result (optional) " : ""}
- `
-
- const example = !isCommandDisabled
- ? `
-
-Example: Requesting to attempt completion with a result and command
-
-
-I've updated the CSS
-open index.html
- `
- : `
+
Example: Requesting to attempt completion with a result
@@ -43,6 +19,4 @@ Example: Requesting to attempt completion with a result
I've updated the CSS
`
-
- return baseDescription + commandParameter + usage + example
}
diff --git a/src/core/sliding-window/__tests__/sliding-window.spec.ts b/src/core/sliding-window/__tests__/sliding-window.spec.ts
index 0f41942547..3bda5351d4 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 dc9eaf718d..ae26f51a52 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/Task.ts b/src/core/task/Task.ts
index a6a9d89986..46da7485ed 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -140,9 +140,17 @@ export class Task extends EventEmitter {
// API
readonly apiConfiguration: ProviderSettings
api: ApiHandler
- private lastApiRequestTime?: number
+ private static lastGlobalApiRequestTime?: number
private consecutiveAutoApprovedRequestsCount: number = 0
+ /**
+ * Reset the global API request timestamp. This should only be used for testing.
+ * @internal
+ */
+ static resetGlobalApiRequestTime(): void {
+ Task.lastGlobalApiRequestTime = undefined
+ }
+
toolRepetitionDetector: ToolRepetitionDetector
rooIgnoreController?: RooIgnoreController
rooProtectedController?: RooProtectedController
@@ -1431,19 +1439,22 @@ export class Task extends EventEmitter {
} finally {
this.isStreaming = false
}
- if (
- inputTokens > 0 ||
- outputTokens > 0 ||
- cacheWriteTokens > 0 ||
- cacheReadTokens > 0 ||
- typeof totalCost !== "undefined"
- ) {
+
+ if (inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0) {
TelemetryService.instance.captureLlmCompletion(this.taskId, {
inputTokens,
outputTokens,
cacheWriteTokens,
cacheReadTokens,
- cost: totalCost,
+ cost:
+ totalCost ??
+ calculateApiCostAnthropic(
+ this.api.getModel().info,
+ inputTokens,
+ outputTokens,
+ cacheWriteTokens,
+ cacheReadTokens,
+ ),
})
}
@@ -1632,6 +1643,7 @@ export class Task extends EventEmitter {
mode,
autoCondenseContext = true,
autoCondenseContextPercent = 100,
+ profileThresholds = {},
} = state ?? {}
// Get condensing configuration for automatic triggers
@@ -1657,10 +1669,11 @@ export class Task extends EventEmitter {
let rateLimitDelay = 0
- // Only apply rate limiting if this isn't the first request
- if (this.lastApiRequestTime) {
+ // Use the shared timestamp so that subtasks respect the same rate-limit
+ // window as their parent tasks.
+ if (Task.lastGlobalApiRequestTime) {
const now = Date.now()
- const timeSinceLastRequest = now - this.lastApiRequestTime
+ const timeSinceLastRequest = now - Task.lastGlobalApiRequestTime
const rateLimit = apiConfiguration?.rateLimitSeconds || 0
rateLimitDelay = Math.ceil(Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000)
}
@@ -1675,8 +1688,9 @@ export class Task extends EventEmitter {
}
}
- // Update last request time before making the request
- this.lastApiRequestTime = Date.now()
+ // Update last request time before making the request so that subsequent
+ // requests — even from new subtasks — will honour the provider's rate-limit.
+ Task.lastGlobalApiRequestTime = Date.now()
const systemPrompt = await this.getSystemPrompt()
const { contextTokens } = this.getTokenUsage()
@@ -1706,6 +1720,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)
diff --git a/src/core/task/__tests__/Task.spec.ts b/src/core/task/__tests__/Task.spec.ts
index 5798a0bacd..693f72d1c7 100644
--- a/src/core/task/__tests__/Task.spec.ts
+++ b/src/core/task/__tests__/Task.spec.ts
@@ -18,38 +18,55 @@ import { MultiSearchReplaceDiffStrategy } from "../../diff/strategies/multi-sear
import { MultiFileSearchReplaceDiffStrategy } from "../../diff/strategies/multi-file-search-replace"
import { EXPERIMENT_IDS } from "../../../shared/experiments"
+// Mock delay before any imports that might use it
+vi.mock("delay", () => ({
+ __esModule: true,
+ default: vi.fn().mockResolvedValue(undefined),
+}))
+
+import delay from "delay"
+
vi.mock("execa", () => ({
execa: vi.fn(),
}))
-vi.mock("fs/promises", () => ({
- mkdir: vi.fn().mockResolvedValue(undefined),
- writeFile: vi.fn().mockResolvedValue(undefined),
- readFile: vi.fn().mockImplementation((filePath) => {
- if (filePath.includes("ui_messages.json")) {
- return Promise.resolve(JSON.stringify(mockMessages))
- }
- if (filePath.includes("api_conversation_history.json")) {
- return Promise.resolve(
- JSON.stringify([
- {
- role: "user",
- content: [{ type: "text", text: "historical task" }],
- ts: Date.now(),
- },
- {
- role: "assistant",
- content: [{ type: "text", text: "I'll help you with that task." }],
- ts: Date.now(),
- },
- ]),
- )
- }
- return Promise.resolve("[]")
- }),
- unlink: vi.fn().mockResolvedValue(undefined),
- rmdir: vi.fn().mockResolvedValue(undefined),
-}))
+vi.mock("fs/promises", async (importOriginal) => {
+ const actual = (await importOriginal()) as Record
+ const mockFunctions = {
+ mkdir: vi.fn().mockResolvedValue(undefined),
+ writeFile: vi.fn().mockResolvedValue(undefined),
+ readFile: vi.fn().mockImplementation((filePath) => {
+ if (filePath.includes("ui_messages.json")) {
+ return Promise.resolve(JSON.stringify(mockMessages))
+ }
+ if (filePath.includes("api_conversation_history.json")) {
+ return Promise.resolve(
+ JSON.stringify([
+ {
+ role: "user",
+ content: [{ type: "text", text: "historical task" }],
+ ts: Date.now(),
+ },
+ {
+ role: "assistant",
+ content: [{ type: "text", text: "I'll help you with that task." }],
+ ts: Date.now(),
+ },
+ ]),
+ )
+ }
+ return Promise.resolve("[]")
+ }),
+ unlink: vi.fn().mockResolvedValue(undefined),
+ rmdir: vi.fn().mockResolvedValue(undefined),
+ }
+
+ return {
+ ...actual,
+ ...mockFunctions,
+ default: mockFunctions,
+ }
+})
vi.mock("p-wait-for", () => ({
default: vi.fn().mockImplementation(async () => Promise.resolve()),
@@ -869,6 +886,353 @@ describe("Cline", () => {
})
})
+ describe("Subtask Rate Limiting", () => {
+ let mockProvider: any
+ let mockApiConfig: any
+ let mockDelay: ReturnType
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ // Reset the global timestamp before each test
+ Task.resetGlobalApiRequestTime()
+
+ mockApiConfig = {
+ apiProvider: "anthropic",
+ apiKey: "test-key",
+ rateLimitSeconds: 5,
+ }
+
+ mockProvider = {
+ context: {
+ globalStorageUri: { fsPath: "/test/storage" },
+ },
+ getState: vi.fn().mockResolvedValue({
+ apiConfiguration: mockApiConfig,
+ }),
+ say: vi.fn(),
+ postStateToWebview: vi.fn().mockResolvedValue(undefined),
+ postMessageToWebview: vi.fn().mockResolvedValue(undefined),
+ updateTaskHistory: vi.fn().mockResolvedValue(undefined),
+ }
+
+ // Get the mocked delay function
+ mockDelay = delay as ReturnType
+ mockDelay.mockClear()
+ })
+
+ afterEach(() => {
+ // Clean up the global state after each test
+ Task.resetGlobalApiRequestTime()
+ })
+
+ it("should enforce rate limiting across parent and subtask", async () => {
+ // Add a spy to track getState calls
+ const getStateSpy = vi.spyOn(mockProvider, "getState")
+
+ // Create parent task
+ const parent = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "parent task",
+ startTask: false,
+ })
+
+ // Mock the API stream response
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "parent response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "parent response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(parent.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the parent task
+ const parentIterator = parent.attemptApiRequest(0)
+ await parentIterator.next()
+
+ // Verify no delay was applied for the first request
+ expect(mockDelay).not.toHaveBeenCalled()
+
+ // Create a subtask immediately after
+ const child = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "child task",
+ parentTask: parent,
+ rootTask: parent,
+ startTask: false,
+ })
+
+ // Mock the child's API stream
+ const childMockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "child response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "child response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(child.api, "createMessage").mockReturnValue(childMockStream)
+
+ // Make an API request with the child task
+ const childIterator = child.attemptApiRequest(0)
+ await childIterator.next()
+
+ // Verify rate limiting was applied
+ expect(mockDelay).toHaveBeenCalledTimes(mockApiConfig.rateLimitSeconds)
+ expect(mockDelay).toHaveBeenCalledWith(1000)
+ }, 10000) // Increase timeout to 10 seconds
+
+ it("should not apply rate limiting if enough time has passed", async () => {
+ // Create parent task
+ const parent = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "parent task",
+ startTask: false,
+ })
+
+ // Mock the API stream response
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(parent.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the parent task
+ const parentIterator = parent.attemptApiRequest(0)
+ await parentIterator.next()
+
+ // Simulate time passing (more than rate limit)
+ const originalDateNow = Date.now
+ const mockTime = Date.now() + (mockApiConfig.rateLimitSeconds + 1) * 1000
+ Date.now = vi.fn(() => mockTime)
+
+ // Create a subtask after time has passed
+ const child = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "child task",
+ parentTask: parent,
+ rootTask: parent,
+ startTask: false,
+ })
+
+ vi.spyOn(child.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the child task
+ const childIterator = child.attemptApiRequest(0)
+ await childIterator.next()
+
+ // Verify no rate limiting was applied
+ expect(mockDelay).not.toHaveBeenCalled()
+
+ // Restore Date.now
+ Date.now = originalDateNow
+ })
+
+ it("should share rate limiting across multiple subtasks", async () => {
+ // Create parent task
+ const parent = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "parent task",
+ startTask: false,
+ })
+
+ // Mock the API stream response
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(parent.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the parent task
+ const parentIterator = parent.attemptApiRequest(0)
+ await parentIterator.next()
+
+ // Create first subtask
+ const child1 = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "child task 1",
+ parentTask: parent,
+ rootTask: parent,
+ startTask: false,
+ })
+
+ vi.spyOn(child1.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the first child task
+ const child1Iterator = child1.attemptApiRequest(0)
+ await child1Iterator.next()
+
+ // Verify rate limiting was applied
+ const firstDelayCount = mockDelay.mock.calls.length
+ expect(firstDelayCount).toBe(mockApiConfig.rateLimitSeconds)
+
+ // Clear the mock to count new delays
+ mockDelay.mockClear()
+
+ // Create second subtask immediately after
+ const child2 = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "child task 2",
+ parentTask: parent,
+ rootTask: parent,
+ startTask: false,
+ })
+
+ vi.spyOn(child2.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the second child task
+ const child2Iterator = child2.attemptApiRequest(0)
+ await child2Iterator.next()
+
+ // Verify rate limiting was applied again
+ expect(mockDelay).toHaveBeenCalledTimes(mockApiConfig.rateLimitSeconds)
+ }, 15000) // Increase timeout to 15 seconds
+
+ it("should handle rate limiting with zero rate limit", async () => {
+ // Update config to have zero rate limit
+ mockApiConfig.rateLimitSeconds = 0
+ mockProvider.getState.mockResolvedValue({
+ apiConfiguration: mockApiConfig,
+ })
+
+ // Create parent task
+ const parent = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "parent task",
+ startTask: false,
+ })
+
+ // Mock the API stream response
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(parent.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the parent task
+ const parentIterator = parent.attemptApiRequest(0)
+ await parentIterator.next()
+
+ // Create a subtask
+ const child = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "child task",
+ parentTask: parent,
+ rootTask: parent,
+ startTask: false,
+ })
+
+ vi.spyOn(child.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request with the child task
+ const childIterator = child.attemptApiRequest(0)
+ await childIterator.next()
+
+ // Verify no delay was applied
+ expect(mockDelay).not.toHaveBeenCalled()
+ })
+
+ it("should update global timestamp even when no rate limiting is needed", async () => {
+ // Create task
+ const task = new Task({
+ provider: mockProvider,
+ apiConfiguration: mockApiConfig,
+ task: "test task",
+ startTask: false,
+ })
+
+ // Mock the API stream response
+ const mockStream = {
+ async *[Symbol.asyncIterator]() {
+ yield { type: "text", text: "response" }
+ },
+ async next() {
+ return { done: true, value: { type: "text", text: "response" } }
+ },
+ async return() {
+ return { done: true, value: undefined }
+ },
+ async throw(e: any) {
+ throw e
+ },
+ [Symbol.asyncDispose]: async () => {},
+ } as AsyncGenerator
+
+ vi.spyOn(task.api, "createMessage").mockReturnValue(mockStream)
+
+ // Make an API request
+ const iterator = task.attemptApiRequest(0)
+ await iterator.next()
+
+ // Access the private static property via reflection for testing
+ const globalTimestamp = (Task as any).lastGlobalApiRequestTime
+ expect(globalTimestamp).toBeDefined()
+ expect(globalTimestamp).toBeGreaterThan(0)
+ })
+ })
+
describe("Dynamic Strategy Selection", () => {
let mockProvider: any
let mockApiConfig: any
diff --git a/src/core/tools/__tests__/attemptCompletionTool.experiment.spec.ts b/src/core/tools/__tests__/attemptCompletionTool.experiment.spec.ts
deleted file mode 100644
index 9ed8f22019..0000000000
--- a/src/core/tools/__tests__/attemptCompletionTool.experiment.spec.ts
+++ /dev/null
@@ -1,356 +0,0 @@
-// Mocks must come first, before imports
-vi.mock("../executeCommandTool", () => ({
- executeCommand: vi.fn(),
-}))
-
-vi.mock("@roo-code/telemetry", () => ({
- TelemetryService: {
- instance: {
- captureTaskCompleted: vi.fn(),
- },
- },
-}))
-
-// Then imports
-import type { Mock } from "vitest"
-import { attemptCompletionTool } from "../attemptCompletionTool"
-import { EXPERIMENT_IDS } from "../../../shared/experiments"
-import { executeCommand } from "../executeCommandTool"
-
-describe("attemptCompletionTool - DISABLE_COMPLETION_COMMAND experiment", () => {
- let mockCline: any
- let mockAskApproval: Mock
- let mockHandleError: Mock
- let mockPushToolResult: Mock
- let mockRemoveClosingTag: Mock
- let mockToolDescription: Mock
- let mockAskFinishSubTaskApproval: Mock
-
- beforeEach(() => {
- vi.clearAllMocks()
-
- mockAskApproval = vi.fn().mockResolvedValue(true)
- mockHandleError = vi.fn()
- mockPushToolResult = vi.fn()
- mockRemoveClosingTag = vi.fn((tag, content) => content)
- mockToolDescription = vi.fn().mockReturnValue("attempt_completion")
- mockAskFinishSubTaskApproval = vi.fn()
-
- mockCline = {
- say: vi.fn(),
- ask: vi.fn().mockResolvedValue({ response: "yesButtonClicked", text: "", images: [] }),
- clineMessages: [],
- lastMessageTs: Date.now(),
- consecutiveMistakeCount: 0,
- sayAndCreateMissingParamError: vi.fn(),
- recordToolError: vi.fn(),
- emit: vi.fn(),
- getTokenUsage: vi.fn().mockReturnValue({}),
- toolUsage: {},
- userMessageContent: [],
- taskId: "test-task-id",
- providerRef: {
- deref: vi.fn().mockReturnValue({
- getState: vi.fn().mockResolvedValue({
- experiments: {},
- }),
- }),
- },
- }
- })
-
- describe("when experiment is disabled (default)", () => {
- beforeEach(() => {
- mockCline.providerRef.deref().getState.mockResolvedValue({
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: false,
- },
- })
- })
-
- it("should execute command when provided", async () => {
- const mockExecuteCommand = executeCommand as Mock
- mockExecuteCommand.mockResolvedValue([false, "Command executed successfully"])
-
- // Mock clineMessages with a previous message that's not a command ask
- mockCline.clineMessages = [{ say: "previous_message", text: "Previous message" }]
-
- const block = {
- params: {
- result: "Task completed successfully",
- command: "npm test",
- },
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- // When there's a lastMessage that's not a command ask, it should say completion_result first
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockCline.emit).toHaveBeenCalledWith(
- "taskCompleted",
- mockCline.taskId,
- expect.any(Object),
- expect.any(Object),
- )
- expect(mockAskApproval).toHaveBeenCalledWith("command", "npm test")
- expect(mockExecuteCommand).toHaveBeenCalled()
- })
-
- it("should not execute command when user rejects", async () => {
- mockAskApproval.mockResolvedValue(false)
- const mockExecuteCommand = executeCommand as Mock
-
- // Mock clineMessages with a previous message that's not a command ask
- mockCline.clineMessages = [{ say: "previous_message", text: "Previous message" }]
-
- const block = {
- params: {
- result: "Task completed successfully",
- command: "npm test",
- },
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- // Should say completion_result and emit before asking for approval
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockCline.emit).toHaveBeenCalledWith(
- "taskCompleted",
- mockCline.taskId,
- expect.any(Object),
- expect.any(Object),
- )
- expect(mockAskApproval).toHaveBeenCalledWith("command", "npm test")
- expect(mockExecuteCommand).not.toHaveBeenCalled()
- })
- })
-
- describe("when experiment is enabled", () => {
- beforeEach(() => {
- mockCline.providerRef.deref().getState.mockResolvedValue({
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: true,
- },
- })
- })
-
- it("should NOT execute command even when provided", async () => {
- const mockExecuteCommand = executeCommand as Mock
-
- const block = {
- params: {
- result: "Task completed successfully",
- command: "npm test",
- },
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockAskApproval).not.toHaveBeenCalled()
- expect(mockExecuteCommand).not.toHaveBeenCalled()
- })
-
- it("should complete normally without command execution", async () => {
- const block = {
- params: {
- result: "Task completed successfully",
- command: "npm test",
- },
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockCline.emit).toHaveBeenCalledWith(
- "taskCompleted",
- mockCline.taskId,
- expect.any(Object),
- expect.any(Object),
- )
- expect(mockAskApproval).not.toHaveBeenCalled()
- })
- })
-
- describe("when no command is provided", () => {
- it("should work the same regardless of experiment state", async () => {
- const block = {
- params: {
- result: "Task completed successfully",
- },
- partial: false,
- }
-
- // Test with experiment disabled
- mockCline.providerRef.deref().getState.mockResolvedValue({
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: false,
- },
- })
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockAskApproval).not.toHaveBeenCalled()
-
- // Reset mocks
- vi.clearAllMocks()
-
- // Test with experiment enabled
- mockCline.providerRef.deref().getState.mockResolvedValue({
- experiments: {
- [EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND]: true,
- },
- })
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- expect(mockCline.say).toHaveBeenCalledWith(
- "completion_result",
- "Task completed successfully",
- undefined,
- false,
- )
- expect(mockAskApproval).not.toHaveBeenCalled()
- })
- })
-
- describe("error handling", () => {
- it("should handle missing result parameter", async () => {
- const block = {
- params: {},
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- expect(mockCline.consecutiveMistakeCount).toBe(1)
- expect(mockCline.recordToolError).toHaveBeenCalledWith("attempt_completion")
- expect(mockCline.sayAndCreateMissingParamError).toHaveBeenCalledWith("attempt_completion", "result")
- })
-
- it("should handle state retrieval errors gracefully", async () => {
- // Mock provider ref to return null
- mockCline.providerRef.deref.mockReturnValue(null)
-
- // Mock clineMessages to simulate no previous messages
- mockCline.clineMessages = []
-
- const block = {
- params: {
- result: "Task completed successfully",
- command: "npm test",
- },
- partial: false,
- }
-
- await attemptCompletionTool(
- mockCline,
- block as any,
- mockAskApproval,
- mockHandleError,
- mockPushToolResult,
- mockRemoveClosingTag,
- mockToolDescription,
- mockAskFinishSubTaskApproval,
- )
-
- // When state retrieval fails, it defaults to not disabled (false), so it will try to execute command
- // Since there's no lastMessage, it goes directly to askApproval
- expect(mockAskApproval).toHaveBeenCalledWith("command", "npm test")
- expect(mockCline.say).not.toHaveBeenCalled()
- })
- })
-})
diff --git a/src/core/tools/__tests__/writeToFileTool.spec.ts b/src/core/tools/__tests__/writeToFileTool.spec.ts
index 47a674cdfb..f223d4b0fc 100644
--- a/src/core/tools/__tests__/writeToFileTool.spec.ts
+++ b/src/core/tools/__tests__/writeToFileTool.spec.ts
@@ -243,14 +243,14 @@ describe("writeToFileTool", () => {
})
describe("file existence detection", () => {
- it("detects existing file and sets editType to modify", async () => {
+ it.skipIf(process.platform === "win32")("detects existing file and sets editType to modify", async () => {
await executeWriteFileTool({}, { fileExists: true })
expect(mockedFileExistsAtPath).toHaveBeenCalledWith(absoluteFilePath)
expect(mockCline.diffViewProvider.editType).toBe("modify")
})
- it("detects new file and sets editType to create", async () => {
+ it.skipIf(process.platform === "win32")("detects new file and sets editType to create", async () => {
await executeWriteFileTool({}, { fileExists: false })
expect(mockedFileExistsAtPath).toHaveBeenCalledWith(absoluteFilePath)
diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts
index d45ce0f65c..57f5870022 100644
--- a/src/core/tools/attemptCompletionTool.ts
+++ b/src/core/tools/attemptCompletionTool.ts
@@ -14,8 +14,6 @@ import {
AskFinishSubTaskApproval,
} from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
-import { type ExecuteCommandOptions, executeCommand } from "./executeCommandTool"
-import { EXPERIMENT_IDS, experiments, experimentDefault } from "../../shared/experiments"
export async function attemptCompletionTool(
cline: Task,
@@ -67,48 +65,11 @@ export async function attemptCompletionTool(
cline.consecutiveMistakeCount = 0
- let commandResult: ToolResponse | undefined
-
- // Check if command execution is disabled via experiment
- const state = await cline.providerRef.deref()?.getState()
- const experimentsConfig = state?.experiments ?? experimentDefault
- const isCommandDisabled = experiments.isEnabled(
- experimentsConfig,
- EXPERIMENT_IDS.DISABLE_COMPLETION_COMMAND,
- )
-
- if (command && !isCommandDisabled) {
- if (lastMessage && lastMessage.ask !== "command") {
- // Haven't sent a command message yet so first send completion_result then command.
- await cline.say("completion_result", result, undefined, false)
- TelemetryService.instance.captureTaskCompleted(cline.taskId)
- cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
- }
-
- // Complete command message.
- const didApprove = await askApproval("command", command)
-
- if (!didApprove) {
- return
- }
-
- const executionId = cline.lastMessageTs?.toString() ?? Date.now().toString()
- const options: ExecuteCommandOptions = { executionId, command }
- const [userRejected, execCommandResult] = await executeCommand(cline, options)
-
- if (userRejected) {
- cline.didRejectTool = true
- pushToolResult(execCommandResult)
- return
- }
-
- // User didn't reject, but the command may have output.
- commandResult = execCommandResult
- } else {
- await cline.say("completion_result", result, undefined, false)
- TelemetryService.instance.captureTaskCompleted(cline.taskId)
- cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
- }
+ // Command execution is permanently disabled in attempt_completion
+ // Users must use execute_command tool separately before attempt_completion
+ await cline.say("completion_result", result, undefined, false)
+ TelemetryService.instance.captureTaskCompleted(cline.taskId)
+ cline.emit("taskCompleted", cline.taskId, cline.getTokenUsage(), cline.toolUsage)
if (cline.parentTask) {
const didApprove = await askFinishSubTaskApproval()
@@ -138,14 +99,6 @@ export async function attemptCompletionTool(
await cline.say("user_feedback", text ?? "", images)
const toolResults: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = []
- if (commandResult) {
- if (typeof commandResult === "string") {
- toolResults.push({ type: "text", text: commandResult })
- } else if (Array.isArray(commandResult)) {
- toolResults.push(...commandResult)
- }
- }
-
toolResults.push({
type: "text",
text: `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n\n${text}\n `,
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 94264ba0de..dff2263a06 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -23,6 +23,7 @@ import {
type TerminalActionPromptType,
type HistoryItem,
type CloudUserInfo,
+ type MarketplaceItem,
requestyDefaultModelId,
openRouterDefaultModelId,
glamaDefaultModelId,
@@ -37,7 +38,7 @@ import { Package } from "../../shared/package"
import { findLast } from "../../shared/array"
import { supportPrompt } from "../../shared/support-prompt"
import { GlobalFileNames } from "../../shared/globalFileNames"
-import { ExtensionMessage } from "../../shared/ExtensionMessage"
+import { ExtensionMessage, MarketplaceInstalledMetadata } from "../../shared/ExtensionMessage"
import { Mode, defaultModeSlug } from "../../shared/modes"
import { experimentDefault, experiments, EXPERIMENT_IDS } from "../../shared/experiments"
import { formatLanguage } from "../../shared/language"
@@ -108,7 +109,7 @@ export class ClineProvider
public isViewLaunched = false
public settingsImportedAt?: number
- public readonly latestAnnouncementId = "dec-12-2025-3-20" // Update for v3.20.0 announcement
+ public readonly latestAnnouncementId = "jun-17-2025-3-21" // Update for v3.21.0 announcement
public readonly providerSettingsManager: ProviderSettingsManager
public readonly customModesManager: CustomModesManager
@@ -232,6 +233,12 @@ export class ClineProvider
await this.getCurrentCline()?.resumePausedTask(lastMessage)
}
+ // Clear the current task without treating it as a subtask
+ // This is used when the user cancels a task that is not a subtask
+ async clearTask() {
+ await this.removeClineFromStack()
+ }
+
/*
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/
@@ -665,7 +672,7 @@ export class ClineProvider
const csp = [
"default-src 'none'",
- `font-src ${webview.cspSource}`,
+ `font-src ${webview.cspSource} data:`,
`style-src ${webview.cspSource} 'unsafe-inline' https://* http://${localServerUrl} http://0.0.0.0:${localPort}`,
`img-src ${webview.cspSource} https://storage.googleapis.com https://img.clerk.com data:`,
`media-src ${webview.cspSource}`,
@@ -752,7 +759,7 @@ export class ClineProvider
-
+