diff --git a/.changeset/wise-icons-sort.md b/.changeset/wise-icons-sort.md deleted file mode 100644 index d0f4c388350..00000000000 --- a/.changeset/wise-icons-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Support mentioning binary files diff --git a/.husky/pre-commit b/.husky/pre-commit index 7abf8c85034..d6393597652 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -5,4 +5,11 @@ branch="$(git rev-parse --abbrev-ref HEAD)" # exit 1 # fi -npx lint-staged +# Detect if running on Windows and use npx.cmd, otherwise use npx +if [ "$OS" = "Windows_NT" ]; then + npx_cmd="npx.cmd" +else + npx_cmd="npx" +fi + +"$npx_cmd" lint-staged \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push index 773cedb6c02..f6549c707d0 100644 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -5,7 +5,14 @@ branch="$(git rev-parse --abbrev-ref HEAD)" # exit 1 # fi -npm run compile +# Detect if running on Windows and use npm.cmd, otherwise use npm +if [ "$OS" = "Windows_NT" ]; then + npm_cmd="npm.cmd" +else + npm_cmd="npm" +fi + +"$npm_cmd" run compile # Check for new changesets. NEW_CHANGESETS=$(find .changeset -name "*.md" ! -name "README.md" | wc -l | tr -d ' ') diff --git a/.vscodeignore b/.vscodeignore index a8cac01b118..560897b9677 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -48,8 +48,9 @@ webview-ui/node_modules/** # Include default themes JSON files used in getTheme !src/integrations/theme/default-themes/** -# Include icons +# Include icons and images !assets/icons/** +!assets/images/** # Include .env file for telemetry !.env diff --git a/CHANGELOG.md b/CHANGELOG.md index 1339300648d..e99bdb354f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Roo Code Changelog +## [3.10.3] - 2025-03-23 + +- Update the welcome page to provide 1-click OAuth flows with LLM routers (thanks @dtrugman!) +- Switch to a more direct method of tracking OpenRouter tokens/spend +- Make partial file reads backwards-compatible with custom system prompts and give users more control over the chunk size +- Fix issues where questions and suggestions weren’t showing up for non-streaming models and were hard to read in some themes +- A variety of fixes and improvements to experimental multi-block diff (thanks @KJ7LNW!) +- Fix opacity of drop-down menus in settings (thanks @KJ7LNW!) +- Fix bugs with reading and mentioning binary files like PDFs +- Fix the pricing information for OpenRouter free models (thanks @Jdo300!) +- Fix an issue with our unit tests on Windows (thanks @diarmidmackenzie!) +- Fix a maxTokens issue for the Outbound provider (thanks @pugazhendhi-m!) +- Fix a line number issue with partial file reads (thanks @samhvw8!) + ## [3.10.2] - 2025-03-21 - Fixes to context mentions on Windows diff --git a/assets/images/openrouter.png b/assets/images/openrouter.png new file mode 100644 index 00000000000..7f2c18d1209 Binary files /dev/null and b/assets/images/openrouter.png differ diff --git a/assets/images/requesty.png b/assets/images/requesty.png new file mode 100644 index 00000000000..1a250ccd95d Binary files /dev/null and b/assets/images/requesty.png differ diff --git a/locales/ca/README.md b/locales/ca/README.md index 2cde98ebe34..3105a140180 100644 --- a/locales/ca/README.md +++ b/locales/ca/README.md @@ -179,6 +179,8 @@ Gràcies a tots els nostres col·laboradors que han ajudat a millorar Roo Code! +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Gràcies a tots els nostres col·laboradors que han ajudat a millorar Roo Code! | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Llicència diff --git a/locales/de/README.md b/locales/de/README.md index 987b0f382d9..812415b784a 100644 --- a/locales/de/README.md +++ b/locales/de/README.md @@ -179,6 +179,8 @@ Danke an alle unsere Mitwirkenden, die geholfen haben, Roo Code zu verbessern! +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Danke an alle unsere Mitwirkenden, die geholfen haben, Roo Code zu verbessern! | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Lizenz diff --git a/locales/es/README.md b/locales/es/README.md index 4f264014831..c5e39e1757d 100644 --- a/locales/es/README.md +++ b/locales/es/README.md @@ -179,6 +179,8 @@ Usamos [changesets](https://github.com/changesets/changesets) para versionar y p +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Usamos [changesets](https://github.com/changesets/changesets) para versionar y p | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Licencia diff --git a/locales/fr/README.md b/locales/fr/README.md index b3072596f66..57cf3e489d9 100644 --- a/locales/fr/README.md +++ b/locales/fr/README.md @@ -179,6 +179,8 @@ Merci à tous nos contributeurs qui ont aidé à améliorer Roo Code ! +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Merci à tous nos contributeurs qui ont aidé à améliorer Roo Code ! | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Licence diff --git a/locales/hi/README.md b/locales/hi/README.md index e0b6b36bc72..70ced677b16 100644 --- a/locales/hi/README.md +++ b/locales/hi/README.md @@ -179,6 +179,8 @@ Roo Code को बेहतर बनाने में मदद करने +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Roo Code को बेहतर बनाने में मदद करने | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## लाइसेंस diff --git a/locales/it/README.md b/locales/it/README.md index 679e5f96892..c50994aba66 100644 --- a/locales/it/README.md +++ b/locales/it/README.md @@ -179,6 +179,8 @@ Grazie a tutti i nostri contributori che hanno aiutato a migliorare Roo Code! +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Grazie a tutti i nostri contributori che hanno aiutato a migliorare Roo Code! | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Licenza diff --git a/locales/ja/README.md b/locales/ja/README.md index 44e05874c3d..ea4eb90372d 100644 --- a/locales/ja/README.md +++ b/locales/ja/README.md @@ -179,6 +179,8 @@ Roo Codeの改善に貢献してくれたすべての貢献者に感謝します +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Roo Codeの改善に貢献してくれたすべての貢献者に感謝します | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## ライセンス diff --git a/locales/ko/README.md b/locales/ko/README.md index f9fc879f9cd..06fef166725 100644 --- a/locales/ko/README.md +++ b/locales/ko/README.md @@ -179,6 +179,8 @@ Roo Code를 더 좋게 만드는 데 도움을 준 모든 기여자에게 감사 +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Roo Code를 더 좋게 만드는 데 도움을 준 모든 기여자에게 감사 | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## 라이선스 diff --git a/locales/pl/README.md b/locales/pl/README.md index 297c690f379..00752ab7d75 100644 --- a/locales/pl/README.md +++ b/locales/pl/README.md @@ -179,6 +179,8 @@ Dziękujemy wszystkim naszym współtwórcom, którzy pomogli ulepszyć Roo Code +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Dziękujemy wszystkim naszym współtwórcom, którzy pomogli ulepszyć Roo Code | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Licencja diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md index e3708eabfb2..e7d5c146b21 100644 --- a/locales/pt-BR/README.md +++ b/locales/pt-BR/README.md @@ -179,6 +179,8 @@ Obrigado a todos os nossos contribuidores que ajudaram a tornar o Roo Code melho +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Obrigado a todos os nossos contribuidores que ajudaram a tornar o Roo Code melho | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Licença diff --git a/locales/tr/README.md b/locales/tr/README.md index 5904450c7a0..dc44e41b299 100644 --- a/locales/tr/README.md +++ b/locales/tr/README.md @@ -179,6 +179,8 @@ Roo Code'u daha iyi hale getirmeye yardımcı olan tüm katkıda bulunanlara te +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Roo Code'u daha iyi hale getirmeye yardımcı olan tüm katkıda bulunanlara te | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Lisans diff --git a/locales/vi/README.md b/locales/vi/README.md index c929c5f4753..4d87279e782 100644 --- a/locales/vi/README.md +++ b/locales/vi/README.md @@ -179,6 +179,8 @@ Cảm ơn tất cả những người đóng góp đã giúp cải thiện Roo C +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ Cảm ơn tất cả những người đóng góp đã giúp cải thiện Roo C | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## Giấy Phép diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md index f1e2e3a668b..d3112e15af6 100644 --- a/locales/zh-CN/README.md +++ b/locales/zh-CN/README.md @@ -179,6 +179,8 @@ code --install-extension bin/roo-cline-.vsix +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ code --install-extension bin/roo-cline-.vsix | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## 许可证 diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md index cd3c24fcf90..ee806168702 100644 --- a/locales/zh-TW/README.md +++ b/locales/zh-TW/README.md @@ -179,6 +179,8 @@ code --install-extension bin/roo-cline-.vsix +<<<<<<< HEAD + | mrubens
mrubens
| saoudrizwan
saoudrizwan
| cte
cte
| samhvw8
samhvw8
| daniel-lxs
daniel-lxs
| a8trejo
a8trejo
| | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | ColemanRoo
ColemanRoo
| stea9499
stea9499
| joemanley201
joemanley201
| System233
System233
| jquanton
jquanton
| nissa-seru
nissa-seru
| @@ -197,6 +199,27 @@ code --install-extension bin/roo-cline-.vsix | eltociear
eltociear
| libertyteeth
libertyteeth
| mamertofabian
mamertofabian
| marvijo-code
marvijo-code
| Sarke
Sarke
| tgfjt
tgfjt
| | vladstudio
vladstudio
| Yoshino-Yukitaro
Yoshino-Yukitaro
| ashktn
ashktn
| | | | +======= +|mrubens
mrubens
|saoudrizwan
saoudrizwan
|cte
cte
|samhvw8
samhvw8
|daniel-lxs
daniel-lxs
|a8trejo
a8trejo
| +|:---:|:---:|:---:|:---:|:---:|:---:| +|ColemanRoo
ColemanRoo
|stea9499
stea9499
|joemanley201
joemanley201
|System233
System233
|nissa-seru
nissa-seru
|jquanton
jquanton
| +|NyxJae
NyxJae
|MuriloFP
MuriloFP
|hannesrudolph
hannesrudolph
|d-oit
d-oit
|punkpeye
punkpeye
|monotykamary
monotykamary
| +|lloydchang
lloydchang
|vigneshsubbiah16
vigneshsubbiah16
|Szpadel
Szpadel
|cannuri
cannuri
|lupuletic
lupuletic
|Smartsheet-JB-Brown
Smartsheet-JB-Brown
| +|Premshay
Premshay
|psv2522
psv2522
|olweraltuve
olweraltuve
|wkordalski
wkordalski
|qdaxb
qdaxb
|feifei325
feifei325
| +|RaySinner
RaySinner
|afshawnlotfi
afshawnlotfi
|emshvac
emshvac
|pdecat
pdecat
|Lunchb0ne
Lunchb0ne
|pugazhendhi-m
pugazhendhi-m
| +|sammcj
sammcj
|KJ7LNW
KJ7LNW
|dtrugman
dtrugman
|aitoroses
aitoroses
|yt3trees
yt3trees
|yongjer
yongjer
| +|vincentsong
vincentsong
|eonghk
eonghk
|arthurauffray
arthurauffray
|aheizi
aheizi
|heyseth
heyseth
|philfung
philfung
| +|napter
napter
|mdp
mdp
|jcbdev
jcbdev
|GitlyHallows
GitlyHallows
|benzntech
benzntech
|anton-otee
anton-otee
| +|moqimoqidea
moqimoqidea
|olup
olup
|lightrabbit
lightrabbit
|kohii
kohii
|kinandan
kinandan
|im47cn
im47cn
| +|dqroid
dqroid
|dairui1
dairui1
|bannzai
bannzai
|AMHesch
AMHesch
|mosleyit
mosleyit
|oprstchn
oprstchn
| +|philipnext
philipnext
|refactorthis
refactorthis
|samir-nimbly
samir-nimbly
|shaybc
shaybc
|shohei-ihaya
shohei-ihaya
|student20880
student20880
| +|teddyOOXX
teddyOOXX
|PretzelVector
PretzelVector
|adamwlarson
adamwlarson
|alarno
alarno
|andreastempsch
andreastempsch
|Atlogit
Atlogit
| +|dleen
dleen
|dbasclpy
dbasclpy
|celestial-vault
celestial-vault
|franekp
franekp
|DeXtroTip
DeXtroTip
|hesara
hesara
| +|eltociear
eltociear
|libertyteeth
libertyteeth
|mamertofabian
mamertofabian
|marvijo-code
marvijo-code
|Sarke
Sarke
|tgfjt
tgfjt
| +|vladstudio
vladstudio
|Yoshino-Yukitaro
Yoshino-Yukitaro
|ashktn
ashktn
| | | | + +> > > > > > > b659690402626498fd0bfab3581d094fddf9a07d + ## 許可證 diff --git a/package-lock.json b/package-lock.json index 6b0efd9f23a..90534cf55e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pearai-roo-cline", - "version": "3.10.2", + "version": "3.10.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pearai-roo-cline", - "version": "3.10.2", + "version": "3.10.3", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.37.0", diff --git a/package.json b/package.json index 6a25b04f128..073f374560f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "PearAI's integration of Roo Code / Cline, a coding agent.", "publisher": "PearAI", "icon": "assets/icons/pear.png", - "version": "3.10.2", + "version": "3.10.3", "galleryBanner": { "color": "#617A91", "theme": "dark" diff --git a/src/activate/handleUri.ts b/src/activate/handleUri.ts index 05440c7683e..96a24fe6fac 100644 --- a/src/activate/handleUri.ts +++ b/src/activate/handleUri.ts @@ -6,7 +6,6 @@ export const handleUri = async (uri: vscode.Uri) => { const path = uri.path const query = new URLSearchParams(uri.query.replace(/\+/g, "%2B")) const visibleProvider = ClineProvider.getVisibleInstance() - if (!visibleProvider) { return } @@ -26,6 +25,13 @@ export const handleUri = async (uri: vscode.Uri) => { } break } + case "/requesty": { + const code = query.get("code") + if (code) { + await visibleProvider.handleRequestyCallback(code) + } + break + } default: break } diff --git a/src/api/providers/__tests__/openrouter.test.ts b/src/api/providers/__tests__/openrouter.test.ts index 981c9ad096f..996644b07f7 100644 --- a/src/api/providers/__tests__/openrouter.test.ts +++ b/src/api/providers/__tests__/openrouter.test.ts @@ -112,6 +112,16 @@ describe("OpenRouterHandler", () => { }, ], } + // Add usage information in the stream response + yield { + id: "test-id", + choices: [{ delta: {} }], + usage: { + prompt_tokens: 10, + completion_tokens: 20, + cost: 0.001, + }, + } }, } @@ -121,17 +131,6 @@ describe("OpenRouterHandler", () => { completions: { create: mockCreate }, } as any - // Mock axios.get for generation details - ;(axios.get as jest.Mock).mockResolvedValue({ - data: { - data: { - native_tokens_prompt: 10, - native_tokens_completion: 20, - total_cost: 0.001, - }, - }, - }) - const systemPrompt = "test system prompt" const messages: Anthropic.Messages.MessageParam[] = [{ role: "user" as const, content: "test message" }] @@ -153,7 +152,6 @@ describe("OpenRouterHandler", () => { inputTokens: 10, outputTokens: 20, totalCost: 0.001, - fullResponseText: "test response", }) // Verify OpenAI client was called with correct parameters diff --git a/src/api/providers/__tests__/requesty.test.ts b/src/api/providers/__tests__/requesty.test.ts index 47921a1c532..e761b4d765d 100644 --- a/src/api/providers/__tests__/requesty.test.ts +++ b/src/api/providers/__tests__/requesty.test.ts @@ -1,6 +1,6 @@ import { Anthropic } from "@anthropic-ai/sdk" import OpenAI from "openai" -import { ApiHandlerOptions, ModelInfo, requestyModelInfoSaneDefaults } from "../../../shared/api" +import { ApiHandlerOptions, ModelInfo, requestyDefaultModelInfo } from "../../../shared/api" import { RequestyHandler } from "../requesty" import { convertToOpenAiMessages } from "../../transform/openai-format" import { convertToR1Format } from "../../transform/r1-format" @@ -18,14 +18,17 @@ describe("RequestyHandler", () => { requestyApiKey: "test-key", requestyModelId: "test-model", requestyModelInfo: { - maxTokens: 1000, - contextWindow: 4000, - supportsPromptCache: false, + maxTokens: 8192, + contextWindow: 200_000, supportsImages: true, - inputPrice: 1, - outputPrice: 10, - cacheReadsPrice: 0.1, - cacheWritesPrice: 1.5, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 3.0, + outputPrice: 15.0, + cacheWritesPrice: 3.75, + cacheReadsPrice: 0.3, + description: + "Claude 3.7 Sonnet is an advanced large language model with improved reasoning, coding, and problem-solving capabilities. It introduces a hybrid reasoning approach, allowing users to choose between rapid responses and extended, step-by-step processing for complex tasks. The model demonstrates notable improvements in coding, particularly in front-end development and full-stack updates, and excels in agentic workflows, where it can autonomously navigate multi-step processes. Claude 3.7 Sonnet maintains performance parity with its predecessor in standard mode while offering an extended reasoning mode for enhanced accuracy in math, coding, and instruction-following tasks. Read more at the [blog post here](https://www.anthropic.com/news/claude-3-7-sonnet)", }, openAiStreamingEnabled: true, includeMaxTokens: true, // Add this to match the implementation @@ -115,7 +118,7 @@ describe("RequestyHandler", () => { outputTokens: 10, cacheWriteTokens: 5, cacheReadTokens: 15, - totalCost: 0.000119, // (10 * 1 / 1,000,000) + (5 * 1.5 / 1,000,000) + (15 * 0.1 / 1,000,000) + (10 * 10 / 1,000,000) + totalCost: 0.00020325000000000003, // (10 * 3 / 1,000,000) + (5 * 3.75 / 1,000,000) + (15 * 0.3 / 1,000,000) + (10 * 15 / 1,000,000) (the ...0 is a fp skew) }, ]) @@ -123,8 +126,30 @@ describe("RequestyHandler", () => { model: defaultOptions.requestyModelId, temperature: 0, messages: [ - { role: "system", content: systemPrompt }, - { role: "user", content: "Hello" }, + { + role: "system", + content: [ + { + cache_control: { + type: "ephemeral", + }, + text: systemPrompt, + type: "text", + }, + ], + }, + { + role: "user", + content: [ + { + cache_control: { + type: "ephemeral", + }, + text: "Hello", + type: "text", + }, + ], + }, ], stream: true, stream_options: { include_usage: true }, @@ -191,7 +216,7 @@ describe("RequestyHandler", () => { outputTokens: 5, cacheWriteTokens: 0, cacheReadTokens: 0, - totalCost: 0.00006, // (10 * 1 / 1,000,000) + (5 * 10 / 1,000,000) + totalCost: 0.000105, // (10 * 3 / 1,000,000) + (5 * 15 / 1,000,000) }, ]) @@ -199,7 +224,18 @@ describe("RequestyHandler", () => { model: defaultOptions.requestyModelId, messages: [ { role: "user", content: systemPrompt }, - { role: "user", content: "Hello" }, + { + role: "user", + content: [ + { + cache_control: { + type: "ephemeral", + }, + text: "Hello", + type: "text", + }, + ], + }, ], }) }) @@ -224,7 +260,7 @@ describe("RequestyHandler", () => { const result = handler.getModel() expect(result).toEqual({ id: defaultOptions.requestyModelId, - info: requestyModelInfoSaneDefaults, + info: defaultOptions.requestyModelInfo, }) }) }) diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index 3f215bfc7c3..72e4fe576a9 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -24,11 +24,6 @@ type OpenRouterChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParams & { thinking?: BetaThinkingConfigParam } -// Add custom interface for OpenRouter usage chunk. -interface OpenRouterApiStreamUsageChunk extends ApiStreamUsageChunk { - fullResponseText: string -} - export class OpenRouterHandler extends BaseProvider implements SingleCompletionHandler { protected options: ApiHandlerOptions private client: OpenAI @@ -110,7 +105,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH top_p: topP, messages: openAiMessages, stream: true, - include_reasoning: true, + stream_options: { include_usage: true }, // Only include provider if openRouterSpecificProvider is not "[default]". ...(this.options.openRouterSpecificProvider && this.options.openRouterSpecificProvider !== OPENROUTER_DEFAULT_PROVIDER_NAME && { @@ -122,7 +117,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH const stream = await this.client.chat.completions.create(completionParams) - let genId: string | undefined + let lastUsage for await (const chunk of stream as unknown as AsyncIterable) { // OpenRouter returns an error object instead of the OpenAI SDK throwing an error. @@ -132,10 +127,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH throw new Error(`OpenRouter API Error ${error?.code}: ${error?.message}`) } - if (!genId && chunk.id) { - genId = chunk.id - } - const delta = chunk.choices[0]?.delta if ("reasoning" in delta && delta.reasoning) { @@ -146,47 +137,23 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH fullResponseText += delta.content yield { type: "text", text: delta.content } as ApiStreamChunk } - } - const endpoint = `${this.client.baseURL}/generation?id=${genId}` - - const config: AxiosRequestConfig = { - headers: { Authorization: `Bearer ${this.options.openRouterApiKey}` }, - timeout: 3_000, + if (chunk.usage) { + lastUsage = chunk.usage + } } - let attempt = 0 - let lastError: Error | undefined - const startTime = Date.now() - - while (attempt++ < 10) { - await delay(attempt * 100) // Give OpenRouter some time to produce the generation metadata. - - try { - const response = await axios.get(endpoint, config) - const generation = response.data?.data - - yield { - type: "usage", - inputTokens: generation?.native_tokens_prompt || 0, - outputTokens: generation?.native_tokens_completion || 0, - totalCost: generation?.total_cost || 0, - fullResponseText, - } as OpenRouterApiStreamUsageChunk - - break - } catch (error: unknown) { - if (error instanceof Error) { - lastError = error - } - } + if (lastUsage) { + yield this.processUsageMetrics(lastUsage) } + } - if (lastError) { - console.error( - `Failed to fetch OpenRouter generation details after attempt #${attempt} (${Date.now() - startTime}ms) [${genId}]`, - lastError, - ) + processUsageMetrics(usage: any): ApiStreamUsageChunk { + return { + type: "usage", + inputTokens: usage?.prompt_tokens || 0, + outputTokens: usage?.completion_tokens || 0, + totalCost: usage?.cost || 0, } } @@ -289,12 +256,13 @@ export async function getOpenRouterModels(options?: ApiHandlerOptions) { modelInfo.maxTokens = 8192 break case rawModel.id.startsWith("anthropic/claude-3-haiku"): - default: modelInfo.supportsPromptCache = true modelInfo.cacheWritesPrice = 0.3 modelInfo.cacheReadsPrice = 0.03 modelInfo.maxTokens = 8192 break + default: + break } models[rawModel.id] = modelInfo diff --git a/src/api/providers/requesty.ts b/src/api/providers/requesty.ts index 434d6f43161..822db1a6b06 100644 --- a/src/api/providers/requesty.ts +++ b/src/api/providers/requesty.ts @@ -1,6 +1,6 @@ import axios from "axios" -import { ModelInfo, requestyModelInfoSaneDefaults, requestyDefaultModelId } from "../../shared/api" +import { ModelInfo, requestyDefaultModelInfo, requestyDefaultModelId } from "../../shared/api" import { calculateApiCostOpenAI, parseApiPrice } from "../../utils/cost" import { ApiStreamUsageChunk } from "../transform/stream" import { OpenAiHandler, OpenAiHandlerOptions } from "./openai" @@ -26,7 +26,7 @@ export class RequestyHandler extends OpenAiHandler { openAiApiKey: options.requestyApiKey, openAiModelId: options.requestyModelId ?? requestyDefaultModelId, openAiBaseUrl: "https://router.requesty.ai/v1", - openAiCustomModelInfo: options.requestyModelInfo ?? requestyModelInfoSaneDefaults, + openAiCustomModelInfo: options.requestyModelInfo ?? requestyDefaultModelInfo, }) } @@ -34,7 +34,7 @@ export class RequestyHandler extends OpenAiHandler { const modelId = this.options.requestyModelId ?? requestyDefaultModelId return { id: modelId, - info: this.options.requestyModelInfo ?? requestyModelInfoSaneDefaults, + info: this.options.requestyModelInfo ?? requestyDefaultModelInfo, } } diff --git a/src/api/providers/unbound.ts b/src/api/providers/unbound.ts index 38cd494cdd3..f83ecd457b9 100644 --- a/src/api/providers/unbound.ts +++ b/src/api/providers/unbound.ts @@ -212,7 +212,10 @@ export async function getUnboundModels() { switch (true) { case modelId.startsWith("anthropic/"): - modelInfo.maxTokens = 8192 + // Set max tokens to 8192 for supported Anthropic models + if (modelInfo.maxTokens !== 4096) { + modelInfo.maxTokens = 8192 + } break default: break diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 21ad1ae0a85..0c31b30d648 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -82,6 +82,7 @@ import { validateToolUse, isToolAllowedForMode, ToolName } from "./mode-validato import { parseXml } from "../utils/xml" import { readLines } from "../integrations/misc/read-lines" import { getWorkspacePath } from "../utils/path" +import { isBinaryFile } from "isbinaryfile" type ToolResponse = string | Array type UserContent = Array @@ -2324,25 +2325,28 @@ export class Cline extends EventEmitter { let isFileTruncated = false let sourceCodeDef = "" + const isBinary = await isBinaryFile(absolutePath).catch(() => false) + const autoTruncate = block.params.auto_truncate === "true" + if (isRangeRead) { if (startLine === undefined) { content = addLineNumbers(await readLines(absolutePath, endLine, startLine)) } else { content = addLineNumbers( await readLines(absolutePath, endLine, startLine), - startLine, + startLine + 1, ) } - } else if (totalLines > maxReadFileLine) { + } else if (autoTruncate && !isBinary && totalLines > maxReadFileLine) { // If file is too large, only read the first maxReadFileLine lines isFileTruncated = true const res = await Promise.all([ - readLines(absolutePath, maxReadFileLine - 1, 0), + maxReadFileLine > 0 ? readLines(absolutePath, maxReadFileLine - 1, 0) : "", parseSourceCodeDefinitionsForFile(absolutePath, this.rooIgnoreController), ]) - content = addLineNumbers(res[0]) + content = res[0].length > 0 ? addLineNumbers(res[0]) : "" const result = res[1] if (result) { sourceCodeDef = `\n\n${result}` @@ -2354,7 +2358,7 @@ export class Cline extends EventEmitter { // Add truncation notice if applicable if (isFileTruncated) { - content += `\n\n[File truncated: showing ${maxReadFileLine} of ${totalLines} total lines. Use start_line and end_line if you need to read more.].${sourceCodeDef}` + content += `\n\n[File truncated: showing ${maxReadFileLine} of ${totalLines} total lines. Use start_line and end_line or set auto_truncate to false if you need to read more.].${sourceCodeDef}` } pushToolResult(content) diff --git a/src/core/assistant-message/index.ts b/src/core/assistant-message/index.ts index 81e6edb95b9..5409c4bbe22 100644 --- a/src/core/assistant-message/index.ts +++ b/src/core/assistant-message/index.ts @@ -51,6 +51,7 @@ export const toolParamNames = [ "diff", "start_line", "end_line", + "auto_truncate", "mode_slug", "reason", "operations", diff --git a/src/core/diff/strategies/__tests__/multi-search-replace.test.ts b/src/core/diff/strategies/__tests__/multi-search-replace.test.ts index 8fc16d2303e..e4a52af6d4b 100644 --- a/src/core/diff/strategies/__tests__/multi-search-replace.test.ts +++ b/src/core/diff/strategies/__tests__/multi-search-replace.test.ts @@ -1,16 +1,64 @@ import { MultiSearchReplaceDiffStrategy } from "../multi-search-replace" describe("MultiSearchReplaceDiffStrategy", () => { - describe("exact matching", () => { + describe("validateMarkerSequencing", () => { let strategy: MultiSearchReplaceDiffStrategy beforeEach(() => { - strategy = new MultiSearchReplaceDiffStrategy(1.0, 5) // Default 1.0 threshold for exact matching, 5 line buffer for tests + strategy = new MultiSearchReplaceDiffStrategy() }) - it("should replace matching content", async () => { - const originalContent = 'function hello() {\n console.log("hello")\n}\n' - const diffContent = `test.ts + it("validates correct marker sequence", () => { + const diff = "<<<<<<< SEARCH\n" + "some content\n" + "=======\n" + "new content\n" + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("validates multiple correct marker sequences", () => { + const diff = + "<<<<<<< SEARCH\n" + + "content1\n" + + "=======\n" + + "new1\n" + + ">>>>>>> REPLACE\n\n" + + "<<<<<<< SEARCH\n" + + "content2\n" + + "=======\n" + + "new2\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("detects separator before search", () => { + const diff = "=======\n" + "content\n" + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(false) + expect(result.error).toContain("'=======' found in your diff content") + }) + + it("detects replace before separator", () => { + const diff = "<<<<<<< SEARCH\n" + "content\n" + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(false) + expect(result.error).toContain("'>>>>>>> REPLACE' found in your diff content") + }) + + it("detects incomplete sequence", () => { + const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(false) + expect(result.error).toContain("Expected '>>>>>>> REPLACE' was not found") + }) + + describe("exact matching", () => { + let strategy: MultiSearchReplaceDiffStrategy + + beforeEach(() => { + strategy = new MultiSearchReplaceDiffStrategy(1.0, 5) // Default 1.0 threshold for exact matching, 5 line buffer for tests + }) + + it("should replace matching content", async () => { + const originalContent = 'function hello() {\n console.log("hello")\n}\n' + const diffContent = `test.ts <<<<<<< SEARCH function hello() { console.log("hello") @@ -21,16 +69,16 @@ function hello() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe('function hello() {\n console.log("hello world")\n}\n') - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe('function hello() {\n console.log("hello world")\n}\n') + } + }) - it("should match content with different surrounding whitespace", async () => { - const originalContent = "\nfunction example() {\n return 42;\n}\n\n" - const diffContent = `test.ts + it("should match content with different surrounding whitespace", async () => { + const originalContent = "\nfunction example() {\n return 42;\n}\n\n" + const diffContent = `test.ts <<<<<<< SEARCH function example() { return 42; @@ -41,16 +89,16 @@ function example() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("\nfunction example() {\n return 43;\n}\n\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("\nfunction example() {\n return 43;\n}\n\n") + } + }) - it("should match content with different indentation in search block", async () => { - const originalContent = " function test() {\n return true;\n }\n" - const diffContent = `test.ts + it("should match content with different indentation in search block", async () => { + const originalContent = " function test() {\n return true;\n }\n" + const diffContent = `test.ts <<<<<<< SEARCH function test() { return true; @@ -61,16 +109,16 @@ function test() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(" function test() {\n return false;\n }\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(" function test() {\n return false;\n }\n") + } + }) - it("should handle tab-based indentation", async () => { - const originalContent = "function test() {\n\treturn true;\n}\n" - const diffContent = `test.ts + it("should handle tab-based indentation", async () => { + const originalContent = "function test() {\n\treturn true;\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH function test() { \treturn true; @@ -81,16 +129,16 @@ function test() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("function test() {\n\treturn false;\n}\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("function test() {\n\treturn false;\n}\n") + } + }) - it("should preserve mixed tabs and spaces", async () => { - const originalContent = "\tclass Example {\n\t constructor() {\n\t\tthis.value = 0;\n\t }\n\t}" - const diffContent = `test.ts + it("should preserve mixed tabs and spaces", async () => { + const originalContent = "\tclass Example {\n\t constructor() {\n\t\tthis.value = 0;\n\t }\n\t}" + const diffContent = `test.ts <<<<<<< SEARCH \tclass Example { \t constructor() { @@ -105,18 +153,18 @@ function test() { \t} >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe( - "\tclass Example {\n\t constructor() {\n\t\tthis.value = 1;\n\t }\n\t}", - ) - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe( + "\tclass Example {\n\t constructor() {\n\t\tthis.value = 1;\n\t }\n\t}", + ) + } + }) - it("should handle additional indentation with tabs", async () => { - const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}" - const diffContent = `test.ts + it("should handle additional indentation with tabs", async () => { + const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}" + const diffContent = `test.ts <<<<<<< SEARCH function test() { \treturn true; @@ -128,16 +176,16 @@ function test() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("\tfunction test() {\n\t\t// Add comment\n\t\treturn false;\n\t}") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("\tfunction test() {\n\t\t// Add comment\n\t\treturn false;\n\t}") + } + }) - it("should preserve exact indentation characters when adding lines", async () => { - const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}" - const diffContent = `test.ts + it("should preserve exact indentation characters when adding lines", async () => { + const originalContent = "\tfunction test() {\n\t\treturn true;\n\t}" + const diffContent = `test.ts <<<<<<< SEARCH \tfunction test() { \t\treturn true; @@ -150,18 +198,18 @@ function test() { \t} >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe( - "\tfunction test() {\n\t\t// First comment\n\t\t// Second comment\n\t\treturn true;\n\t}", - ) - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe( + "\tfunction test() {\n\t\t// First comment\n\t\t// Second comment\n\t\treturn true;\n\t}", + ) + } + }) - it("should handle Windows-style CRLF line endings", async () => { - const originalContent = "function test() {\r\n return true;\r\n}\r\n" - const diffContent = `test.ts + it("should handle Windows-style CRLF line endings", async () => { + const originalContent = "function test() {\r\n return true;\r\n}\r\n" + const diffContent = `test.ts <<<<<<< SEARCH function test() { return true; @@ -172,16 +220,16 @@ function test() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("function test() {\r\n return false;\r\n}\r\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("function test() {\r\n return false;\r\n}\r\n") + } + }) - it("should return false if search content does not match", async () => { - const originalContent = 'function hello() {\n console.log("hello")\n}\n' - const diffContent = `test.ts + it("should return false if search content does not match", async () => { + const originalContent = 'function hello() {\n console.log("hello")\n}\n' + const diffContent = `test.ts <<<<<<< SEARCH function hello() { console.log("wrong") @@ -192,22 +240,22 @@ function hello() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(false) - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(false) + }) - it("should return false if diff format is invalid", async () => { - const originalContent = 'function hello() {\n console.log("hello")\n}\n' - const diffContent = `test.ts\nInvalid diff format` + it("should return false if diff format is invalid", async () => { + const originalContent = 'function hello() {\n console.log("hello")\n}\n' + const diffContent = `test.ts\nInvalid diff format` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(false) - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(false) + }) - it("should handle multiple lines with proper indentation", async () => { - const originalContent = - "class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n return this.value\n }\n}\n" - const diffContent = `test.ts + it("should handle multiple lines with proper indentation", async () => { + const originalContent = + "class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n return this.value\n }\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH getValue() { return this.value @@ -220,18 +268,18 @@ function hello() { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe( - 'class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n // Add logging\n console.log("Getting value")\n return this.value\n }\n}\n', - ) - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe( + 'class Example {\n constructor() {\n this.value = 0\n }\n\n getValue() {\n // Add logging\n console.log("Getting value")\n return this.value\n }\n}\n', + ) + } + }) - it("should preserve whitespace exactly in the output", async () => { - const originalContent = " indented\n more indented\n back\n" - const diffContent = `test.ts + it("should preserve whitespace exactly in the output", async () => { + const originalContent = " indented\n more indented\n back\n" + const diffContent = `test.ts <<<<<<< SEARCH indented more indented @@ -242,16 +290,16 @@ function hello() { end >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(" modified\n still indented\n end\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(" modified\n still indented\n end\n") + } + }) - it("should preserve indentation when adding new lines after existing content", async () => { - const originalContent = " onScroll={() => updateHighlights()}" - const diffContent = `test.ts + it("should preserve indentation when adding new lines after existing content", async () => { + const originalContent = " onScroll={() => updateHighlights()}" + const diffContent = `test.ts <<<<<<< SEARCH onScroll={() => updateHighlights()} ======= @@ -262,17 +310,17 @@ function hello() { }} >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe( - " onScroll={() => updateHighlights()}\n onDragOver={(e) => {\n e.preventDefault()\n e.stopPropagation()\n }}", - ) - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe( + " onScroll={() => updateHighlights()}\n onDragOver={(e) => {\n e.preventDefault()\n e.stopPropagation()\n }}", + ) + } + }) - it("should handle varying indentation levels correctly", async () => { - const originalContent = ` + it("should handle varying indentation levels correctly", async () => { + const originalContent = ` class Example { constructor() { this.value = 0; @@ -282,7 +330,7 @@ class Example { } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH class Example { constructor() { @@ -305,11 +353,11 @@ class Example { } >>>>>>> REPLACE`.trim() - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe( - ` + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe( + ` class Example { constructor() { this.value = 1; @@ -320,12 +368,12 @@ class Example { } } }`.trim(), - ) - } - }) + ) + } + }) - it("should handle mixed indentation styles in the same file", async () => { - const originalContent = `class Example { + it("should handle mixed indentation styles in the same file", async () => { + const originalContent = `class Example { constructor() { this.value = 0; if (true) { @@ -333,7 +381,7 @@ class Example { } } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH constructor() { this.value = 0; @@ -351,10 +399,10 @@ class Example { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`class Example { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`class Example { constructor() { this.value = 1; if (true) { @@ -363,17 +411,17 @@ class Example { } } }`) - } - }) + } + }) - it("should handle Python-style significant whitespace", async () => { - const originalContent = `def example(): + it("should handle Python-style significant whitespace", async () => { + const originalContent = `def example(): if condition: do_something() for item in items: process(item) return True`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH if condition: do_something() @@ -387,28 +435,28 @@ class Example { process(item) >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`def example(): + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`def example(): if condition: do_something() while items: item = items.pop() process(item) return True`) - } - }) + } + }) - it("should preserve empty lines with indentation", async () => { - const originalContent = `function test() { + it("should preserve empty lines with indentation", async () => { + const originalContent = `function test() { const x = 1; if (x) { return true; } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH const x = 1; @@ -420,10 +468,10 @@ class Example { if (x) { >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`function test() { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`function test() { const x = 1; // Check x @@ -431,18 +479,18 @@ class Example { return true; } }`) - } - }) + } + }) - it("should handle indentation when replacing entire blocks", async () => { - const originalContent = `class Test { + it("should handle indentation when replacing entire blocks", async () => { + const originalContent = `class Test { method() { if (true) { console.log("test"); } } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH method() { if (true) { @@ -461,10 +509,10 @@ class Example { } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`class Test { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`class Test { method() { try { if (true) { @@ -475,11 +523,11 @@ class Example { } } }`) - } - }) + } + }) - it("should handle negative indentation relative to search content", async () => { - const originalContent = `class Example { + it("should handle negative indentation relative to search content", async () => { + const originalContent = `class Example { constructor() { if (true) { this.init(); @@ -487,7 +535,7 @@ class Example { } } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH this.init(); this.setup(); @@ -496,10 +544,10 @@ class Example { this.setup(); >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`class Example { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`class Example { constructor() { if (true) { this.init(); @@ -507,39 +555,39 @@ class Example { } } }`) - } - }) + } + }) - it("should handle extreme negative indentation (no indent)", async () => { - const originalContent = `class Example { + it("should handle extreme negative indentation (no indent)", async () => { + const originalContent = `class Example { constructor() { if (true) { this.init(); } } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH this.init(); ======= this.init(); >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`class Example { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`class Example { constructor() { if (true) { this.init(); } } }`) - } - }) + } + }) - it("should handle mixed indentation changes in replace block", async () => { - const originalContent = `class Example { + it("should handle mixed indentation changes in replace block", async () => { + const originalContent = `class Example { constructor() { if (true) { this.init(); @@ -548,7 +596,7 @@ this.init(); } } }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH this.init(); this.setup(); @@ -559,10 +607,10 @@ this.init(); this.validate(); >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`class Example { + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`class Example { constructor() { if (true) { this.init(); @@ -571,11 +619,11 @@ this.init(); } } }`) - } - }) + } + }) - it("should find matches from middle out", async () => { - const originalContent = ` + it("should find matches from middle out", async () => { + const originalContent = ` function one() { return "target"; } @@ -596,20 +644,20 @@ function five() { return "target"; }`.trim() - const diffContent = `test.ts + const diffContent = `test.ts <<<<<<< SEARCH return "target"; ======= return "updated"; >>>>>>> REPLACE` - // Search around the middle (function three) - // Even though all functions contain the target text, - // it should match the one closest to line 9 first - const result = await strategy.applyDiff(originalContent, diffContent, 9, 9) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(`function one() { + // Search around the middle (function three) + // Even though all functions contain the target text, + // it should match the one closest to line 9 first + const result = await strategy.applyDiff(originalContent, diffContent, 9, 9) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(`function one() { return "target"; } @@ -628,21 +676,21 @@ function four() { function five() { return "target"; }`) - } + } + }) }) - }) - describe("line number stripping", () => { describe("line number stripping", () => { - let strategy: MultiSearchReplaceDiffStrategy + describe("line number stripping", () => { + let strategy: MultiSearchReplaceDiffStrategy - beforeEach(() => { - strategy = new MultiSearchReplaceDiffStrategy() - }) + beforeEach(() => { + strategy = new MultiSearchReplaceDiffStrategy() + }) - it("should strip line numbers from both search and replace sections", async () => { - const originalContent = "function test() {\n return true;\n}\n" - const diffContent = `test.ts + it("should strip line numbers from both search and replace sections", async () => { + const originalContent = "function test() {\n return true;\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH 1 | function test() { 2 | return true; @@ -653,16 +701,16 @@ function five() { 3 | } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("function test() {\n return false;\n}\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("function test() {\n return false;\n}\n") + } + }) - it("should strip line numbers with leading spaces", async () => { - const originalContent = "function test() {\n return true;\n}\n" - const diffContent = `test.ts + it("should strip line numbers with leading spaces", async () => { + const originalContent = "function test() {\n return true;\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH 1 | function test() { 2 | return true; @@ -673,16 +721,16 @@ function five() { 3 | } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("function test() {\n return false;\n}\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("function test() {\n return false;\n}\n") + } + }) - it("should not strip when not all lines have numbers in either section", async () => { - const originalContent = "function test() {\n return true;\n}\n" - const diffContent = `test.ts + it("should not strip when not all lines have numbers in either section", async () => { + const originalContent = "function test() {\n return true;\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH 1 | function test() { 2 | return true; @@ -693,13 +741,13 @@ function five() { 3 | } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(false) - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(false) + }) - it("should preserve content that naturally starts with pipe", async () => { - const originalContent = "|header|another|\n|---|---|\n|data|more|\n" - const diffContent = `test.ts + it("should preserve content that naturally starts with pipe", async () => { + const originalContent = "|header|another|\n|---|---|\n|data|more|\n" + const diffContent = `test.ts <<<<<<< SEARCH 1 | |header|another| 2 | |---|---| @@ -710,16 +758,16 @@ function five() { 3 | |data|updated| >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("|header|another|\n|---|---|\n|data|updated|\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("|header|another|\n|---|---|\n|data|updated|\n") + } + }) - it("should preserve indentation when stripping line numbers", async () => { - const originalContent = " function test() {\n return true;\n }\n" - const diffContent = `test.ts + it("should preserve indentation when stripping line numbers", async () => { + const originalContent = " function test() {\n return true;\n }\n" + const diffContent = `test.ts <<<<<<< SEARCH 1 | function test() { 2 | return true; @@ -730,16 +778,16 @@ function five() { 3 | } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe(" function test() {\n return false;\n }\n") - } - }) + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe(" function test() {\n return false;\n }\n") + } + }) - it("should handle different line numbers between sections", async () => { - const originalContent = "function test() {\n return true;\n}\n" - const diffContent = `test.ts + it("should handle different line numbers between sections", async () => { + const originalContent = "function test() {\n return true;\n}\n" + const diffContent = `test.ts <<<<<<< SEARCH 10 | function test() { 11 | return true; @@ -750,11 +798,563 @@ function five() { 22 | } >>>>>>> REPLACE` - const result = await strategy.applyDiff(originalContent, diffContent) - expect(result.success).toBe(true) - if (result.success) { - expect(result.content).toBe("function test() {\n return false;\n}\n") - } + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("function test() {\n return false;\n}\n") + } + }) + + it("detects search marker when expecting replace", () => { + const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content\n" + "<<<<<<< SEARCH" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(false) + expect(result.error).toContain("'<<<<<<< SEARCH' found in your diff content") + }) + + it("allows escaped search marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(true) + }) + + it("allows escaped separator in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(true) + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "test.ts\n" + + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "test.ts\n" + + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("allows escaped search marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped separator in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped search marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped search marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped separator in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped replace marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped separator in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped replace marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("allows escaped replace marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + expect(strategy["validateMarkerSequencing"](diff).success).toBe(true) + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "replaced content\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("replaced content\n") + } + }) + + it("processes escaped replace marker in content", async () => { + const originalContent = "before\n>>>>>>> REPLACE\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes multiple escaped markers in content", async () => { + const originalContent = "<<<<<<< SEARCH\n=======\n>>>>>>> REPLACE\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "\\<<<<<<< SEARCH\n" + + "\\=======\n" + + "\\>>>>>>> REPLACE\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped search marker in content", async () => { + const originalContent = "before\n<<<<<<< SEARCH\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\<<<<<<< SEARCH\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped replace marker in content", async () => { + const originalContent = "before\n>>>>>>> REPLACE\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped separator in content", async () => { + const originalContent = "before\n=======\nafter\n" + const diffContent = + "test.ts\n" + + "<<<<<<< SEARCH\n" + + "before\n" + + "\\=======\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped replace marker in content", async () => { + const originalContent = "before\n>>>>>>> REPLACE\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes multiple escaped markers in content", async () => { + const originalContent = "<<<<<<< SEARCH\n=======\n>>>>>>> REPLACE\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "\\<<<<<<< SEARCH\n" + + "\\=======\n" + + "\\>>>>>>> REPLACE\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes escaped replace marker in content", async () => { + const originalContent = "before\n>>>>>>> REPLACE\nafter\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("processes multiple escaped markers in content", async () => { + const originalContent = "<<<<<<< SEARCH\n=======\n>>>>>>> REPLACE\n" + const diffContent = + "<<<<<<< SEARCH\n" + + "\\<<<<<<< SEARCH\n" + + "\\=======\n" + + "\\>>>>>>> REPLACE\n" + + "=======\n" + + "unchanged\n" + + ">>>>>>> REPLACE" + const result = await strategy.applyDiff(originalContent, diffContent) + expect(result.success).toBe(true) + if (result.success) { + expect(result.content).toBe("unchanged\n") + } + }) + + it("allows escaped replace marker in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "before\n" + + "\\>>>>>>> REPLACE\n" + + "after\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(true) + }) + + it("allows multiple escaped markers in content", () => { + const diff = + "<<<<<<< SEARCH\n" + + "\\<<<<<<< SEARCH\n" + + "\\=======\n" + + "\\>>>>>>> REPLACE\n" + + "=======\n" + + "new content\n" + + ">>>>>>> REPLACE" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(true) + }) + + it("detects separator when expecting replace", () => { + const diff = "<<<<<<< SEARCH\n" + "content\n" + "=======\n" + "new content\n" + "=======" + const result = strategy["validateMarkerSequencing"](diff) + expect(result.success).toBe(false) + expect(result.error).toContain("'=======' found in your diff content") + }) }) it("should not strip content that starts with pipe but no line number", async () => { @@ -980,7 +1580,6 @@ function test() { :end_line:4 ------- ======= - // End of file >>>>>>> REPLACE` @@ -990,7 +1589,6 @@ function test() { expect(result.content).toBe(`function test() { return true; } - // End of file`) } }) diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index ad12448d046..bf80f090528 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -73,6 +73,7 @@ Diff format: \`\`\` + Example: Original file: @@ -128,6 +129,7 @@ def calculate_sum(items): >>>>>>> REPLACE \`\`\` + Usage: File path here @@ -139,22 +141,140 @@ Only use a single line of '=======' between search and replacement content, beca ` } + private unescapeMarkers(content: string): string { + return content + .replace(/^\\<<<<<<< SEARCH/gm, "<<<<<<< SEARCH") + .replace(/^\\=======/gm, "=======") + .replace(/^\\>>>>>>> REPLACE/gm, ">>>>>>> REPLACE") + .replace(/^\\-------/gm, "-------") + .replace(/^\\:end_line:/gm, ":end_line:") + .replace(/^\\:start_line:/gm, ":start_line:") + } + + private validateMarkerSequencing(diffContent: string): { success: boolean; error?: string } { + enum State { + START, + AFTER_SEARCH, + AFTER_SEPARATOR, + } + const state = { current: State.START, line: 0 } + + const SEARCH = "<<<<<<< SEARCH" + const SEP = "=======" + const REPLACE = ">>>>>>> REPLACE" + + const reportError = (found: string, expected: string) => ({ + success: false, + error: + `ERROR: Special marker '${found}' found in your diff content at line ${state.line}:\n` + + "\n" + + `When removing merge conflict markers like '${found}' from files, you MUST escape them\n` + + "in your SEARCH section by prepending a backslash (\\) at the beginning of the line:\n" + + "\n" + + "CORRECT FORMAT:\n\n" + + "<<<<<<< SEARCH\n" + + "content before\n" + + `\\${found} <-- Note the backslash here in this example\n` + + "content after\n" + + "=======\n" + + "replacement content\n" + + ">>>>>>> REPLACE\n" + + "\n" + + "Without escaping, the system confuses your content with diff syntax markers.\n" + + "You may use multiple diff blocks in a single diff request, but ANY of ONLY the following separators that occur within SEARCH or REPLACE content must be escaped, as follows:\n" + + `\\${SEARCH}\n` + + `\\${SEP}\n` + + `\\${REPLACE}\n`, + }) + + for (const line of diffContent.split("\n")) { + state.line++ + const marker = line.trim() + + switch (state.current) { + case State.START: + if (marker === SEP) return reportError(SEP, SEARCH) + if (marker === REPLACE) return reportError(REPLACE, SEARCH) + if (marker === SEARCH) state.current = State.AFTER_SEARCH + break + + case State.AFTER_SEARCH: + if (marker === SEARCH) return reportError(SEARCH, SEP) + if (marker === REPLACE) return reportError(REPLACE, SEP) + if (marker === SEP) state.current = State.AFTER_SEPARATOR + break + + case State.AFTER_SEPARATOR: + if (marker === SEARCH) return reportError(SEARCH, REPLACE) + if (marker === SEP) return reportError(SEP, REPLACE) + if (marker === REPLACE) state.current = State.START + break + } + } + + return state.current === State.START + ? { success: true } + : { + success: false, + error: `ERROR: Unexpected end of sequence: Expected '${state.current === State.AFTER_SEARCH ? SEP : REPLACE}' was not found.`, + } + } + async applyDiff( originalContent: string, diffContent: string, _paramStartLine?: number, _paramEndLine?: number, ): Promise { + const validseq = this.validateMarkerSequencing(diffContent) + if (!validseq.success) { + return { + success: false, + error: validseq.error!, + } + } + + /* + Regex parts: + + 1. (?:^|\n) +   Ensures the first marker starts at the beginning of the file or right after a newline. + + 2. (?>>>>>> REPLACE)(?=\n|$) +   Matches the final “>>>>>>> REPLACE” marker on its own line (and requires a following newline or the end of file). + */ + let matches = [ ...diffContent.matchAll( - /<<<<<<< SEARCH\n(:start_line:\s*(\d+)\n){0,1}(:end_line:\s*(\d+)\n){0,1}(-------\n){0,1}([\s\S]*?)\n?=======\n([\s\S]*?)\n?>>>>>>> REPLACE/g, + /(?:^|\n)(?>>>>>> REPLACE)(?=\n|$)/g, ), ] if (matches.length === 0) { return { success: false, - error: `Invalid diff format - missing required sections\n\nDebug Info:\n- Expected Format: <<<<<<< SEARCH\\n:start_line: start line\\n:end_line: end line\\n-------\\n[search content]\\n=======\\n[replace content]\\n>>>>>>> REPLACE\n- Tip: Make sure to include start_line/end_line/SEARCH/REPLACE sections with correct markers`, + error: `Invalid diff format - missing required sections\n\nDebug Info:\n- Expected Format: <<<<<<< SEARCH\\n:start_line: start line\\n:end_line: end line\\n-------\\n[search content]\\n=======\\n[replace content]\\n>>>>>>> REPLACE\n- Tip: Make sure to include start_line/end_line/SEARCH/=======/REPLACE sections with correct markers on new lines`, } } // Detect line ending from original content @@ -176,12 +296,29 @@ Only use a single line of '=======' between search and replacement content, beca startLine += startLine === 0 ? 0 : delta endLine += delta + // First unescape any escaped markers in the content + searchContent = this.unescapeMarkers(searchContent) + replaceContent = this.unescapeMarkers(replaceContent) + // Strip line numbers from search and replace content if every line starts with a line number if (everyLineHasLineNumbers(searchContent) && everyLineHasLineNumbers(replaceContent)) { searchContent = stripLineNumbers(searchContent) replaceContent = stripLineNumbers(replaceContent) } + // Validate that search and replace content are not identical + if (searchContent === replaceContent) { + diffResults.push({ + success: false, + error: + `Search and replace content are identical - no changes would be made\n\n` + + `Debug Info:\n` + + `- Search and replace must be different to make changes\n` + + `- Use read_file to verify the content you want to change`, + }) + continue + } + // Split content into lines, handling both \n and \r\n const searchLines = searchContent === "" ? [] : searchContent.split(/\r?\n/) const replaceLines = replaceContent === "" ? [] : replaceContent.split(/\r?\n/) diff --git a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap index e6f7db94447..31a75fff8a0 100644 --- a/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap +++ b/src/core/prompts/__tests__/__snapshots__/system.test.ts.snap @@ -35,11 +35,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -68,9 +70,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -412,11 +421,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -445,9 +456,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -878,11 +896,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -911,9 +931,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -1308,11 +1335,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -1341,9 +1370,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -1685,11 +1721,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -1718,9 +1756,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -2062,11 +2107,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -2095,9 +2142,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -2439,11 +2493,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -2472,9 +2528,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -2865,11 +2928,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -2898,9 +2963,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -3696,11 +3768,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -3729,9 +3803,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -4122,11 +4203,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -4155,9 +4238,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -4242,17 +4332,9 @@ Original file: Search/Replace content: \`\`\` -<<<<<<< SEARCH -def calculate_total(items): - total = 0 - for item in items: - total += item - return total -======= def calculate_total(items): """Calculate total with 10% markup""" return sum(item * 1.1 for item in items) ->>>>>>> REPLACE \`\`\` Usage: @@ -4557,11 +4639,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -4590,9 +4674,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -4976,11 +5067,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -5009,9 +5102,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -5515,11 +5615,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -5548,9 +5650,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -5968,11 +6077,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -6001,9 +6112,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: @@ -6319,11 +6437,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory /test/path) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -6352,9 +6472,16 @@ Examples: 46 68 - Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files. + ## search_files Description: Request to perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. Parameters: diff --git a/src/core/prompts/__tests__/custom-system-prompt.test.ts b/src/core/prompts/__tests__/custom-system-prompt.test.ts index 812caffbafd..977ab051a00 100644 --- a/src/core/prompts/__tests__/custom-system-prompt.test.ts +++ b/src/core/prompts/__tests__/custom-system-prompt.test.ts @@ -2,6 +2,7 @@ import { SYSTEM_PROMPT } from "../system" import { defaultModeSlug, modes } from "../../../shared/modes" import * as vscode from "vscode" import * as fs from "fs/promises" +import { toPosix } from "./utils" // Mock the fs/promises module jest.mock("fs/promises", () => ({ @@ -89,7 +90,7 @@ describe("File-Based Custom System Prompt", () => { const fileCustomSystemPrompt = "Custom system prompt from file" // When called with utf-8 encoding, return a string mockedFs.readFile.mockImplementation((filePath, options) => { - if (filePath.toString().includes(`.roo/system-prompt-${defaultModeSlug}`) && options === "utf-8") { + if (toPosix(filePath).includes(`.roo/system-prompt-${defaultModeSlug}`) && options === "utf-8") { return Promise.resolve(fileCustomSystemPrompt) } return Promise.reject({ code: "ENOENT" }) @@ -124,7 +125,7 @@ describe("File-Based Custom System Prompt", () => { // Mock the readFile to return content from a file const fileCustomSystemPrompt = "Custom system prompt from file" mockedFs.readFile.mockImplementation((filePath, options) => { - if (filePath.toString().includes(`.roo/system-prompt-${defaultModeSlug}`) && options === "utf-8") { + if (toPosix(filePath).includes(`.roo/system-prompt-${defaultModeSlug}`) && options === "utf-8") { return Promise.resolve(fileCustomSystemPrompt) } return Promise.reject({ code: "ENOENT" }) diff --git a/src/core/prompts/__tests__/responses-rooignore.test.ts b/src/core/prompts/__tests__/responses-rooignore.test.ts index 37b3050dd05..46f1bec438a 100644 --- a/src/core/prompts/__tests__/responses-rooignore.test.ts +++ b/src/core/prompts/__tests__/responses-rooignore.test.ts @@ -2,9 +2,9 @@ import { formatResponse } from "../responses" import { RooIgnoreController, LOCK_TEXT_SYMBOL } from "../../ignore/RooIgnoreController" -import * as path from "path" import { fileExistsAtPath } from "../../../utils/fs" import * as fs from "fs/promises" +import { toPosix } from "./utils" // Mock dependencies jest.mock("../../../utils/fs") @@ -82,7 +82,9 @@ describe("RooIgnore Response Formatting", () => { controller.validateAccess = jest.fn().mockImplementation((filePath: string) => { // Only allow files not matching these patterns return ( - !filePath.includes("node_modules") && !filePath.includes(".git") && !filePath.includes("secrets/") + !filePath.includes("node_modules") && + !filePath.includes(".git") && + !toPosix(filePath).includes("secrets/") ) }) @@ -124,7 +126,9 @@ describe("RooIgnore Response Formatting", () => { controller.validateAccess = jest.fn().mockImplementation((filePath: string) => { // Only allow files not matching these patterns return ( - !filePath.includes("node_modules") && !filePath.includes(".git") && !filePath.includes("secrets/") + !filePath.includes("node_modules") && + !filePath.includes(".git") && + !toPosix(filePath).includes("secrets/") ) }) diff --git a/src/core/prompts/__tests__/utils.ts b/src/core/prompts/__tests__/utils.ts new file mode 100644 index 00000000000..f2ac4fec1e7 --- /dev/null +++ b/src/core/prompts/__tests__/utils.ts @@ -0,0 +1,7 @@ +import * as fs from "fs/promises" +import { PathLike } from "fs" + +// Make a path take a unix-like form. Useful for making path comparisons. +export function toPosix(filePath: PathLike | fs.FileHandle) { + return filePath.toString().toPosix() +} diff --git a/src/core/prompts/tools/read-file.ts b/src/core/prompts/tools/read-file.ts index 5586b90dc4a..49322973192 100644 --- a/src/core/prompts/tools/read-file.ts +++ b/src/core/prompts/tools/read-file.ts @@ -7,11 +7,13 @@ Parameters: - path: (required) The path of the file to read (relative to the current working directory ${args.cwd}) - start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file. - end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file. +- auto_truncate: (optional) Whether to automatically truncate large files when start_line and end_line are not specified. If true and the file exceeds a certain line threshold, it will: a) return only a subset of lines to save tokens, b) include information about the total line count, and c) provide a summary of method definitions with their line ranges. You should set this to true unless you've been explicitly asked to read an entire large file at once, as this prevents context bloat that can lead to truncated responses. For backwards compatibility, it defaults to false when omitted. Usage: File path here Starting line number (optional) Ending line number (optional) +true or false (optional) Examples: @@ -40,6 +42,13 @@ Examples: 46 68 +Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues. -Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues.` +5. Reading a large file with automatic truncation: + +src/large-module.ts +true + + +This will return a truncated version of the file with information about total line count and method definitions, helping to prevent context size issues with very large files.` } diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index a53d73fb4d3..5a53eab36c5 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -10,7 +10,18 @@ import * as vscode from "vscode" import { changeLanguage, t } from "../../i18n" import { setPanel } from "../../activate/registerCommands" -import { ApiConfiguration, ApiProvider, ModelInfo, API_CONFIG_KEYS } from "../../shared/api" +import { + ApiConfiguration, + ApiProvider, + ModelInfo, + API_CONFIG_KEYS, + requestyDefaultModelId, + requestyDefaultModelInfo, + openRouterDefaultModelId, + openRouterDefaultModelInfo, + glamaDefaultModelId, + glamaDefaultModelInfo, +} from "../../shared/api" import { findLast } from "../../shared/array" import { supportPrompt } from "../../shared/support-prompt" import { GlobalFileNames } from "../../shared/globalFileNames" @@ -593,6 +604,8 @@ export class ClineProvider extends EventEmitter implements "codicon.css", ]) + const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"]) + const file = "src/index.tsx" const scriptUri = `http://${localServerUrl}/${file}` @@ -624,6 +637,9 @@ export class ClineProvider extends EventEmitter implements + Roo Code @@ -672,6 +688,8 @@ export class ClineProvider extends EventEmitter implements "codicon.css", ]) + const imagesUri = getUri(webview, this.contextProxy.extensionUri, ["assets", "images"]) + // const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "main.js")) // const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, "assets", "reset.css")) @@ -704,6 +722,9 @@ export class ClineProvider extends EventEmitter implements + Roo Code @@ -1811,23 +1832,7 @@ export class ClineProvider extends EventEmitter implements break case "upsertApiConfiguration": if (message.text && message.apiConfiguration) { - try { - await this.configManager.saveConfig(message.text, message.apiConfiguration) - const listApiConfig = await this.configManager.listConfig() - - await Promise.all([ - this.updateGlobalState("listApiConfigMeta", listApiConfig), - this.updateApiConfiguration(message.apiConfiguration), - this.updateGlobalState("currentApiConfigName", message.text), - ]) - - await this.postStateToWebview() - } catch (error) { - this.outputChannel.appendLine( - `Error create new api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, - ) - vscode.window.showErrorMessage(t("common:errors.create_api_config")) - } + await this.upsertApiConfiguration(message.text, message.apiConfiguration) } break case "renameApiConfiguration": @@ -2059,6 +2064,7 @@ export class ClineProvider extends EventEmitter implements apiConfiguration.apiModelId || apiConfiguration.openRouterModelId || "", fuzzyMatchThreshold, Experiments.isEnabled(experiments, EXPERIMENT_IDS.DIFF_STRATEGY), + Experiments.isEnabled(experiments, EXPERIMENT_IDS.MULTI_SEARCH_AND_REPLACE), ) const cwd = this.cwd @@ -2263,9 +2269,10 @@ export class ClineProvider extends EventEmitter implements // OpenRouter async handleOpenRouterCallback(code: string) { + let { apiConfiguration, currentApiConfigName } = await this.getState() + let apiKey: string try { - const { apiConfiguration } = await this.getState() const baseUrl = apiConfiguration.openRouterBaseUrl || "https://openrouter.ai/api/v1" // Extract the base domain for the auth endpoint const baseUrlDomain = baseUrl.match(/^(https?:\/\/[^\/]+)/)?.[1] || "https://openrouter.ai" @@ -2282,17 +2289,15 @@ export class ClineProvider extends EventEmitter implements throw error } - const openrouter: ApiProvider = "openrouter" - await this.contextProxy.setValues({ - apiProvider: openrouter, + const newConfiguration: ApiConfiguration = { + ...apiConfiguration, + apiProvider: "openrouter", openRouterApiKey: apiKey, - }) - - await this.postStateToWebview() - if (this.getCurrentCline()) { - this.getCurrentCline()!.api = buildApiHandler({ apiProvider: openrouter, openRouterApiKey: apiKey }) + openRouterModelId: apiConfiguration?.openRouterModelId || openRouterDefaultModelId, + openRouterModelInfo: apiConfiguration?.openRouterModelInfo || openRouterDefaultModelInfo, } - // await this.postMessageToWebview({ type: "action", action: "settingsButtonClicked" }) // bad ux if user is on welcome + + await this.upsertApiConfiguration(currentApiConfigName, newConfiguration) } // Glama @@ -2313,19 +2318,55 @@ export class ClineProvider extends EventEmitter implements throw error } - const glama: ApiProvider = "glama" - await this.contextProxy.setValues({ - apiProvider: glama, + const { apiConfiguration, currentApiConfigName } = await this.getState() + + const newConfiguration: ApiConfiguration = { + ...apiConfiguration, + apiProvider: "glama", glamaApiKey: apiKey, - }) - await this.postStateToWebview() - if (this.getCurrentCline()) { - this.getCurrentCline()!.api = buildApiHandler({ - apiProvider: glama, - glamaApiKey: apiKey, - }) + glamaModelId: apiConfiguration?.glamaModelId || glamaDefaultModelId, + glamaModelInfo: apiConfiguration?.glamaModelInfo || glamaDefaultModelInfo, + } + + await this.upsertApiConfiguration(currentApiConfigName, newConfiguration) + } + + // Requesty + + async handleRequestyCallback(code: string) { + let { apiConfiguration, currentApiConfigName } = await this.getState() + + const newConfiguration: ApiConfiguration = { + ...apiConfiguration, + apiProvider: "requesty", + requestyApiKey: code, + requestyModelId: apiConfiguration?.requestyModelId || requestyDefaultModelId, + requestyModelInfo: apiConfiguration?.requestyModelInfo || requestyDefaultModelInfo, + } + + await this.upsertApiConfiguration(currentApiConfigName, newConfiguration) + } + + // Save configuration + + async upsertApiConfiguration(configName: string, apiConfiguration: ApiConfiguration) { + try { + await this.configManager.saveConfig(configName, apiConfiguration) + const listApiConfig = await this.configManager.listConfig() + + await Promise.all([ + this.updateGlobalState("listApiConfigMeta", listApiConfig), + this.updateApiConfiguration(apiConfiguration), + this.updateGlobalState("currentApiConfigName", configName), + ]) + + await this.postStateToWebview() + } catch (error) { + this.outputChannel.appendLine( + `Error create new api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, + ) + vscode.window.showErrorMessage(t("common:errors.create_api_config")) } - // await this.postMessageToWebview({ type: "action", action: "settingsButtonClicked" }) // bad ux if user is on welcome } // Task history @@ -2639,14 +2680,7 @@ export class ClineProvider extends EventEmitter implements if (stateValues.apiProvider) { apiProvider = stateValues.apiProvider } else { - // Either new user or legacy user that doesn't have the apiProvider stored in state - // (If they're using OpenRouter or Bedrock, then apiProvider state will exist) - if (secretValues.apiKey) { - apiProvider = "anthropic" - } else { - // New users should default to openrouter - apiProvider = "openrouter" - } + apiProvider = "anthropic" } // Build the apiConfiguration object combining state values and secrets diff --git a/src/shared/api.ts b/src/shared/api.ts index 84cac5d6313..4b87e43e914 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -754,15 +754,6 @@ export const openAiModelInfoSaneDefaults: ModelInfo = { outputPrice: 0, } -export const requestyModelInfoSaneDefaults: ModelInfo = { - maxTokens: -1, - contextWindow: 128_000, - supportsImages: true, - supportsPromptCache: false, - inputPrice: 0, - outputPrice: 0, -} - // Gemini // https://ai.google.dev/gemini-api/docs/models/gemini export type GeminiModelId = keyof typeof geminiModels diff --git a/src/shared/pearaiApi.ts b/src/shared/pearaiApi.ts index 6f9ef07eaa8..2ff45a276df 100644 --- a/src/shared/pearaiApi.ts +++ b/src/shared/pearaiApi.ts @@ -1,8 +1,8 @@ // CHANGE AS NEEDED FOR DEVELOPMENT // PROD: -// export const PEARAI_URL = "https://server.trypear.ai/pearai-server-api2/integrations/cline" +export const PEARAI_URL = "https://server.trypear.ai/pearai-server-api2/integrations/cline" // DEV: -export const PEARAI_URL = "http://localhost:8000/integrations/cline" +// export const PEARAI_URL = "http://localhost:8000/integrations/cline" import { anthropicModels, diff --git a/webview-ui/package-lock.json b/webview-ui/package-lock.json index 7d2a6b01f09..b42b7df0e07 100644 --- a/webview-ui/package-lock.json +++ b/webview-ui/package-lock.json @@ -33,6 +33,7 @@ "fzf": "^0.5.2", "i18next": "^24.2.2", "i18next-http-backend": "^3.0.2", + "knuth-shuffle-seeded": "^1.0.6", "lucide-react": "^0.475.0", "mermaid": "^11.4.1", "posthog-js": "^1.227.2", @@ -15201,6 +15202,14 @@ "node": ">=6" } }, + "node_modules/knuth-shuffle-seeded": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", + "integrity": "sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==", + "dependencies": { + "seed-random": "~2.2.0" + } + }, "node_modules/kolorist": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", @@ -19970,6 +19979,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/seed-random": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", + "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/webview-ui/package.json b/webview-ui/package.json index c39f3d26796..834c0dfe466 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -43,6 +43,7 @@ "fzf": "^0.5.2", "i18next": "^24.2.2", "i18next-http-backend": "^3.0.2", + "knuth-shuffle-seeded": "^1.0.6", "lucide-react": "^0.475.0", "mermaid": "^11.4.1", "posthog-js": "^1.227.2", diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 6be47ef09c2..044815a6153 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -253,7 +253,7 @@ export const ChatRowContent = ({ }, [message.ask, message.say, message.text]) const followUpData = useMemo(() => { - if (message.type === "ask" && message.ask === "followup" && message.partial === false) { + if (message.type === "ask" && message.ask === "followup" && !message.partial) { return JSON.parse(message.text || "{}") } return null diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx index 76aa32c7fb3..24dc42ca7de 100644 --- a/webview-ui/src/components/chat/FollowUpSuggest.tsx +++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx @@ -28,7 +28,7 @@ const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: Follow {suggestions.map((suggestion) => (
{!apiConfiguration?.openRouterApiKey && ( - + {t("settings:providers.getOpenRouterApiKey")} )} @@ -420,7 +424,10 @@ const ApiOptions = ({ {t("settings:providers.apiKeyStorageNotice")} {!apiConfiguration?.glamaApiKey && ( - + {t("settings:providers.getGlamaApiKey")} )} @@ -440,6 +447,14 @@ const ApiOptions = ({
{t("settings:providers.apiKeyStorageNotice")}
+ {!apiConfiguration?.requestyApiKey && ( + + {t("settings:providers.getRequestyApiKey")} + + )} )} @@ -1576,15 +1591,6 @@ const ApiOptions = ({ ) } -export function getGlamaAuthUrl(uriScheme?: string) { - const callbackUrl = `${uriScheme || "vscode"}://rooveterinaryinc.roo-cline/glama` - return `https://glama.ai/oauth/authorize?callback_url=${encodeURIComponent(callbackUrl)}` -} - -export function getOpenRouterAuthUrl(uriScheme?: string) { - return `https://openrouter.ai/auth?callback_url=${uriScheme || "vscode"}://rooveterinaryinc.roo-cline/openrouter` -} - export function normalizeApiConfiguration( apiConfiguration?: ApiConfiguration, pearAiModelsQuery?: Record, diff --git a/webview-ui/src/components/settings/ContextManagementSettings.tsx b/webview-ui/src/components/settings/ContextManagementSettings.tsx index 947ba7382c4..0e8a580be6c 100644 --- a/webview-ui/src/components/settings/ContextManagementSettings.tsx +++ b/webview-ui/src/components/settings/ContextManagementSettings.tsx @@ -96,18 +96,24 @@ export const ContextManagementSettings = ({
{t("settings:contextManagement.maxReadFile.label")}
- setCachedStateField("maxReadFileLine", value)} - data-testid="max-read-file-line-slider" + onChange={(e) => { + const newValue = parseInt(e.target.value, 10) + if (!isNaN(newValue) && newValue >= 0) { + setCachedStateField("maxReadFileLine", newValue) + } + }} + onClick={(e) => e.currentTarget.select()} + data-testid="max-read-file-line-input" /> - {maxReadFileLine ?? 450} + {t("settings:contextManagement.maxReadFile.lines")}
-
+
{t("settings:contextManagement.maxReadFile.description")}
diff --git a/webview-ui/src/components/ui/dropdown-menu.tsx b/webview-ui/src/components/ui/dropdown-menu.tsx index bce7508dd9b..3a3812bf34a 100644 --- a/webview-ui/src/components/ui/dropdown-menu.tsx +++ b/webview-ui/src/components/ui/dropdown-menu.tsx @@ -27,7 +27,7 @@ const DropdownMenuContent = React.forwardRef< "z-50 min-w-[8rem] overflow-hidden rounded-xs p-1 shadow-xs", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "border border-vscode-focusBorder", - "bg-vscode-dropdown-background", + "bg-vscode-dropdown-background bg-opacity-100", "text-vscode-dropdown-foreground", className, )} diff --git a/webview-ui/src/components/welcome/WelcomeView.tsx b/webview-ui/src/components/welcome/WelcomeView.tsx index 937c59a5f10..3b81f51b618 100644 --- a/webview-ui/src/components/welcome/WelcomeView.tsx +++ b/webview-ui/src/components/welcome/WelcomeView.tsx @@ -1,18 +1,17 @@ import { useCallback, useState } from "react" import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" - import { useExtensionState } from "../../context/ExtensionStateContext" import { validateApiConfiguration } from "../../utils/validate" import { vscode } from "../../utils/vscode" import ApiOptions from "../settings/ApiOptions" import { Tab, TabContent } from "../common/Tab" -import { Alert } from "../common/Alert" import { useAppTranslation } from "../../i18n/TranslationContext" +import { getRequestyAuthUrl, getOpenRouterAuthUrl } from "../../oauth/urls" +import knuthShuffle from "knuth-shuffle-seeded" const WelcomeView = () => { - const { apiConfiguration, currentApiConfigName, setApiConfiguration, uriScheme } = useExtensionState() + const { apiConfiguration, currentApiConfigName, setApiConfiguration, uriScheme, machineId } = useExtensionState() const { t } = useAppTranslation() - const [errorMessage, setErrorMessage] = useState(undefined) const handleSubmit = useCallback(() => { @@ -27,24 +26,92 @@ const WelcomeView = () => { vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration }) }, [apiConfiguration, currentApiConfigName]) + // Using a lazy initializer so it reads once at mount + const [imagesBaseUri] = useState(() => { + const w = window as any + return w.IMAGES_BASE_URI || "" + }) + return (

{t("welcome:greeting")}

{t("welcome:introduction")}
- {t("welcome:notice")} - setApiConfiguration({ [field]: value })} - errorMessage={errorMessage} - setErrorMessage={setErrorMessage} - /> +
{t("welcome:chooseProvider")}
+ +
+

{t("welcome:startRouter")}

+ +
+ {/* Define the providers */} + {(() => { + // Provider card configuration + const providers = [ + { + slug: "requesty", + name: "Requesty", + description: t("welcome:routers.requesty.description"), + incentive: t("welcome:routers.requesty.incentive"), + authUrl: getRequestyAuthUrl(uriScheme), + }, + { + slug: "openrouter", + name: "OpenRouter", + description: t("welcome:routers.openrouter.description"), + authUrl: getOpenRouterAuthUrl(uriScheme), + }, + ] + + // Shuffle providers based on machine ID (will be consistent for the same machine) + const orderedProviders = [...providers] + knuthShuffle(orderedProviders, (machineId as any) || Date.now()) + + // Render the provider cards + return orderedProviders.map((provider, index) => ( + +
+ {provider.name} +
+
+
{provider.name}
+
+ {provider.description} +
+ {provider.incentive && ( +
{provider.incentive}
+ )} +
+
+ )) + })()} +
+ +
{t("welcome:or")}
+

{t("welcome:startCustom")}

+ setApiConfiguration({ [field]: value })} + errorMessage={errorMessage} + setErrorMessage={setErrorMessage} + /> +
- {t("welcome:start")} + + {t("welcome:start")} + {errorMessage &&
{errorMessage}
}
diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 571da595eb3..b5d5ff2708b 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -267,8 +267,9 @@ "description": "Quan està habilitat, els fitxers que coincideixen amb els patrons a .rooignore es mostraran en llistes amb un símbol de cadenat. Quan està deshabilitat, aquests fitxers s'ocultaran completament de les llistes de fitxers i cerques." }, "maxReadFile": { - "label": "Nombre màxim de línies per llegir d'un fitxer", - "description": "Nombre màxim de línies per llegir d'un fitxer a la vegada. Valors més baixos redueixen l'ús de context/recursos però poden requerir més lectures per a fitxers grans." + "label": "Llindar d'auto-truncament de lectura de fitxers", + "description": "El nombre predeterminat de línies per llegir d'un fitxer en un lot. Valors més baixos redueixen l'ús de context/recursos però poden requerir més lectures per a fitxers grans.", + "lines": "línies" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ca/welcome.json b/webview-ui/src/i18n/locales/ca/welcome.json index bd2ebea05ac..89b1611881c 100644 --- a/webview-ui/src/i18n/locales/ca/welcome.json +++ b/webview-ui/src/i18n/locales/ca/welcome.json @@ -3,6 +3,18 @@ "introduction": "Puc fer tot tipus de tasques gràcies als últims avenços en capacitats de codificació agent i accés a eines que em permeten crear i editar fitxers, explorar projectes complexos, utilitzar el navegador i executar ordres de terminal (amb el teu permís, és clar). Fins i tot puc utilitzar MCP per crear noves eines i ampliar les meves pròpies capacitats.", "notice": "Per començar, aquesta extensió necessita un proveïdor d'API.", "start": "Som-hi!", + "chooseProvider": "Tria un proveïdor d'API per començar:", + "routers": { + "requesty": { + "description": "El teu router LLM optimitzat", + "incentive": "$1 de crèdit gratuït" + }, + "openrouter": { + "description": "Una interfície unificada per a LLMs" + } + }, + "startRouter": "Configuració ràpida a través d'un router", + "startCustom": "Utilitza la teva pròpia clau API", "telemetry": { "title": "Ajuda a millorar Roo Code", "anonymousTelemetry": "Envia dades d'ús i errors anònims per ajudar-nos a corregir errors i millorar l'extensió. No s'envia mai cap codi, text o informació personal.", @@ -10,5 +22,6 @@ "settings": "configuració", "allow": "Permetre", "deny": "Denegar" - } + }, + "or": "o" } diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 277ab839823..05d195a093b 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -267,8 +267,9 @@ "description": "Wenn aktiviert, werden Dateien, die mit Mustern in .rooignore übereinstimmen, in Listen mit einem Schlosssymbol angezeigt. Wenn deaktiviert, werden diese Dateien vollständig aus Dateilisten und Suchen ausgeblendet." }, "maxReadFile": { - "label": "Maximale Anzahl an Zeilen, die aus einer Datei gelesen werden", - "description": "Maximale Anzahl an Zeilen, die auf einmal aus einer Datei gelesen werden. Niedrigere Werte reduzieren den Kontext-/Ressourcenverbrauch, können aber mehr Lesevorgänge für große Dateien erfordern." + "label": "Schwellenwert für automatische Dateilesekürzung", + "description": "Die Standardanzahl an Zeilen, die in einem Durchgang aus einer Datei gelesen werden. Niedrigere Werte reduzieren den Kontext-/Ressourcenverbrauch, können aber mehr Lesevorgänge für große Dateien erfordern.", + "lines": "Zeilen" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/de/welcome.json b/webview-ui/src/i18n/locales/de/welcome.json index aded3848861..19fcb0eac34 100644 --- a/webview-ui/src/i18n/locales/de/welcome.json +++ b/webview-ui/src/i18n/locales/de/welcome.json @@ -3,6 +3,18 @@ "introduction": "Ich kann alle Arten von Aufgaben erledigen, dank der neuesten Durchbrüche in agentenbasierten Codierungsfähigkeiten und dem Zugang zu Tools, die es mir ermöglichen, Dateien zu erstellen und zu bearbeiten, komplexe Projekte zu erkunden, den Browser zu verwenden und Terminalbefehle auszuführen (natürlich mit deiner Erlaubnis). Ich kann sogar MCP verwenden, um neue Tools zu erstellen und meine eigenen Fähigkeiten zu erweitern.", "notice": "Um loszulegen, benötigt diese Erweiterung einen API-Anbieter.", "start": "Los geht's!", + "chooseProvider": "Wähle einen API-Anbieter, um zu beginnen:", + "routers": { + "requesty": { + "description": "Dein optimierter LLM-Router", + "incentive": "$1 Guthaben gratis" + }, + "openrouter": { + "description": "Eine einheitliche Schnittstelle für LLMs" + } + }, + "startRouter": "Express-Einrichtung über einen Router", + "startCustom": "Eigenen API-Schlüssel verwenden", "telemetry": { "title": "Hilf, Roo Code zu verbessern", "anonymousTelemetry": "Sende anonyme Fehler- und Nutzungsdaten, um uns bei der Fehlerbehebung und Verbesserung der Erweiterung zu helfen. Es werden niemals Code, Texte oder persönliche Informationen gesendet.", @@ -10,5 +22,6 @@ "settings": "Einstellungen", "allow": "Erlauben", "deny": "Ablehnen" - } + }, + "or": "oder" } diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 29b163512eb..7fd923b4ee1 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -267,8 +267,9 @@ "description": "When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol. When disabled, these files will be completely hidden from file lists and searches." }, "maxReadFile": { - "label": "Maximum lines to read from a file", - "description": "Maximum number of lines to read from a file at once. Lower values reduce context/resource usage but may require more reads for large files." + "label": "File read auto-truncate threshold", + "description": "The default number of lines to read from a file in one batch. Lower values reduce context/resource usage but may require more reads for large files.", + "lines": "lines" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/en/welcome.json b/webview-ui/src/i18n/locales/en/welcome.json index f02021b7186..811d760c0f1 100644 --- a/webview-ui/src/i18n/locales/en/welcome.json +++ b/webview-ui/src/i18n/locales/en/welcome.json @@ -3,6 +3,18 @@ "introduction": "I can do all kinds of tasks thanks to the latest breakthroughs in agentic coding capabilities and access to tools that let me create & edit files, explore complex projects, use the browser, and execute terminal commands (with your permission, of course). I can even use MCP to create new tools and extend my own capabilities.", "notice": "To get started, this extension needs an API provider.", "start": "Let's go!", + "chooseProvider": "Choose an API provider to get started:", + "routers": { + "requesty": { + "description": "Your optimized LLM router", + "incentive": "$1 free credit" + }, + "openrouter": { + "description": "A unified interface for LLMs" + } + }, + "startRouter": "Express Setup Through a Router", + "startCustom": "Bring Your Own API Key", "telemetry": { "title": "Help Improve Roo Code", "anonymousTelemetry": "Send anonymous error and usage data to help us fix bugs and improve the extension. No code, prompts, or personal information is ever sent.", @@ -10,5 +22,6 @@ "settings": "settings", "allow": "Allow", "deny": "Deny" - } + }, + "or": "or" } diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index ccc255e8a1d..9c5ae82da97 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -267,8 +267,9 @@ "description": "Cuando está habilitado, los archivos que coinciden con los patrones en .rooignore se mostrarán en listas con un símbolo de candado. Cuando está deshabilitado, estos archivos se ocultarán completamente de las listas de archivos y búsquedas." }, "maxReadFile": { - "label": "Número máximo de líneas para leer de un archivo", - "description": "Número máximo de líneas para leer de un archivo a la vez. Valores más bajos reducen el uso de contexto/recursos pero pueden requerir más lecturas para archivos grandes." + "label": "Umbral de auto-truncado de lectura de archivos", + "description": "El número predeterminado de líneas para leer de un archivo en un lote. Valores más bajos reducen el uso de contexto/recursos pero pueden requerir más lecturas para archivos grandes.", + "lines": "líneas" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/es/welcome.json b/webview-ui/src/i18n/locales/es/welcome.json index 9482732d492..b2289200a1c 100644 --- a/webview-ui/src/i18n/locales/es/welcome.json +++ b/webview-ui/src/i18n/locales/es/welcome.json @@ -3,6 +3,18 @@ "introduction": "Puedo realizar todo tipo de tareas gracias a los últimos avances en capacidades de codificación agentica y acceso a herramientas que me permiten crear y editar archivos, explorar proyectos complejos, usar el navegador y ejecutar comandos de terminal (con tu permiso, por supuesto). Incluso puedo usar MCP para crear nuevas herramientas y ampliar mis propias capacidades.", "notice": "Para comenzar, esta extensión necesita un proveedor de API.", "start": "¡Vamos!", + "chooseProvider": "Elige un proveedor de API para comenzar:", + "routers": { + "requesty": { + "description": "Tu router LLM optimizado", + "incentive": "$1 de crédito gratis" + }, + "openrouter": { + "description": "Una interfaz unificada para LLMs" + } + }, + "startRouter": "Configuración rápida a través de un router", + "startCustom": "Usa tu propia clave API", "telemetry": { "title": "Ayuda a mejorar Roo Code", "anonymousTelemetry": "Envía datos de uso y errores anónimos para ayudarnos a corregir errores y mejorar la extensión. Nunca se envía código, texto o información personal.", @@ -10,5 +22,6 @@ "settings": "configuración", "allow": "Permitir", "deny": "Denegar" - } + }, + "or": "o" } diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 63a3c4be71e..1553e11876c 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -267,8 +267,9 @@ "description": "Lorsque cette option est activée, les fichiers correspondant aux modèles dans .rooignore seront affichés dans les listes avec un symbole de cadenas. Lorsqu'elle est désactivée, ces fichiers seront complètement masqués des listes de fichiers et des recherches." }, "maxReadFile": { - "label": "Nombre maximum de lignes à lire depuis un fichier", - "description": "Nombre maximum de lignes à lire depuis un fichier à la fois. Des valeurs plus basses réduisent l'utilisation de contexte/ressources mais peuvent nécessiter plus de lectures pour les fichiers volumineux." + "label": "Seuil d'auto-troncature de lecture de fichier", + "description": "Le nombre par défaut de lignes à lire depuis un fichier en un lot. Des valeurs plus basses réduisent l'utilisation de contexte/ressources mais peuvent nécessiter plus de lectures pour les fichiers volumineux.", + "lines": "lignes" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/fr/welcome.json b/webview-ui/src/i18n/locales/fr/welcome.json index 7e34e61a0a1..ca2038a4f5a 100644 --- a/webview-ui/src/i18n/locales/fr/welcome.json +++ b/webview-ui/src/i18n/locales/fr/welcome.json @@ -1,14 +1,27 @@ { "greeting": "Salut, je suis Roo !", - "introduction": "Je peux effectuer toutes sortes de tâches grâce aux dernières avancées en matière de capacités de codage agentique et à l'accès à des outils qui me permettent de créer et de modifier des fichiers, d'explorer des projets complexes, d'utiliser le navigateur et d'exécuter des commandes terminal (avec votre permission, bien sûr). Je peux même utiliser MCP pour créer de nouveaux outils et étendre mes propres capacités.", + "introduction": "Je peux effectuer toutes sortes de tâches grâce aux dernières avancées en matière de capacités de codage agentique et à l'accès à des outils qui me permettent de créer et de modifier des fichiers, d'explorer des projets complexes, d'utiliser le navigateur et d'exécuter des commandes terminal (avec ta permission, bien sûr). Je peux même utiliser MCP pour créer de nouveaux outils et étendre mes propres capacités.", "notice": "Pour commencer, cette extension a besoin d'un fournisseur d'API.", "start": "C'est parti !", + "chooseProvider": "Choisis un fournisseur d'API pour commencer :", + "routers": { + "requesty": { + "description": "Ton routeur LLM optimisé", + "incentive": "1$ de crédit gratuit" + }, + "openrouter": { + "description": "Une interface unifiée pour les LLMs" + } + }, + "startRouter": "Configuration rapide via un routeur", + "startCustom": "Utiliser ta propre clé API", "telemetry": { - "title": "Aidez à améliorer Roo Code", - "anonymousTelemetry": "Envoyez des données d'utilisation et d'erreurs anonymes pour nous aider à corriger les bugs et améliorer l'extension. Aucun code, texte ou information personnelle n'est jamais envoyé.", - "changeSettings": "Vous pouvez toujours modifier cela en bas des paramètres", + "title": "Aide à améliorer Roo Code", + "anonymousTelemetry": "Envoie des données d'utilisation et d'erreurs anonymes pour nous aider à corriger les bugs et améliorer l'extension. Aucun code, texte ou information personnelle n'est jamais envoyé.", + "changeSettings": "Tu peux toujours modifier cela en bas des paramètres", "settings": "paramètres", "allow": "Autoriser", "deny": "Refuser" - } + }, + "or": "ou" } diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index ba0461071f4..26054ea70df 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -267,8 +267,9 @@ "description": "जब सक्षम होता है, .rooignore में पैटर्न से मेल खाने वाली फाइलें लॉक प्रतीक के साथ सूचियों में दिखाई जाएंगी। जब अक्षम होता है, ये फाइलें फाइल सूचियों और खोजों से पूरी तरह छिपा दी जाएंगी।" }, "maxReadFile": { - "label": "फ़ाइल से पढ़ने के लिए अधिकतम लाइनें", - "description": "फ़ाइल से एक बार में पढ़ने के लिए अधिकतम लाइनों की संख्या। कम मान संदर्भ/संसाधन उपयोग को कम करते हैं लेकिन बड़ी फाइलों के लिए अधिक पठन की आवश्यकता हो सकती है।" + "label": "फ़ाइल पढ़ने का स्वचालित काटने की सीमा", + "description": "एक बैच में फ़ाइल से पढ़ने के लिए डिफ़ॉल्ट लाइनों की संख्या। कम मान संदर्भ/संसाधन उपयोग को कम करते हैं लेकिन बड़ी फाइलों के लिए अधिक पठन की आवश्यकता हो सकती है।", + "lines": "पंक्तियाँ" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/hi/welcome.json b/webview-ui/src/i18n/locales/hi/welcome.json index ef85bdc8bfc..6ec08c646b7 100644 --- a/webview-ui/src/i18n/locales/hi/welcome.json +++ b/webview-ui/src/i18n/locales/hi/welcome.json @@ -3,6 +3,18 @@ "introduction": "मैं सभी प्रकार के कार्य कर सकता हूँ, एजेंटिक कोडिंग क्षमताओं में नवीनतम सफलताओं और उन टूल्स तक पहुंच के लिए धन्यवाद जो मुझे फाइलें बनाने और संपादित करने, जटिल परियोजनाओं का पता लगाने, ब्राउज़र का उपयोग करने और टर्मिनल कमांड निष्पादित करने की अनुमति देते हैं (आपकी अनुमति से, बिल्कुल)। मैं MCP का उपयोग करके नए टूल बना सकता हूँ और अपनी क्षमताओं का विस्तार कर सकता हूँ।", "notice": "शुरू करने के लिए, इस एक्सटेंशन को एक API प्रदाता की आवश्यकता है।", "start": "चलो शुरू करें!", + "chooseProvider": "शुरू करने के लिए एक API प्रदाता चुनें:", + "routers": { + "requesty": { + "description": "आपका अनुकूलित LLM राउटर", + "incentive": "$1 मुफ्त क्रेडिट" + }, + "openrouter": { + "description": "LLMs के लिए एक एकीकृत इंटरफेस" + } + }, + "startRouter": "राउटर के माध्यम से तेज़ सेटअप", + "startCustom": "अपनी खुद की API कुंजी का उपयोग करें", "telemetry": { "title": "Roo Code को बेहतर बनाने में मदद करें", "anonymousTelemetry": "बग ठीक करने और एक्सटेंशन को बेहतर बनाने में हमारी मदद करने के लिए गुमनाम त्रुटि और उपयोग डेटा भेजें। कोड, संकेत या व्यक्तिगत जानकारी कभी नहीं भेजी जाती है।", @@ -10,5 +22,6 @@ "settings": "सेटिंग्स", "allow": "अनुमति दें", "deny": "अस्वीकार करें" - } + }, + "or": "या" } diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 4d5ea142a22..1e62f7bac81 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -267,8 +267,9 @@ "description": "Quando abilitato, i file che corrispondono ai pattern in .rooignore verranno mostrati negli elenchi con un simbolo di blocco. Quando disabilitato, questi file saranno completamente nascosti dagli elenchi di file e dalle ricerche." }, "maxReadFile": { - "label": "Numero massimo di righe da leggere da un file", - "description": "Numero massimo di righe da leggere da un file alla volta. Valori più bassi riducono l'utilizzo di contesto/risorse ma potrebbero richiedere più letture per file di grandi dimensioni." + "label": "Soglia di auto-troncamento lettura file", + "description": "Il numero predefinito di righe da leggere da un file in un singolo batch. Valori più bassi riducono l'utilizzo di contesto/risorse ma potrebbero richiedere più letture per file di grandi dimensioni.", + "lines": "righe" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/it/welcome.json b/webview-ui/src/i18n/locales/it/welcome.json index e05fc1c43e3..94dba7c2e90 100644 --- a/webview-ui/src/i18n/locales/it/welcome.json +++ b/webview-ui/src/i18n/locales/it/welcome.json @@ -3,6 +3,18 @@ "introduction": "Posso svolgere tutti i tipi di attività grazie ai più recenti progressi nelle capacità di codifica agentica e all'accesso a strumenti che mi permettono di creare e modificare file, esplorare progetti complessi, utilizzare il browser ed eseguire comandi terminal (con il tuo permesso, ovviamente). Posso persino utilizzare MCP per creare nuovi strumenti ed estendere le mie capacità.", "notice": "Per iniziare, questa estensione necessita di un fornitore di API.", "start": "Andiamo!", + "chooseProvider": "Scegli un fornitore di API per iniziare:", + "routers": { + "requesty": { + "description": "Il tuo router LLM ottimizzato", + "incentive": "$1 di credito gratuito" + }, + "openrouter": { + "description": "Un'interfaccia unificata per LLMs" + } + }, + "startRouter": "Configurazione rapida tramite router", + "startCustom": "Usa la tua chiave API", "telemetry": { "title": "Aiuta a migliorare Roo Code", "anonymousTelemetry": "Invia dati di utilizzo ed errori anonimi per aiutarci a correggere bug e migliorare l'estensione. Non viene mai inviato codice, testo o informazioni personali.", @@ -10,5 +22,6 @@ "settings": "impostazioni", "allow": "Consenti", "deny": "Nega" - } + }, + "or": "o" } diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 21a2f5410eb..5bbbc20a6f2 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -267,8 +267,9 @@ "description": "有効にすると、.rooignoreのパターンに一致するファイルがロックシンボル付きでリストに表示されます。無効にすると、これらのファイルはファイルリストや検索から完全に非表示になります。" }, "maxReadFile": { - "label": "ファイルから読み込む最大行数", - "description": "一度にファイルから読み込む最大行数。低い値はコンテキスト/リソース使用量を減らしますが、大きなファイルではより多くの読み込みが必要になる場合があります。" + "label": "ファイル読み込み自動切り詰めしきい値", + "description": "一括でファイルから読み込むデフォルトの行数。低い値はコンテキスト/リソース使用量を減らしますが、大きなファイルではより多くの読み込みが必要になる場合があります。", + "lines": "行" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ja/welcome.json b/webview-ui/src/i18n/locales/ja/welcome.json index 9e5b30e4c95..6b614d3dd20 100644 --- a/webview-ui/src/i18n/locales/ja/welcome.json +++ b/webview-ui/src/i18n/locales/ja/welcome.json @@ -3,6 +3,18 @@ "introduction": "エージェント型コーディング能力の最新の進歩と、ファイルの作成・編集、複雑なプロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行(もちろんあなたの許可を得て)を可能にするツールへのアクセスにより、あらゆる種類のタスクを実行できます。MCPを使用して新しいツールを作成し、自分の能力を拡張することもできます。", "notice": "開始するには、この拡張機能にはAPIプロバイダーが必要です。", "start": "さあ、始めましょう!", + "chooseProvider": "開始するにはAPIプロバイダーを選択してください:", + "routers": { + "requesty": { + "description": "最適化されたLLMルーター", + "incentive": "$1の無料クレジット" + }, + "openrouter": { + "description": "LLMsのための統一インターフェース" + } + }, + "startRouter": "ルーター経由の簡単セットアップ", + "startCustom": "自分のAPIキーを使用", "telemetry": { "title": "Roo Codeの改善にご協力ください", "anonymousTelemetry": "バグの修正と拡張機能の改善のため、匿名のエラーと使用データを送信してください。コード、プロンプト、個人情報は一切送信されません。", @@ -10,5 +22,6 @@ "settings": "設定", "allow": "許可", "deny": "拒否" - } + }, + "or": "または" } diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 54debd390fc..60d0e94405b 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -267,8 +267,9 @@ "description": "활성화되면 .rooignore의 패턴과 일치하는 파일이 잠금 기호와 함께 목록에 표시됩니다. 비활성화되면 이러한 파일은 파일 목록 및 검색에서 완전히 숨겨집니다." }, "maxReadFile": { - "label": "파일에서 읽을 최대 라인 수", - "description": "한 번에 파일에서 읽을 최대 라인 수. 낮은 값은 컨텍스트/리소스 사용량을 줄이지만 대용량 파일의 경우 더 많은 읽기가 필요할 수 있습니다." + "label": "파일 읽기 자동 축소 임계값", + "description": "한 번에 파일에서 읽을 기본 라인 수. 낮은 값은 컨텍스트/리소스 사용량을 줄이지만 대용량 파일의 경우 더 많은 읽기가 필요할 수 있습니다.", + "lines": "줄" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/ko/welcome.json b/webview-ui/src/i18n/locales/ko/welcome.json index b8b8cbd2527..83eb000af1b 100644 --- a/webview-ui/src/i18n/locales/ko/welcome.json +++ b/webview-ui/src/i18n/locales/ko/welcome.json @@ -3,6 +3,18 @@ "introduction": "에이전트 코딩 능력의 최신 발전과 파일 생성 및 편집, 복잡한 프로젝트 탐색, 브라우저 사용, 터미널 명령 실행(물론 사용자의 허락 하에)을 가능하게 하는 도구에 대한 접근 덕분에 모든 종류의 작업을 수행할 수 있습니다. MCP를 사용하여 새로운 도구를 만들고 제 능력을 확장할 수도 있습니다.", "notice": "시작하려면 이 확장 프로그램에 API 공급자가 필요합니다.", "start": "시작해 봅시다!", + "chooseProvider": "시작하려면 API 공급자를 선택하세요:", + "routers": { + "requesty": { + "description": "최적화된 LLM 라우터", + "incentive": "$1 무료 크레딧" + }, + "openrouter": { + "description": "LLM을 위한 통합 인터페이스" + } + }, + "startRouter": "라우터를 통한 빠른 설정", + "startCustom": "직접 API 키 사용하기", "telemetry": { "title": "Roo Code 개선에 도움 주세요", "anonymousTelemetry": "버그 수정 및 확장 기능 개선을 위해 익명의 오류 및 사용 데이터를 보내주세요. 코드, 프롬프트 또는 개인 정보는 절대 전송되지 않습니다.", @@ -10,5 +22,6 @@ "settings": "설정", "allow": "허용", "deny": "거부" - } + }, + "or": "또는" } diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 2b5938ddd70..1e4709df3fb 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -267,8 +267,9 @@ "description": "Gdy włączone, pliki pasujące do wzorców w .rooignore będą pokazywane na listach z symbolem kłódki. Gdy wyłączone, te pliki będą całkowicie ukryte z list plików i wyszukiwań." }, "maxReadFile": { - "label": "Maksymalna liczba linii do odczytu z pliku", - "description": "Maksymalna liczba linii odczytywanych z pliku jednocześnie. Niższe wartości zmniejszają użycie kontekstu/zasobów, ale mogą wymagać więcej odczytów dla dużych plików." + "label": "Próg automatycznego skracania odczytu pliku", + "description": "Domyślna liczba linii odczytywanych z pliku w jednej partii. Niższe wartości zmniejszają użycie kontekstu/zasobów, ale mogą wymagać więcej odczytów dla dużych plików.", + "lines": "linii" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/pl/welcome.json b/webview-ui/src/i18n/locales/pl/welcome.json index 0e6546bc21c..fb13723490b 100644 --- a/webview-ui/src/i18n/locales/pl/welcome.json +++ b/webview-ui/src/i18n/locales/pl/welcome.json @@ -3,6 +3,18 @@ "introduction": "Mogę wykonywać wszelkiego rodzaju zadania dzięki najnowszym osiągnięciom w zakresie możliwości kodowania agentowego i dostępu do narzędzi, które pozwalają mi tworzyć i edytować pliki, eksplorować złożone projekty, korzystać z przeglądarki i wykonywać polecenia terminalowe (oczywiście za Twoją zgodą). Mogę nawet używać MCP do tworzenia nowych narzędzi i rozszerzania własnych możliwości.", "notice": "Aby rozpocząć, to rozszerzenie potrzebuje dostawcy API.", "start": "Zaczynajmy!", + "chooseProvider": "Wybierz dostawcę API, aby rozpocząć:", + "routers": { + "requesty": { + "description": "Twój zoptymalizowany router LLM", + "incentive": "$1 darmowego kredytu" + }, + "openrouter": { + "description": "Ujednolicony interfejs dla LLMs" + } + }, + "startRouter": "Szybka konfiguracja przez router", + "startCustom": "Użyj własnego klucza API", "telemetry": { "title": "Pomóż ulepszyć Roo Code", "anonymousTelemetry": "Wyślij anonimowe dane o błędach i użyciu, aby pomóc nam w naprawianiu błędów i ulepszaniu rozszerzenia. Nigdy nie są wysyłane żadne kody, teksty ani informacje osobiste.", @@ -10,5 +22,6 @@ "settings": "ustawienia", "allow": "Zezwól", "deny": "Odmów" - } + }, + "or": "lub" } diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index a7c4b7283e0..db3f7458305 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -267,8 +267,9 @@ "description": "Quando ativado, os arquivos que correspondem aos padrões em .rooignore serão mostrados em listas com um símbolo de cadeado. Quando desativado, esses arquivos serão completamente ocultos das listas de arquivos e pesquisas." }, "maxReadFile": { - "label": "Número máximo de linhas para ler de um arquivo", - "description": "Número máximo de linhas para ler de um arquivo de uma vez. Valores mais baixos reduzem o uso de contexto/recursos, mas podem exigir mais leituras para arquivos grandes." + "label": "Limite de auto-truncamento de leitura de arquivo", + "description": "O número padrão de linhas para ler de um arquivo em um lote. Valores mais baixos reduzem o uso de contexto/recursos, mas podem exigir mais leituras para arquivos grandes.", + "lines": "linhas" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/pt-BR/welcome.json b/webview-ui/src/i18n/locales/pt-BR/welcome.json index c28386a6136..5f0fa0c193b 100644 --- a/webview-ui/src/i18n/locales/pt-BR/welcome.json +++ b/webview-ui/src/i18n/locales/pt-BR/welcome.json @@ -3,6 +3,18 @@ "introduction": "Posso realizar todos os tipos de tarefas graças aos últimos avanços nas capacidades de codificação agentica e ao acesso a ferramentas que me permitem criar e editar arquivos, explorar projetos complexos, usar o navegador e executar comandos de terminal (com sua permissão, é claro). Posso até usar o MCP para criar novas ferramentas e expandir minhas próprias capacidades.", "notice": "Para começar, esta extensão precisa de um provedor de API.", "start": "Vamos lá!", + "chooseProvider": "Escolha um provedor de API para começar:", + "routers": { + "requesty": { + "description": "Seu roteador LLM otimizado", + "incentive": "$1 de crédito grátis" + }, + "openrouter": { + "description": "Uma interface unificada para LLMs" + } + }, + "startRouter": "Configuração rápida através de um roteador", + "startCustom": "Use sua própria chave API", "telemetry": { "title": "Ajude a melhorar o Roo Code", "anonymousTelemetry": "Envie dados de uso e erros anônimos para nos ajudar a corrigir bugs e melhorar a extensão. Nenhum código, texto ou informação pessoal é enviado.", @@ -10,5 +22,6 @@ "settings": "configurações", "allow": "Permitir", "deny": "Negar" - } + }, + "or": "ou" } diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 078c495c46c..d02e16cd5c2 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -267,8 +267,9 @@ "description": "Etkinleştirildiğinde, .rooignore'daki desenlerle eşleşen dosyalar kilit sembolü ile listelerde gösterilecektir. Devre dışı bırakıldığında, bu dosyalar dosya listelerinden ve aramalardan tamamen gizlenecektir." }, "maxReadFile": { - "label": "Bir dosyadan okunacak maksimum satır sayısı", - "description": "Bir dosyadan bir kerede okunacak maksimum satır sayısı. Daha düşük değerler bağlam/kaynak kullanımını azaltır ancak büyük dosyalar için daha fazla okuma gerektirebilir." + "label": "Dosya okuma otomatik kısaltma eşiği", + "description": "Bir dosyadan bir partide okunacak varsayılan satır sayısı. Daha düşük değerler bağlam/kaynak kullanımını azaltır ancak büyük dosyalar için daha fazla okuma gerektirebilir.", + "lines": "satır" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/tr/welcome.json b/webview-ui/src/i18n/locales/tr/welcome.json index 2f25a1e93d5..76bf97429e3 100644 --- a/webview-ui/src/i18n/locales/tr/welcome.json +++ b/webview-ui/src/i18n/locales/tr/welcome.json @@ -1,14 +1,27 @@ { "greeting": "Merhaba, ben Roo!", - "introduction": "Ajan tabanlı kodlama yeteneklerindeki son gelişmeler ve dosya oluşturma ve düzenleme, karmaşık projeleri keşfetme, tarayıcı kullanma ve terminal komutları çalıştırma (tabii ki sizin izninizle) gibi işlemleri yapmamı sağlayan araçlara erişim sayesinde her türlü görevi gerçekleştirebilirim. Hatta MCP'yi kullanarak yeni araçlar oluşturabilir ve kendi yeteneklerimi genişletebilirim.", + "introduction": "Ajan tabanlı kodlama yeteneklerindeki son gelişmeler ve dosya oluşturma ve düzenleme, karmaşık projeleri keşfetme, tarayıcı kullanma ve terminal komutları çalıştırma (tabii ki senin izninle) gibi işlemleri yapmamı sağlayan araçlara erişim sayesinde her türlü görevi gerçekleştirebilirim. Hatta MCP'yi kullanarak yeni araçlar oluşturabilir ve kendi yeteneklerimi genişletebilirim.", "notice": "Başlamak için bu eklentinin bir API sağlayıcısına ihtiyacı var.", "start": "Hadi başlayalım!", + "chooseProvider": "Başlamak için bir API sağlayıcısı seç:", + "routers": { + "requesty": { + "description": "Optimize edilmiş LLM yönlendiricin", + "incentive": "$1 ücretsiz kredi" + }, + "openrouter": { + "description": "LLM'ler için birleşik bir arayüz" + } + }, + "startRouter": "Yönlendirici Üzerinden Hızlı Kurulum", + "startCustom": "Kendi API Anahtarını Kullan", "telemetry": { - "title": "Roo Code'u Geliştirmeye Yardım Edin", - "anonymousTelemetry": "Hataları düzeltmemize ve eklentiyi geliştirmemize yardımcı olmak için anonim hata ve kullanım verileri gönderin. Hiçbir zaman kod, metin veya kişisel bilgi gönderilmez.", - "changeSettings": "Bunu her zaman ayarların altından değiştirebilirsiniz", + "title": "Roo Code'u Geliştirmeye Yardım Et", + "anonymousTelemetry": "Hataları düzeltmemize ve eklentiyi geliştirmemize yardımcı olmak için anonim hata ve kullanım verileri gönder. Hiçbir zaman kod, metin veya kişisel bilgi gönderilmez.", + "changeSettings": "Bunu her zaman ayarların altından değiştirebilirsin", "settings": "ayarlar", "allow": "İzin Ver", "deny": "Reddet" - } + }, + "or": "veya" } diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 5344cc73308..bd197f2aaba 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -267,8 +267,9 @@ "description": "Khi được bật, các tệp khớp với mẫu trong .rooignore sẽ được hiển thị trong danh sách với biểu tượng khóa. Khi bị tắt, các tệp này sẽ hoàn toàn bị ẩn khỏi danh sách tệp và tìm kiếm." }, "maxReadFile": { - "label": "Số dòng tối đa để đọc từ một tệp", - "description": "Số dòng tối đa để đọc từ một tệp cùng một lúc. Giá trị thấp hơn giảm sử dụng ngữ cảnh/tài nguyên nhưng có thể yêu cầu đọc nhiều lần hơn cho các tệp lớn." + "label": "Ngưỡng tự động cắt ngắn khi đọc tệp", + "description": "Số dòng mặc định để đọc từ một tệp trong một lô. Giá trị thấp hơn giảm sử dụng ngữ cảnh/tài nguyên nhưng có thể yêu cầu đọc nhiều lần hơn cho các tệp lớn.", + "lines": "dòng" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/vi/welcome.json b/webview-ui/src/i18n/locales/vi/welcome.json index 4801b80b7f4..91dcea70c67 100644 --- a/webview-ui/src/i18n/locales/vi/welcome.json +++ b/webview-ui/src/i18n/locales/vi/welcome.json @@ -3,6 +3,18 @@ "introduction": "Tôi có thể thực hiện nhiều loại nhiệm vụ nhờ vào những đột phá mới nhất trong khả năng lập trình dạng đại lý và quyền truy cập vào các công cụ cho phép tôi tạo & chỉnh sửa tệp, khám phá các dự án phức tạp, sử dụng trình duyệt và thực thi lệnh terminal (với sự cho phép của bạn, tất nhiên). Tôi thậm chí có thể sử dụng MCP để tạo công cụ mới và mở rộng khả năng của mình.", "notice": "Để bắt đầu, tiện ích mở rộng này cần một nhà cung cấp API.", "start": "Bắt đầu thôi!", + "chooseProvider": "Chọn một nhà cung cấp API để bắt đầu:", + "routers": { + "requesty": { + "description": "Bộ định tuyến LLM được tối ưu hóa của bạn", + "incentive": "$1 tín dụng miễn phí" + }, + "openrouter": { + "description": "Giao diện thống nhất cho các LLM" + } + }, + "startRouter": "Thiết lập nhanh qua bộ định tuyến", + "startCustom": "Sử dụng khóa API của riêng bạn", "telemetry": { "title": "Giúp cải thiện Roo Code", "anonymousTelemetry": "Gửi dữ liệu lỗi và sử dụng ẩn danh để giúp chúng tôi sửa lỗi và cải thiện tiện ích mở rộng. Không bao giờ gửi mã, lời nhắc hoặc thông tin cá nhân.", @@ -10,5 +22,6 @@ "settings": "cài đặt", "allow": "Cho phép", "deny": "Từ chối" - } + }, + "or": "hoặc" } diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index aec816d94ad..d19096787d0 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -267,8 +267,9 @@ "description": "启用后,与 .rooignore 中模式匹配的文件将在列表中显示锁定符号。禁用时,这些文件将从文件列表和搜索中完全隐藏。" }, "maxReadFile": { - "label": "文件读取的最大行数", - "description": "一次从文件读取的最大行数。较低的值会减少上下文/资源使用,但可能需要对大文件进行更多次读取。" + "label": "文件读取自动截断阈值", + "description": "一次批处理中从文件读取的默认行数。较低的值会减少上下文/资源使用,但可能需要对大文件进行更多次读取。", + "lines": "行" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/zh-CN/welcome.json b/webview-ui/src/i18n/locales/zh-CN/welcome.json index 523e026f526..27fc616cf67 100644 --- a/webview-ui/src/i18n/locales/zh-CN/welcome.json +++ b/webview-ui/src/i18n/locales/zh-CN/welcome.json @@ -3,6 +3,18 @@ "introduction": "得益于最新的代理编码能力突破和对各种工具的访问权限,我可以完成各种任务。我可以创建和编辑文件、探索复杂项目、使用浏览器,以及执行终端命令(当然,需要你的许可)。我甚至可以使用 MCP 创建新工具并扩展自己的能力。", "notice": "首先,请配置一个大模型 API 服务商。", "start": "开始吧!", + "chooseProvider": "选择一个 API 服务商开始:", + "routers": { + "requesty": { + "description": "你的优化 LLM 路由器", + "incentive": "$1 免费额度" + }, + "openrouter": { + "description": "LLM 的统一接口" + } + }, + "startRouter": "通过路由器快速设置", + "startCustom": "使用你自己的 API 密钥", "telemetry": { "title": "帮助改进 Roo 代码", "changeSettings": "可以随时在设置页面底部更改此设置", @@ -10,5 +22,6 @@ "anonymousTelemetry": "发送匿名的错误和使用数据,以帮助我们修复错误并改进扩展程序。不会发送任何代码、提示或个人信息。", "allow": "允许", "deny": "拒绝" - } + }, + "or": "或" } diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index a2778f5bb8c..aed74ae3aad 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -267,8 +267,9 @@ "description": "啟用後,與 .rooignore 中模式匹配的檔案將在列表中顯示鎖定符號。禁用時,這些檔案將從檔案列表和搜尋中完全隱藏。" }, "maxReadFile": { - "label": "從檔案讀取的最大行數", - "description": "一次從檔案讀取的最大行數。較低的值會減少內容/資源使用,但可能需要對大型檔案進行更多次讀取。" + "label": "檔案讀取自動截斷閾值", + "description": "一批中從檔案讀取的預設行數。較低的值會減少內容/資源使用,但可能需要對大型檔案進行更多次讀取。", + "lines": "行" } }, "terminal": { diff --git a/webview-ui/src/i18n/locales/zh-TW/welcome.json b/webview-ui/src/i18n/locales/zh-TW/welcome.json index 7eadb6deb36..4d987628072 100644 --- a/webview-ui/src/i18n/locales/zh-TW/welcome.json +++ b/webview-ui/src/i18n/locales/zh-TW/welcome.json @@ -1,14 +1,27 @@ { "greeting": "嗨,我是 Roo!", - "introduction": "由於最新的代理編碼能力突破,以及能夠讓我創建和編輯文件、探索複雜項目、使用瀏覽器和執行終端命令的工具(當然是在您的許可下),我可以完成各種任務。我甚至可以使用 MCP 創建新工具並擴展自己的能力。", + "introduction": "由於最新的代理編碼能力突破,以及能夠讓我創建和編輯文件、探索複雜項目、使用瀏覽器和執行終端命令的工具(當然是在你的許可下),我可以完成各種任務。我甚至可以使用 MCP 創建新工具並擴展自己的能力。", "notice": "要開始使用,此擴展需要一個 API 提供者。", "start": "我們開始吧!", + "chooseProvider": "選擇一個 API 提供者開始:", + "routers": { + "requesty": { + "description": "你的優化 LLM 路由器", + "incentive": "$1 免費額度" + }, + "openrouter": { + "description": "LLM 的統一接口" + } + }, + "startRouter": "通過路由器快速設置", + "startCustom": "使用你自己的 API 密鑰", "telemetry": { "title": "幫助改進 Roo Code", "anonymousTelemetry": "發送匿名的錯誤和使用數據,以幫助我們修復錯誤並改進擴展功能。不會發送任何代碼、提示或個人信息。", - "changeSettings": "您隨時可以在設置底部更改此選項", + "changeSettings": "你隨時可以在設置底部更改此選項", "settings": "設置", "allow": "允許", "deny": "拒絕" - } + }, + "or": "或" } diff --git a/webview-ui/src/oauth/urls.ts b/webview-ui/src/oauth/urls.ts new file mode 100644 index 00000000000..46a1815377c --- /dev/null +++ b/webview-ui/src/oauth/urls.ts @@ -0,0 +1,16 @@ +export function getCallbackUrl(provider: string, uriScheme?: string) { + const callbackUrl = `${uriScheme || "vscode"}://rooveterinaryinc.roo-cline/${provider}` + return encodeURIComponent(callbackUrl) +} + +export function getGlamaAuthUrl(uriScheme?: string) { + return `https://glama.ai/oauth/authorize?callback_url=${getCallbackUrl("glama", uriScheme)}` +} + +export function getOpenRouterAuthUrl(uriScheme?: string) { + return `https://openrouter.ai/auth?callback_url=${getCallbackUrl("openrouter", uriScheme)}` +} + +export function getRequestyAuthUrl(uriScheme?: string) { + return `https://app.requesty.ai/oauth/authorize?callback_url=${getCallbackUrl("requesty", uriScheme)}` +} diff --git a/webview-ui/src/types.d.ts b/webview-ui/src/types.d.ts new file mode 100644 index 00000000000..ff5ef47841a --- /dev/null +++ b/webview-ui/src/types.d.ts @@ -0,0 +1,5 @@ +// Type declarations for third-party modules + +declare module "knuth-shuffle-seeded" { + export default function knuthShuffle(array: T[], seed: any): T[] +}