@aiderdesk/aiderdesk 0.61.1 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/out/renderer/assets/{_baseUniq-BPF2Herp.js → _baseUniq-C6Q8LpuQ.js} +1 -1
  2. package/out/renderer/assets/abap-B7h4dtBh.js +7 -0
  3. package/out/renderer/assets/actionscript-3-DtnkuHN2.js +7 -0
  4. package/out/renderer/assets/ada-BZS802Se.js +7 -0
  5. package/out/renderer/assets/andromeeda-C847lm7Z.js +4 -0
  6. package/out/renderer/assets/angular-html-BYG42TJr.js +42 -0
  7. package/out/renderer/assets/angular-ts-BftcHvZ6.js +29 -0
  8. package/out/renderer/assets/apache-D4roVlsU.js +7 -0
  9. package/out/renderer/assets/apex-B-mI3Md2.js +7 -0
  10. package/out/renderer/assets/apl-CGZawg-A.js +18 -0
  11. package/out/renderer/assets/applescript-C43Knf0G.js +7 -0
  12. package/out/renderer/assets/ara-DRBH84ND.js +7 -0
  13. package/out/renderer/assets/{arc-DfPLteHF.js → arc-DoIK-bD2.js} +1 -1
  14. package/out/renderer/assets/{architectureDiagram-Q4EWVU46-Bw0u-sSH.js → architectureDiagram-Q4EWVU46-B8_dgBXp.js} +5 -5
  15. package/out/renderer/assets/asciidoc-CT8_dLUs.js +7 -0
  16. package/out/renderer/assets/asm-3tg4MVib.js +7 -0
  17. package/out/renderer/assets/astro-BxdWOZvM.js +19 -0
  18. package/out/renderer/assets/aurora-x-wJ4-eM2h.js +4 -0
  19. package/out/renderer/assets/awk-ChreaG-G.js +7 -0
  20. package/out/renderer/assets/ayu-dark-rtpbXCNg.js +4 -0
  21. package/out/renderer/assets/ayu-light-BCZDSyV8.js +4 -0
  22. package/out/renderer/assets/ayu-mirage-BVoH71sA.js +4 -0
  23. package/out/renderer/assets/ballerina-B0yt0TYU.js +7 -0
  24. package/out/renderer/assets/bat-BzNgQIA7.js +7 -0
  25. package/out/renderer/assets/beancount-aZWrE5WV.js +7 -0
  26. package/out/renderer/assets/berry--Qc8OslH.js +7 -0
  27. package/out/renderer/assets/bibtex-BLeFwAes.js +7 -0
  28. package/out/renderer/assets/bicep-DbBeGdXQ.js +7 -0
  29. package/out/renderer/assets/bird2-aXhIUHPg.js +7 -0
  30. package/out/renderer/assets/blade-BbH7YAUi.js +22 -0
  31. package/out/renderer/assets/{blockDiagram-DXYQGD6D-CkfB9if8.js → blockDiagram-DXYQGD6D-BDOvGPDN.js} +6 -6
  32. package/out/renderer/assets/bsl-DwPS0BId.js +9 -0
  33. package/out/renderer/assets/c-C4VtT7JA.js +7 -0
  34. package/out/renderer/assets/c3-CWHczQMq.js +7 -0
  35. package/out/renderer/assets/{c4Diagram-AHTNJAMY-DweK9Liz.js → c4Diagram-AHTNJAMY-1ABZnJ2v.js} +2 -2
  36. package/out/renderer/assets/cadence-S_NtR5Dy.js +7 -0
  37. package/out/renderer/assets/cairo-BtYx2aM5.js +9 -0
  38. package/out/renderer/assets/catppuccin-frappe-C21OPQfC.js +4 -0
  39. package/out/renderer/assets/catppuccin-latte-0ZtXlsrX.js +4 -0
  40. package/out/renderer/assets/catppuccin-macchiato-BD_FR4sl.js +4 -0
  41. package/out/renderer/assets/catppuccin-mocha-C653csR5.js +4 -0
  42. package/out/renderer/assets/{channel-C5wwrRof.js → channel-Cr_H2zdE.js} +1 -1
  43. package/out/renderer/assets/{chunk-4BX2VUAB-0KM14cFd.js → chunk-4BX2VUAB-d88VZY9C.js} +1 -1
  44. package/out/renderer/assets/{chunk-4TB4RGXK-CmVtCVL4.js → chunk-4TB4RGXK-DLcMuHVI.js} +5 -5
  45. package/out/renderer/assets/{chunk-55IACEB6-BzVYZvBM.js → chunk-55IACEB6-BO1oJBQV.js} +1 -1
  46. package/out/renderer/assets/{chunk-EDXVE4YY-BryQl5Kv.js → chunk-EDXVE4YY-Dt80V_EG.js} +1 -1
  47. package/out/renderer/assets/{chunk-FMBD7UC4-CRiLea_e.js → chunk-FMBD7UC4-D5MNbIWZ.js} +1 -1
  48. package/out/renderer/assets/{chunk-OYMX7WX6-Cpi4N3NO.js → chunk-OYMX7WX6-DBFhtMcs.js} +3 -3
  49. package/out/renderer/assets/{chunk-QZHKN3VN-BT8kABWC.js → chunk-QZHKN3VN-Bxwt_pyh.js} +1 -1
  50. package/out/renderer/assets/{chunk-YZCP3GAM-OLZV_Sef.js → chunk-YZCP3GAM-gAcMGuhT.js} +1 -1
  51. package/out/renderer/assets/clarity-D2ViJC0i.js +7 -0
  52. package/out/renderer/assets/{classDiagram-6PBFFD2Q-VdE6G90i.js → classDiagram-6PBFFD2Q-B7lgamMP.js} +6 -6
  53. package/out/renderer/assets/{classDiagram-v2-HSJHXN6E-VdE6G90i.js → classDiagram-v2-HSJHXN6E-B7lgamMP.js} +6 -6
  54. package/out/renderer/assets/clojure-C_G4_w5x.js +7 -0
  55. package/out/renderer/assets/{clone-DwQZ86nS.js → clone-DKkqtIT8.js} +1 -1
  56. package/out/renderer/assets/cmake-CDfQILeU.js +7 -0
  57. package/out/renderer/assets/cobol-B8r1pfPr.js +13 -0
  58. package/out/renderer/assets/codeowners-awy7PWCD.js +7 -0
  59. package/out/renderer/assets/codeql-lfK8ppuq.js +7 -0
  60. package/out/renderer/assets/coffee-XLjtuEYs.js +9 -0
  61. package/out/renderer/assets/common-lisp-DAq1kaby.js +7 -0
  62. package/out/renderer/assets/coq-l_JvzFJl.js +7 -0
  63. package/out/renderer/assets/{cose-bilkent-S5V4N54A-BEcAKM9H.js → cose-bilkent-S5V4N54A-BZNBIG2x.js} +1 -1
  64. package/out/renderer/assets/cpp-zh2ePAE_.js +22 -0
  65. package/out/renderer/assets/crystal-BqBRy7Ec.js +19 -0
  66. package/out/renderer/assets/csharp-DxX_6tHh.js +7 -0
  67. package/out/renderer/assets/css-BtVcDqlU.js +7 -0
  68. package/out/renderer/assets/csv-Ba84L8e5.js +7 -0
  69. package/out/renderer/assets/cue-BFSVLV6N.js +7 -0
  70. package/out/renderer/assets/cypher-DbUmWIxC.js +7 -0
  71. package/out/renderer/assets/d-9qSZPw74.js +7 -0
  72. package/out/renderer/assets/{dagre-KV5264BT-BcFQYL1M.js → dagre-KV5264BT-C3hXUNb-.js} +6 -6
  73. package/out/renderer/assets/dark-plus-DmZ1Dzd4.js +4 -0
  74. package/out/renderer/assets/dart-CCSsOg9l.js +7 -0
  75. package/out/renderer/assets/dax-CvsmLV-B.js +7 -0
  76. package/out/renderer/assets/desktop-_xiGZ9X1.js +7 -0
  77. package/out/renderer/assets/{diagram-5BDNPKRD-GrUNdC1u.js → diagram-5BDNPKRD-DNh45EqP.js} +6 -6
  78. package/out/renderer/assets/{diagram-G4DWMVQ6-CG4S-ov5.js → diagram-G4DWMVQ6-8lhqJfPk.js} +6 -6
  79. package/out/renderer/assets/{diagram-MMDJMWI5-9ogY3MRC.js → diagram-MMDJMWI5-BcI1Ek4N.js} +5 -5
  80. package/out/renderer/assets/{diagram-TYMM5635-Ck7mI1bS.js → diagram-TYMM5635-DuHcW-s7.js} +5 -5
  81. package/out/renderer/assets/diff-BEdzuHlE.js +7 -0
  82. package/out/renderer/assets/docker-CUaLOm2I.js +7 -0
  83. package/out/renderer/assets/dotenv-Bb4iNxXK.js +7 -0
  84. package/out/renderer/assets/dracula-B8-AVrwI.js +4 -0
  85. package/out/renderer/assets/dracula-soft-BHeefow7.js +4 -0
  86. package/out/renderer/assets/dream-maker-CNLQpoF-.js +7 -0
  87. package/out/renderer/assets/edge-CnHxQ_FD.js +15 -0
  88. package/out/renderer/assets/elixir-B_LIBv5J.js +11 -0
  89. package/out/renderer/assets/elm-BlO7pcFp.js +10 -0
  90. package/out/renderer/assets/emacs-lisp-4gdXY_g3.js +7 -0
  91. package/out/renderer/assets/{erDiagram-SMLLAGMA-Dvf_c-7M.js → erDiagram-SMLLAGMA-I6Q9HYdF.js} +4 -4
  92. package/out/renderer/assets/erb-Bzn22wO6.js +28 -0
  93. package/out/renderer/assets/erlang-Ch5kuXHm.js +9 -0
  94. package/out/renderer/assets/everforest-dark-Cg1xdODP.js +4 -0
  95. package/out/renderer/assets/everforest-light-BmTD3bxe.js +4 -0
  96. package/out/renderer/assets/fennel-BTELNkeT.js +7 -0
  97. package/out/renderer/assets/fish-kGF2-4SL.js +7 -0
  98. package/out/renderer/assets/{flowDiagram-DWJPFMVM-CPDjOXYp.js → flowDiagram-DWJPFMVM-BzRjtX5C.js} +6 -6
  99. package/out/renderer/assets/fluent-YyC28MRr.js +7 -0
  100. package/out/renderer/assets/fortran-fixed-form-CpmOyvS5.js +9 -0
  101. package/out/renderer/assets/fortran-free-form-5X94ETMi.js +7 -0
  102. package/out/renderer/assets/fsharp-5vtGqRR9.js +9 -0
  103. package/out/renderer/assets/{ganttDiagram-T4ZO3ILL-B4dJrK-3.js → ganttDiagram-T4ZO3ILL-DVkem_IA.js} +1 -1
  104. package/out/renderer/assets/gdresource-B5TLWiFO.js +11 -0
  105. package/out/renderer/assets/gdscript-CNW3Aj-d.js +7 -0
  106. package/out/renderer/assets/gdshader-BEzE4j_3.js +7 -0
  107. package/out/renderer/assets/genie-BvhtM5Ga.js +7 -0
  108. package/out/renderer/assets/gherkin-xCNF9gh8.js +7 -0
  109. package/out/renderer/assets/git-commit-PP9xCApN.js +9 -0
  110. package/out/renderer/assets/git-rebase-D-XQSvDj.js +9 -0
  111. package/out/renderer/assets/{gitGraphDiagram-UUTBAWPF-De2eCfMN.js → gitGraphDiagram-UUTBAWPF-BYpvdMpK.js} +6 -6
  112. package/out/renderer/assets/github-dark-O22yVQaY.js +4 -0
  113. package/out/renderer/assets/github-dark-default-DB2Hkvqn.js +4 -0
  114. package/out/renderer/assets/github-dark-dimmed-CMZ_OfqC.js +4 -0
  115. package/out/renderer/assets/github-dark-high-contrast-DmxWVmCU.js +4 -0
  116. package/out/renderer/assets/github-light-BTbR9xVK.js +4 -0
  117. package/out/renderer/assets/github-light-default-DWEonwFe.js +4 -0
  118. package/out/renderer/assets/github-light-high-contrast-WJ_cPDts.js +4 -0
  119. package/out/renderer/assets/gleam-LmNxrMsN.js +7 -0
  120. package/out/renderer/assets/glimmer-js-h2QNNiD7.js +15 -0
  121. package/out/renderer/assets/glimmer-ts-Bk3uX6Ae.js +15 -0
  122. package/out/renderer/assets/glsl-CGsiYPcu.js +9 -0
  123. package/out/renderer/assets/gn-OUMx7fqt.js +7 -0
  124. package/out/renderer/assets/gnuplot-tV8vezdE.js +7 -0
  125. package/out/renderer/assets/go-DRMr3iML.js +7 -0
  126. package/out/renderer/assets/{graph-BFn23kR_.js → graph-CAtr5PoG.js} +2 -2
  127. package/out/renderer/assets/graphql-CwmtR1ib.js +15 -0
  128. package/out/renderer/assets/groovy-Bn4MhXgW.js +7 -0
  129. package/out/renderer/assets/gruvbox-dark-hard-DVsRsETr.js +4 -0
  130. package/out/renderer/assets/gruvbox-dark-medium-B5JBrQdg.js +4 -0
  131. package/out/renderer/assets/gruvbox-dark-soft-Db-YOqRx.js +4 -0
  132. package/out/renderer/assets/gruvbox-light-hard-CXzJt7DI.js +4 -0
  133. package/out/renderer/assets/gruvbox-light-medium-B89RAI1Y.js +4 -0
  134. package/out/renderer/assets/gruvbox-light-soft-Cs0hTZYv.js +4 -0
  135. package/out/renderer/assets/hack-BTX3ICIE.js +13 -0
  136. package/out/renderer/assets/haml-DrIklt7F.js +11 -0
  137. package/out/renderer/assets/handlebars-yWFGGD2R.js +15 -0
  138. package/out/renderer/assets/haskell-CzPS7wjM.js +7 -0
  139. package/out/renderer/assets/haxe-BpobLYM9.js +7 -0
  140. package/out/renderer/assets/hcl-axoq0Ycu.js +7 -0
  141. package/out/renderer/assets/hjson-I7LcauIB.js +7 -0
  142. package/out/renderer/assets/hlsl-TRzjajlb.js +7 -0
  143. package/out/renderer/assets/horizon-DWzh3z5C.js +4 -0
  144. package/out/renderer/assets/horizon-bright-C1AFkPsv.js +4 -0
  145. package/out/renderer/assets/houston-CF_ws8Cq.js +4 -0
  146. package/out/renderer/assets/html-GC16tDh9.js +11 -0
  147. package/out/renderer/assets/html-derivative-HU9p64q4.js +11 -0
  148. package/out/renderer/assets/http-DjsOm9E4.js +20 -0
  149. package/out/renderer/assets/hurl-Am2cDU4f.js +18 -0
  150. package/out/renderer/assets/hxml-Jle7oGdm.js +9 -0
  151. package/out/renderer/assets/hy-B1k9U6S8.js +7 -0
  152. package/out/renderer/assets/imba-C4923lSV.js +7 -0
  153. package/out/renderer/assets/{index-BL-57WPa.js → index-CNL53LoL.js} +33672 -11520
  154. package/out/renderer/assets/{index-BkntVzTm.css → index-Duw36zwk.css} +209 -24
  155. package/out/renderer/assets/{infoDiagram-42DDH7IO-BIt9B6mQ.js → infoDiagram-42DDH7IO-BcmBthOY.js} +4 -4
  156. package/out/renderer/assets/ini-B84Ha1bx.js +7 -0
  157. package/out/renderer/assets/{ishikawaDiagram-UXIWVN3A-CXZs0KGV.js → ishikawaDiagram-UXIWVN3A-moTWny-V.js} +1 -1
  158. package/out/renderer/assets/java-BfXh-0uJ.js +7 -0
  159. package/out/renderer/assets/javascript-BsAkV7mL.js +7 -0
  160. package/out/renderer/assets/jinja-FkIlHBgj.js +16 -0
  161. package/out/renderer/assets/jison-BkdOIOd4.js +9 -0
  162. package/out/renderer/assets/{journeyDiagram-VCZTEJTY-B-EXuj5b.js → journeyDiagram-VCZTEJTY-DOW8zaZt.js} +4 -4
  163. package/out/renderer/assets/json-TjWBGEk1.js +7 -0
  164. package/out/renderer/assets/json5-DCGCKrmX.js +7 -0
  165. package/out/renderer/assets/jsonc-DLVLp8id.js +7 -0
  166. package/out/renderer/assets/jsonl-B-R_pDGg.js +7 -0
  167. package/out/renderer/assets/jsonnet-Cs8BnnC6.js +7 -0
  168. package/out/renderer/assets/jssm-DDuANZ2u.js +7 -0
  169. package/out/renderer/assets/jsx-BPmvoin2.js +7 -0
  170. package/out/renderer/assets/julia-CU_UwNb8.js +20 -0
  171. package/out/renderer/assets/just-tGFryTtU.js +34 -0
  172. package/out/renderer/assets/kanagawa-dragon-DU8n2NNT.js +4 -0
  173. package/out/renderer/assets/kanagawa-lotus-Byd0CDet.js +4 -0
  174. package/out/renderer/assets/kanagawa-wave-DExoagcR.js +4 -0
  175. package/out/renderer/assets/{kanban-definition-6JOO6SKY-ByvN0qaD.js → kanban-definition-6JOO6SKY-DpJjTob4.js} +2 -2
  176. package/out/renderer/assets/kdl-DzNQTDs7.js +7 -0
  177. package/out/renderer/assets/kotlin-BM2ZNTMh.js +7 -0
  178. package/out/renderer/assets/kusto-dtpuxMFE.js +7 -0
  179. package/out/renderer/assets/laserwave-DF03wMlf.js +4 -0
  180. package/out/renderer/assets/latex-B0gTO9uZ.js +10 -0
  181. package/out/renderer/assets/{layout-BpybWUv6.js → layout-BvH51Ui9.js} +4 -4
  182. package/out/renderer/assets/lean-CTow-IzD.js +7 -0
  183. package/out/renderer/assets/less-BAzLMJNR.js +7 -0
  184. package/out/renderer/assets/light-plus-DS08Xg5J.js +4 -0
  185. package/out/renderer/assets/liquid-QmJ_LYTW.js +15 -0
  186. package/out/renderer/assets/llvm-CTKcAHbb.js +7 -0
  187. package/out/renderer/assets/log-BF22rfM9.js +7 -0
  188. package/out/renderer/assets/logo-D9l7oEJ8.js +7 -0
  189. package/out/renderer/assets/lua-BVbbqwZC.js +9 -0
  190. package/out/renderer/assets/luau-CdZ6BoEa.js +7 -0
  191. package/out/renderer/assets/make-DLtqaK4D.js +7 -0
  192. package/out/renderer/assets/markdown-F_EULe_G.js +7 -0
  193. package/out/renderer/assets/marko-BAWrmNIa.js +15 -0
  194. package/out/renderer/assets/material-theme-B8B2U48Q.js +4 -0
  195. package/out/renderer/assets/material-theme-darker-BV0iY_T3.js +4 -0
  196. package/out/renderer/assets/material-theme-lighter-DrzybSTF.js +4 -0
  197. package/out/renderer/assets/material-theme-ocean-BRPLVReX.js +4 -0
  198. package/out/renderer/assets/material-theme-palenight-DSJwsR_D.js +4 -0
  199. package/out/renderer/assets/matlab-7XHduepk.js +7 -0
  200. package/out/renderer/assets/mdc-Ca0ft0PS.js +16 -0
  201. package/out/renderer/assets/mdx-D5wExp-O.js +7 -0
  202. package/out/renderer/assets/mermaid-z_1ejSlp.js +7 -0
  203. package/out/renderer/assets/{min-DB8ixvoT.js → min-CowxrbD6.js} +2 -2
  204. package/out/renderer/assets/min-dark-BNaN9fWk.js +4 -0
  205. package/out/renderer/assets/min-light-CMrjentn.js +4 -0
  206. package/out/renderer/assets/{mindmap-definition-QFDTVHPH-Do-I-At8.js → mindmap-definition-QFDTVHPH-DggFFNHq.js} +3 -3
  207. package/out/renderer/assets/mipsasm-BQyyUrpa.js +7 -0
  208. package/out/renderer/assets/mojo-ByCRDvCf.js +7 -0
  209. package/out/renderer/assets/monokai-DelygWXa.js +4 -0
  210. package/out/renderer/assets/moonbit-CqjK87KZ.js +7 -0
  211. package/out/renderer/assets/move-DhTNmxqC.js +7 -0
  212. package/out/renderer/assets/narrat-CLjGcbCy.js +7 -0
  213. package/out/renderer/assets/nextflow-B166B-y1.js +9 -0
  214. package/out/renderer/assets/nextflow-groovy-BOO9s0iq.js +7 -0
  215. package/out/renderer/assets/nginx-BFAkI5_-.js +10 -0
  216. package/out/renderer/assets/night-owl-DSS199ra.js +4 -0
  217. package/out/renderer/assets/night-owl-light-gC6E-Eh2.js +4 -0
  218. package/out/renderer/assets/nim-B3PAIZ4D.js +22 -0
  219. package/out/renderer/assets/nix-ByWcmvXF.js +12 -0
  220. package/out/renderer/assets/nord-CvDbBq5M.js +4 -0
  221. package/out/renderer/assets/nushell-DB8ZUEbK.js +7 -0
  222. package/out/renderer/assets/objective-c-BRoNQF42.js +7 -0
  223. package/out/renderer/assets/objective-cpp-DEoN9Fe5.js +7 -0
  224. package/out/renderer/assets/ocaml-B1kfGk9Y.js +7 -0
  225. package/out/renderer/assets/odin-CNQ56Ay2.js +7 -0
  226. package/out/renderer/assets/one-dark-pro-CsMf0BoJ.js +4 -0
  227. package/out/renderer/assets/one-light-B0cTzZyr.js +4 -0
  228. package/out/renderer/assets/openscad-C_m7ehZF.js +7 -0
  229. package/out/renderer/assets/pascal-CU8Kjkr_.js +7 -0
  230. package/out/renderer/assets/perl-HITCDkgu.js +18 -0
  231. package/out/renderer/assets/php-C2HieitX.js +20 -0
  232. package/out/renderer/assets/{pieDiagram-DEJITSTG-Cnpf6Gt6.js → pieDiagram-DEJITSTG-BED4dnMF.js} +6 -6
  233. package/out/renderer/assets/pierre-dark-DADY5eR0.js +4 -0
  234. package/out/renderer/assets/pierre-light-DUjirxKp.js +4 -0
  235. package/out/renderer/assets/pkl-BsByaYax.js +7 -0
  236. package/out/renderer/assets/plastic-BjwMpBc0.js +4 -0
  237. package/out/renderer/assets/plsql-B3Na24V4.js +7 -0
  238. package/out/renderer/assets/po-BajfNjc5.js +7 -0
  239. package/out/renderer/assets/poimandres-ChWyhPrn.js +4 -0
  240. package/out/renderer/assets/polar-BB-dlxnO.js +7 -0
  241. package/out/renderer/assets/postcss-kj1IbjVd.js +7 -0
  242. package/out/renderer/assets/powerquery-B-e1fO-k.js +7 -0
  243. package/out/renderer/assets/powershell-BcMVbGpk.js +7 -0
  244. package/out/renderer/assets/prisma-bmxcSDxq.js +7 -0
  245. package/out/renderer/assets/prolog-BT9GCzqD.js +7 -0
  246. package/out/renderer/assets/proto-Ds-m32NR.js +7 -0
  247. package/out/renderer/assets/pug-BwQB43qN.js +13 -0
  248. package/out/renderer/assets/puppet-N15G4Usj.js +7 -0
  249. package/out/renderer/assets/purescript-DrwsEYNH.js +7 -0
  250. package/out/renderer/assets/python-CrdIx4PZ.js +7 -0
  251. package/out/renderer/assets/qml-jtL8okyu.js +9 -0
  252. package/out/renderer/assets/qmldir-DuMSk0Oz.js +7 -0
  253. package/out/renderer/assets/qss-BFrB6p4y.js +7 -0
  254. package/out/renderer/assets/{quadrantDiagram-34T5L4WZ-VcOb1qLd.js → quadrantDiagram-34T5L4WZ-RpQ3qNU5.js} +1 -1
  255. package/out/renderer/assets/r-Dpdc-Kyk.js +7 -0
  256. package/out/renderer/assets/racket-DbA06HL7.js +7 -0
  257. package/out/renderer/assets/raku-6v-Y17bs.js +7 -0
  258. package/out/renderer/assets/razor-gBXW6YBJ.js +13 -0
  259. package/out/renderer/assets/red-DByOl5N0.js +4 -0
  260. package/out/renderer/assets/reg-CULnG2WX.js +7 -0
  261. package/out/renderer/assets/regexp-BxWeO75u.js +7 -0
  262. package/out/renderer/assets/rel-CHRwzjd4.js +7 -0
  263. package/out/renderer/assets/{requirementDiagram-MS252O5E-VJs9Hpaw.js → requirementDiagram-MS252O5E-VQt4zBMB.js} +3 -3
  264. package/out/renderer/assets/riscv-BNQ9cVpw.js +7 -0
  265. package/out/renderer/assets/ron-CUEPaFZU.js +7 -0
  266. package/out/renderer/assets/rose-pine-B-kZ4Z9q.js +4 -0
  267. package/out/renderer/assets/rose-pine-dawn-efeVGdSI.js +4 -0
  268. package/out/renderer/assets/rose-pine-moon-DmodZNzl.js +4 -0
  269. package/out/renderer/assets/rosmsg-Bfahr6vb.js +7 -0
  270. package/out/renderer/assets/rst-by6KAwTb.js +37 -0
  271. package/out/renderer/assets/ruby-C13Bjepi.js +37 -0
  272. package/out/renderer/assets/rust-CMNYZh5a.js +7 -0
  273. package/out/renderer/assets/{sankeyDiagram-XADWPNL6-BoXxgLvi.js → sankeyDiagram-XADWPNL6-DywR7qAk.js} +1 -1
  274. package/out/renderer/assets/sas-BLBgC3TA.js +9 -0
  275. package/out/renderer/assets/sass-BheygBdF.js +7 -0
  276. package/out/renderer/assets/scala-B-_7vFVn.js +7 -0
  277. package/out/renderer/assets/scheme-BSHdPinv.js +7 -0
  278. package/out/renderer/assets/scss-Dq-LbI_c.js +9 -0
  279. package/out/renderer/assets/sdbl-BBUhycGU.js +7 -0
  280. package/out/renderer/assets/{sequenceDiagram-FGHM5R23-b69hQjSp.js → sequenceDiagram-FGHM5R23-CVPfZD4e.js} +3 -3
  281. package/out/renderer/assets/shaderlab-C07uO3dL.js +9 -0
  282. package/out/renderer/assets/shellscript-CQ8MXh-D.js +7 -0
  283. package/out/renderer/assets/shellsession-CkeTp4M1.js +9 -0
  284. package/out/renderer/assets/slack-dark-BEe10hxO.js +4 -0
  285. package/out/renderer/assets/slack-ochin-BKmu9pBc.js +4 -0
  286. package/out/renderer/assets/smalltalk-qxcGy4fT.js +7 -0
  287. package/out/renderer/assets/snazzy-light-Dcvd-ZyI.js +4 -0
  288. package/out/renderer/assets/solarized-dark-BBl5y5sR.js +4 -0
  289. package/out/renderer/assets/solarized-light-DW9b_AY8.js +4 -0
  290. package/out/renderer/assets/solidity-CSTQ0FCC.js +7 -0
  291. package/out/renderer/assets/soy-BHaHgMUy.js +11 -0
  292. package/out/renderer/assets/sparql-DswowMAp.js +9 -0
  293. package/out/renderer/assets/splunk-DcGJXIDa.js +7 -0
  294. package/out/renderer/assets/sql-DzUuSofg.js +7 -0
  295. package/out/renderer/assets/ssh-config-Bk_I5wDR.js +7 -0
  296. package/out/renderer/assets/stata-Dl7wDdBE.js +9 -0
  297. package/out/renderer/assets/{stateDiagram-FHFEXIEX-BK7E-REm.js → stateDiagram-FHFEXIEX-BrH8Q8ZG.js} +8 -8
  298. package/out/renderer/assets/{stateDiagram-v2-QKLJ7IA2-Cd2wfCQu.js → stateDiagram-v2-QKLJ7IA2-BTWk2K0H.js} +4 -4
  299. package/out/renderer/assets/stylus-DXFa_2Jl.js +7 -0
  300. package/out/renderer/assets/surrealql-Bs3vUeKA.js +9 -0
  301. package/out/renderer/assets/svelte-fC0HkEkx.js +15 -0
  302. package/out/renderer/assets/swift-Cohr-WZC.js +7 -0
  303. package/out/renderer/assets/synthwave-84-CoUef9sh.js +4 -0
  304. package/out/renderer/assets/system-verilog-BcESSvRn.js +7 -0
  305. package/out/renderer/assets/systemd-DJPFjU02.js +7 -0
  306. package/out/renderer/assets/talonscript-CEEMXJTH.js +7 -0
  307. package/out/renderer/assets/tasl-DfOr2qHi.js +7 -0
  308. package/out/renderer/assets/tcl-CTsc4-t7.js +7 -0
  309. package/out/renderer/assets/templ-CSEiQwNm.js +13 -0
  310. package/out/renderer/assets/terraform-CeztUfUr.js +7 -0
  311. package/out/renderer/assets/tex-CGVqF8nD.js +9 -0
  312. package/out/renderer/assets/{timeline-definition-GMOUNBTQ-Bl-MTfK5.js → timeline-definition-GMOUNBTQ-DwDUCrTb.js} +2 -2
  313. package/out/renderer/assets/tokyo-night-DjtLpAEY.js +4 -0
  314. package/out/renderer/assets/toml-vHPzWDj6.js +7 -0
  315. package/out/renderer/assets/ts-tags-cG2hZuda.js +54 -0
  316. package/out/renderer/assets/tsv-ChRVFvMy.js +7 -0
  317. package/out/renderer/assets/tsx-CmGGo4Hm.js +7 -0
  318. package/out/renderer/assets/turtle-BnC7StHY.js +7 -0
  319. package/out/renderer/assets/twig-CwEEYIBf.js +36 -0
  320. package/out/renderer/assets/typescript-CP6ECzON.js +7 -0
  321. package/out/renderer/assets/typespec-CkDVVIcK.js +7 -0
  322. package/out/renderer/assets/typst-XYLFxYau.js +7 -0
  323. package/out/renderer/assets/v-BSYXvR4g.js +7 -0
  324. package/out/renderer/assets/vala-qJa5rry9.js +7 -0
  325. package/out/renderer/assets/vb-Bzg9rspf.js +7 -0
  326. package/out/renderer/assets/{vennDiagram-DHZGUBPP-DNmr1k2L.js → vennDiagram-DHZGUBPP-Bjvr7yGM.js} +1 -1
  327. package/out/renderer/assets/verilog-CCb_iTfF.js +7 -0
  328. package/out/renderer/assets/vesper-4Q1cEwPL.js +4 -0
  329. package/out/renderer/assets/vhdl-DMqk4T2s.js +7 -0
  330. package/out/renderer/assets/viml--FINbfoq.js +7 -0
  331. package/out/renderer/assets/vitesse-black-BqNLki8b.js +4 -0
  332. package/out/renderer/assets/vitesse-dark-jJ32WhwH.js +4 -0
  333. package/out/renderer/assets/vitesse-light-476zM4e6.js +4 -0
  334. package/out/renderer/assets/vue-K-7Ga-y8.js +40 -0
  335. package/out/renderer/assets/vue-html-DhreShjd.js +9 -0
  336. package/out/renderer/assets/vue-vine-rMIwOpFf.js +19 -0
  337. package/out/renderer/assets/vyper-DP4whl13.js +7 -0
  338. package/out/renderer/assets/{wardley-RL74JXVD-DTbxPMj9.js → wardley-RL74JXVD-Bo-sW7uQ.js} +3 -3
  339. package/out/renderer/assets/{wardleyDiagram-NUSXRM2D-BWw08wtD.js → wardleyDiagram-NUSXRM2D-DRW_1PCJ.js} +5 -5
  340. package/out/renderer/assets/wasm-BBh6f151.js +7 -0
  341. package/out/renderer/assets/wasm-DDgzZJey.js +10 -0
  342. package/out/renderer/assets/wenyan-BdqozpMZ.js +7 -0
  343. package/out/renderer/assets/wgsl-Vo-hHVWH.js +7 -0
  344. package/out/renderer/assets/wikitext-BDjE6pmL.js +7 -0
  345. package/out/renderer/assets/wit-C_nQzOkY.js +7 -0
  346. package/out/renderer/assets/wolfram-CRmjUoI4.js +7 -0
  347. package/out/renderer/assets/xml-BMzZeaqs.js +9 -0
  348. package/out/renderer/assets/xsl-CnwVr_6q.js +10 -0
  349. package/out/renderer/assets/{xychartDiagram-5P7HB3ND-EEYPnLDT.js → xychartDiagram-5P7HB3ND-Ds-qS4nC.js} +1 -1
  350. package/out/renderer/assets/yaml-B_vW5iTY.js +7 -0
  351. package/out/renderer/assets/zenscript-DFINJL6j.js +7 -0
  352. package/out/renderer/assets/zig-CS4FMAZp.js +7 -0
  353. package/out/renderer/index.html +2 -2
  354. package/out/resources/connector/connector.py +9 -6
  355. package/out/resources/mcp-server/aider-desk-mcp-server.js +16 -1
  356. package/out/resources/prompts/code-change-requests.hbs +21 -0
  357. package/out/resources/skills/extension-creator/SKILL.md +25 -0
  358. package/out/resources/skills/extension-creator/references/config-components.md +6 -6
  359. package/out/resources/skills/extension-creator/references/extension-interface.md +66 -0
  360. package/out/runner.js +1650 -409
  361. package/package.json +12 -10
  362. package/patches/@ai-sdk+deepseek+1.0.37.patch +150 -0
  363. package/out/resources/prompts/code-inline-request.hbs +0 -16
  364. /package/patches/{ai+5.0.167.patch → ai+5.0.179.patch} +0 -0
package/out/runner.js CHANGED
@@ -31,12 +31,8 @@ const node_sqlite = require("node:sqlite");
31
31
  const path = require("path");
32
32
  const os = require("os");
33
33
  const http = require("http");
34
- const undici = require("undici");
35
- const uuid = require("uuid");
36
- const ai = require("ai");
37
34
  const gpt4o = require("gpt-tokenizer/model/gpt-4o");
38
35
  const istextorbinary = require("istextorbinary");
39
- const fileType = require("file-type");
40
36
  const child_process = require("child_process");
41
37
  const treeKill = require("tree-kill");
42
38
  const glob = require("glob");
@@ -51,7 +47,7 @@ const filenamifyImport = require("filenamify");
51
47
  const slugify = require("slugify");
52
48
  const Turndown = require("turndown");
53
49
  const cheerio = require("cheerio");
54
- const yamlFrontMatter = require("yaml-front-matter");
50
+ const uuid = require("uuid");
55
51
  const index_js = require("@modelcontextprotocol/sdk/client/index.js");
56
52
  const stdio_js = require("@modelcontextprotocol/sdk/client/stdio.js");
57
53
  const streamableHttp_js = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -62,8 +58,13 @@ const express = require("express");
62
58
  const cors = require("cors");
63
59
  const cloudflared = require("cloudflared");
64
60
  const socket_io = require("socket.io");
61
+ const yamlFrontMatter = require("yaml-front-matter");
65
62
  const debounce = require("lodash/debounce.js");
66
63
  const crypto = require("crypto");
64
+ const undici = require("undici");
65
+ const globalAgent = require("global-agent");
66
+ const ai = require("ai");
67
+ const fileType = require("file-type");
67
68
  const anthropic = require("@ai-sdk/anthropic");
68
69
  const azure = require("@ai-sdk/azure");
69
70
  const clientBedrock = require("@aws-sdk/client-bedrock");
@@ -78,6 +79,7 @@ const genai = require("@google/genai");
78
79
  const openaiCompatible = require("@ai-sdk/openai-compatible");
79
80
  const groq = require("@ai-sdk/groq");
80
81
  const alibaba = require("@ai-sdk/alibaba");
82
+ const mistral = require("@ai-sdk/mistral");
81
83
  const ollamaAiProviderV2 = require("ollama-ai-provider-v2");
82
84
  const openai = require("@ai-sdk/openai");
83
85
  const aiSdkProvider = require("@openrouter/ai-sdk-provider");
@@ -241,6 +243,7 @@ const WorktreeSchema = zod.z.object({
241
243
  path: zod.z.string(),
242
244
  baseBranch: zod.z.string().optional(),
243
245
  baseCommit: zod.z.string().optional(),
246
+ branch: zod.z.string().optional(),
244
247
  prunable: zod.z.boolean().optional()
245
248
  });
246
249
  const MergeStateSchema = zod.z.object({
@@ -297,7 +300,10 @@ const ProjectSettingsSchema = zod.z.object({
297
300
  contextCompactingThreshold: zod.z.number().optional(),
298
301
  weakModelLocked: zod.z.boolean().optional(),
299
302
  autoApproveLocked: zod.z.boolean().optional(),
300
- updatedFilesGroupMode: zod.z.enum(["grouped", "flat"]).default("flat")
303
+ updatedFilesGroupMode: zod.z.enum(["grouped", "flat"]).default("flat"),
304
+ disabledRuleFiles: zod.z.array(zod.z.string()).default([]),
305
+ contextSidebarSectionsOrder: zod.z.array(zod.z.string()).default([]),
306
+ contextSidebarSectionsHidden: zod.z.array(zod.z.string()).default([])
301
307
  });
302
308
  var ToolApprovalState = /* @__PURE__ */ ((ToolApprovalState2) => {
303
309
  ToolApprovalState2["Always"] = "always";
@@ -481,19 +487,22 @@ const parseUsageReport = (model, report) => {
481
487
  };
482
488
  const normalizeBaseDir = (baseDir, os2 = process.platform === "win32" ? OS.Windows : process.platform === "darwin" ? OS.MacOS : OS.Linux) => {
483
489
  if (os2 === OS.Windows) {
484
- return baseDir.toLowerCase();
490
+ return baseDir.toLowerCase().replace(/\\+$/, "");
485
491
  } else {
486
492
  const wslPrefix = "\\\\wsl.localhost\\";
487
493
  if (baseDir.startsWith(wslPrefix)) {
488
494
  const thirdBackslashIndex = baseDir.indexOf("\\", wslPrefix.length);
489
495
  if (thirdBackslashIndex !== -1) {
490
496
  const actualPath = baseDir.substring(thirdBackslashIndex + 1);
491
- return "/" + actualPath.replace(/\\/g, "/");
497
+ return ("/" + actualPath.replace(/\\/g, "/")).replace(/\/+$/, "");
492
498
  }
493
499
  }
494
- return baseDir;
500
+ return baseDir.replace(/\/+$/, "");
495
501
  }
496
502
  };
503
+ const compareBaseDirs$1 = (baseDir1, baseDir2, os2) => {
504
+ return normalizeBaseDir(baseDir1, os2) === normalizeBaseDir(baseDir2, os2);
505
+ };
497
506
  const fileExists = async (fileName) => {
498
507
  return await fs.stat(fileName).catch(() => null) !== null;
499
508
  };
@@ -810,6 +819,7 @@ const POSTHOG_HOST = "https://eu.i.posthog.com";
810
819
  process.env.AIDER_DESK_HEADLESS === "true";
811
820
  const AUTH_USERNAME = process.env.AIDER_DESK_USERNAME;
812
821
  const AUTH_PASSWORD = process.env.AIDER_DESK_PASSWORD;
822
+ const CORS_ALLOWED_ORIGINS = process.env.AIDER_DESK_CORS_ALLOWED_ORIGINS;
813
823
  const PROBE_BINARY_PATH = path.join(
814
824
  RESOURCES_DIR,
815
825
  process.platform === "win32" ? "win" : process.platform === "darwin" ? "macos" : "linux",
@@ -1432,6 +1442,7 @@ const search = async (options) => {
1432
1442
  args.push(`${flag} ${String(value)}`);
1433
1443
  }
1434
1444
  }
1445
+ args.push("--");
1435
1446
  args.push(`"${options.query}"`);
1436
1447
  if (options.path) {
1437
1448
  args.push(`"${options.path}"`);
@@ -1462,6 +1473,7 @@ const AVAILABLE_PROVIDERS = [
1462
1473
  "litellm",
1463
1474
  "lmstudio",
1464
1475
  "minimax",
1476
+ "mistral",
1465
1477
  "ollama",
1466
1478
  "openai",
1467
1479
  "openai-compatible",
@@ -1506,24 +1518,28 @@ const isRequestyProvider = (provider) => provider.name === "requesty";
1506
1518
  const isOpenCodeProvider = (provider) => provider.name === "opencode";
1507
1519
  const isZaiPlanProvider = (provider) => provider.name === "zai-plan";
1508
1520
  const isMinimaxProvider = (provider) => provider.name === "minimax";
1521
+ const isMistralProvider = (provider) => provider.name === "mistral";
1509
1522
  const isSyntheticProvider = (provider) => provider.name === "synthetic";
1510
- const DEFAULT_MODEL_TEMPERATURE = 0;
1511
1523
  const DEFAULT_PROVIDER_MODELS = {
1512
1524
  "alibaba-plan": "qwen3-coder-plus",
1513
1525
  anthropic: "claude-sonnet-4-6",
1526
+ auggie: "gpt-5-4",
1527
+ bedrock: "global.anthropic.claude-sonnet-4-6",
1514
1528
  cerebras: "qwen-3-235b-a22b-instruct-2507",
1515
1529
  "claude-agent-sdk": "sonnet",
1516
- deepseek: "deepseek-chat",
1530
+ deepseek: "deepseek-v4-pro",
1517
1531
  gemini: "gemini-pro-latest",
1518
- "gemini-cli": "gemini-2.5-flash",
1532
+ "gemini-cli": "gemini-2.5-pro",
1519
1533
  groq: "moonshotai/kimi-k2-instruct-0905",
1534
+ "kimi-plan": "k2p6",
1520
1535
  openai: "gpt-5.4",
1521
1536
  openrouter: "anthropic/claude-sonnet-4.6",
1522
1537
  opencode: "claude-sonnet-4-6",
1523
1538
  requesty: "anthropic/claude-sonnet-4-6",
1524
1539
  synthetic: "hf:zai-org/GLM-4.7",
1525
- "zai-plan": "glm-5",
1526
- minimax: "MiniMax-M2"
1540
+ "zai-plan": "glm-5.1",
1541
+ minimax: "MiniMax-M2.7",
1542
+ mistral: "mistral-large-latest"
1527
1543
  };
1528
1544
  const DEFAULT_AIDER_MAIN_MODEL = `anthropic/${DEFAULT_PROVIDER_MODELS.anthropic}`;
1529
1545
  const DEFAULT_AGENT_PROFILE_ID = "default";
@@ -1835,7 +1851,8 @@ const getDefaultProviderParams = (providerName) => {
1835
1851
  case "deepseek":
1836
1852
  provider = {
1837
1853
  name: "deepseek",
1838
- apiKey: ""
1854
+ apiKey: "",
1855
+ thinkingEnabled: true
1839
1856
  };
1840
1857
  break;
1841
1858
  case "bedrock":
@@ -1920,6 +1937,12 @@ const getDefaultProviderParams = (providerName) => {
1920
1937
  apiKey: ""
1921
1938
  };
1922
1939
  break;
1940
+ case "mistral":
1941
+ provider = {
1942
+ name: "mistral",
1943
+ apiKey: ""
1944
+ };
1945
+ break;
1923
1946
  case "gemini-cli":
1924
1947
  provider = {
1925
1948
  name: "gemini-cli",
@@ -2181,7 +2204,8 @@ const readApiKeyFromConfFile = (filePath, envVarName) => {
2181
2204
  CEREBRAS_API_KEY: ["cerebras"],
2182
2205
  OPENCODE_API_KEY: ["opencode"],
2183
2206
  REQUESTY_API_KEY: ["requesty"],
2184
- SYNTHETIC_API_KEY: ["synthetic"]
2207
+ SYNTHETIC_API_KEY: ["synthetic"],
2208
+ MISTRAL_API_KEY: ["mistral"]
2185
2209
  };
2186
2210
  const providerNames = envVarToProviderName[envVarName] || [envVarName.replace(/_API_KEY$/, "").toLowerCase()];
2187
2211
  const apiKeys = Array.isArray(apiKeyValue) ? apiKeyValue : [apiKeyValue];
@@ -2347,7 +2371,10 @@ const getDefaultProjectSettings = (store, providerModels, baseDir, defaultAgentP
2347
2371
  currentMode: "agent",
2348
2372
  agentProfileId: defaultAgentProfileId,
2349
2373
  autoApproveLocked: false,
2350
- updatedFilesGroupMode: "flat"
2374
+ updatedFilesGroupMode: "flat",
2375
+ disabledRuleFiles: [],
2376
+ contextSidebarSectionsOrder: [],
2377
+ contextSidebarSectionsHidden: []
2351
2378
  };
2352
2379
  };
2353
2380
  const filenamify = filenamifyImport.default;
@@ -3034,19 +3061,16 @@ const scrapeWeb = async (url, timeout = 6e4, abortSignal, format = "markdown") =
3034
3061
  const scraper = new WebScraper();
3035
3062
  return await scraper.scrape(url, timeout, abortSignal, format);
3036
3063
  };
3037
- const fileLocks = /* @__PURE__ */ new Map();
3038
- const withFileLock = (filePath, operation) => {
3039
- logger.debug("Acquiring file lock:", { filePath });
3040
- const currentLock = fileLocks.get(filePath) || Promise.resolve();
3041
- const newLock = currentLock.then(operation, operation);
3042
- fileLocks.set(filePath, newLock);
3043
- newLock.finally(() => {
3044
- if (fileLocks.get(filePath) === newLock) {
3045
- logger.debug("Releasing file lock:", { filePath });
3046
- fileLocks.delete(filePath);
3047
- }
3048
- });
3049
- return newLock;
3064
+ const THINKING_RESPONSE_STAR_TAG = "---\n► **THINKING**\n";
3065
+ const ANSWER_RESPONSE_START_TAG = "---\n► **ANSWER**\n";
3066
+ const extractPromptContextFromToolResult = (toolResult) => {
3067
+ if (toolResult && typeof toolResult === "object" && "promptContext" in toolResult) {
3068
+ return toolResult.promptContext;
3069
+ }
3070
+ return void 0;
3071
+ };
3072
+ const findLastUserMessage = (messages) => {
3073
+ return [...messages].reverse().find((msg) => msg.role === MessageRole.User);
3050
3074
  };
3051
3075
  const expandTilde = (filePath) => {
3052
3076
  if (filePath.startsWith("~/") || filePath === "~") {
@@ -3054,11 +3078,25 @@ const expandTilde = (filePath) => {
3054
3078
  }
3055
3079
  return filePath;
3056
3080
  };
3057
- const readFileContent = async (absolutePath, withLines = false, lineOffset = 0, lineLimit = 1e3) => {
3081
+ const readFileContent = async (absolutePath, withLines = false, lineOffset = 0, lineLimit = 1e3, sizeLimit = 0.05 * lineLimit) => {
3058
3082
  const fileContentBuffer = await fs.readFile(absolutePath);
3059
3083
  if (istextorbinary.isBinary(absolutePath, fileContentBuffer)) {
3060
3084
  throw new Error("Binary files cannot be read.");
3061
3085
  }
3086
+ const fileSizeKB = fileContentBuffer.length / 1024;
3087
+ if (fileSizeKB > sizeLimit) {
3088
+ const truncatedBytes = fileContentBuffer.subarray(0, Math.floor(sizeLimit * 1024));
3089
+ const truncatedContent = truncatedBytes.toString("utf8");
3090
+ const truncatedLines = truncatedContent.split("\n");
3091
+ if (withLines) {
3092
+ return truncatedLines.map((line, index) => `${index + 1}|${line}`).join("\n") + `
3093
+
3094
+ File size limit (${sizeLimit.toFixed(1)} KB) exceeded. Use shell commands (e.g., head, tail, grep) to read specific parts.`;
3095
+ }
3096
+ return truncatedContent + `
3097
+
3098
+ File size limit (${sizeLimit.toFixed(1)} KB) exceeded. Use shell commands (e.g., head, tail, grep) to read specific parts.`;
3099
+ }
3062
3100
  const fileContent = fileContentBuffer.toString("utf8");
3063
3101
  const lines = fileContent.split("\n");
3064
3102
  const totalLines = lines.length;
@@ -3074,6 +3112,42 @@ const readFileContent = async (absolutePath, withLines = false, lineOffset = 0,
3074
3112
  }
3075
3113
  return limitedLines.join("\n");
3076
3114
  };
3115
+ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50) => {
3116
+ const lines = content.split("\n");
3117
+ const sizeBytes = Buffer.byteLength(content, "utf8");
3118
+ const sizeKB = sizeBytes / 1024;
3119
+ if (lines.length <= maxLines && sizeKB <= maxSizeKB) {
3120
+ return content;
3121
+ }
3122
+ const id = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
3123
+ const tmpFileName = `aider-desk-tool-result-${id}.txt`;
3124
+ const tmpFilePath = path.join(os.tmpdir(), tmpFileName);
3125
+ await fs.writeFile(tmpFilePath, content, "utf8");
3126
+ const previewLines = lines.slice(0, maxLines);
3127
+ const reasons = [];
3128
+ if (lines.length > maxLines) {
3129
+ reasons.push(`${lines.length} lines exceeded limit of ${maxLines}`);
3130
+ }
3131
+ if (sizeKB > maxSizeKB) {
3132
+ reasons.push(`${sizeKB.toFixed(1)} KB exceeded limit of ${maxSizeKB} KB`);
3133
+ }
3134
+ return previewLines.join("\n") + `
3135
+ ... Content truncated (${reasons.join(", ")}). Full content saved to ${tmpFilePath}.`;
3136
+ };
3137
+ const fileLocks = /* @__PURE__ */ new Map();
3138
+ const withFileLock = (filePath, operation) => {
3139
+ logger.debug("Acquiring file lock:", { filePath });
3140
+ const currentLock = fileLocks.get(filePath) || Promise.resolve();
3141
+ const newLock = currentLock.then(operation, operation);
3142
+ fileLocks.set(filePath, newLock);
3143
+ newLock.finally(() => {
3144
+ if (fileLocks.get(filePath) === newLock) {
3145
+ logger.debug("Releasing file lock:", { filePath });
3146
+ fileLocks.delete(filePath);
3147
+ }
3148
+ });
3149
+ return newLock;
3150
+ };
3077
3151
  const createPowerToolset = (task, profile, promptContext, abortSignal) => {
3078
3152
  const approvalManager = new ApprovalManager(task, profile);
3079
3153
  const fileEditTool = ai.tool({
@@ -3392,10 +3466,10 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3392
3466
  encoding: "utf8",
3393
3467
  signal: abortSignal
3394
3468
  });
3395
- const lines = fileContent.split("\n");
3469
+ const lines2 = fileContent.split("\n");
3396
3470
  const relativeFilePath = path.relative(task.getTaskDir(), absoluteFilePath);
3397
- for (let index = 0; index < lines.length; index++) {
3398
- const line = lines[index];
3471
+ for (let index = 0; index < lines2.length; index++) {
3472
+ const line = lines2[index];
3399
3473
  if (searchRegex.test(line)) {
3400
3474
  if (results.length >= maxResults) {
3401
3475
  break;
@@ -3407,8 +3481,8 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3407
3481
  };
3408
3482
  if (contextLines > 0) {
3409
3483
  const start = Math.max(0, index - contextLines);
3410
- const end = Math.min(lines.length - 1, index + contextLines);
3411
- matchResult.context = lines.slice(start, end + 1);
3484
+ const end = Math.min(lines2.length - 1, index + contextLines);
3485
+ matchResult.context = lines2.slice(start, end + 1);
3412
3486
  }
3413
3487
  results.push(matchResult);
3414
3488
  }
@@ -3417,7 +3491,40 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3417
3491
  if (results.length === 0) {
3418
3492
  return `No matches found for pattern '${searchTerm}' in files matching '${filePattern}'.`;
3419
3493
  }
3420
- return results;
3494
+ const grouped = {};
3495
+ for (const r of results) {
3496
+ if (!grouped[r.filePath]) {
3497
+ grouped[r.filePath] = [];
3498
+ }
3499
+ grouped[r.filePath].push(r);
3500
+ }
3501
+ const lines = [];
3502
+ lines.push(`## Grep Results: \`${searchTerm}\` in \`${filePattern}\` (${results.length} matches)`);
3503
+ lines.push("");
3504
+ for (const [filePath, matches] of Object.entries(grouped)) {
3505
+ lines.push(`### ${filePath} (${matches.length} ${matches.length === 1 ? "match" : "matches"})`);
3506
+ for (const match of matches) {
3507
+ const escapedContent = match.lineContent.replace(/`/g, "\\`");
3508
+ lines.push(`- **L${match.lineNumber}:** \`${escapedContent}\``);
3509
+ if (match.context && match.context.length > 0) {
3510
+ lines.push(" ```");
3511
+ for (const ctxLine of match.context) {
3512
+ lines.push(` ${ctxLine}`);
3513
+ }
3514
+ lines.push(" ```");
3515
+ }
3516
+ }
3517
+ lines.push("");
3518
+ }
3519
+ const notices = [];
3520
+ if (results.length >= maxResults) {
3521
+ notices.push(`${maxResults} matches limit reached. Use maxResults=${maxResults * 2} for more, or refine pattern`);
3522
+ }
3523
+ if (notices.length > 0) {
3524
+ lines.push("---");
3525
+ lines.push(`[${notices.join(". ")}]`);
3526
+ }
3527
+ return lines.join("\n");
3421
3528
  } catch (error) {
3422
3529
  if (isAbortError(error)) {
3423
3530
  return "Operation was cancelled by user.";
@@ -3491,24 +3598,26 @@ Timeout: ${timeout}ms`;
3491
3598
  abortSignal?.removeEventListener("abort", abortListener);
3492
3599
  }
3493
3600
  };
3494
- const resolveWithResult = () => {
3601
+ const resolveWithResult = async () => {
3495
3602
  if (isResolved) {
3496
3603
  return;
3497
3604
  }
3498
3605
  isResolved = true;
3499
3606
  cleanup();
3500
- resolve({ stdout, stderr, exitCode });
3607
+ const truncatedStdout = await truncateToolResult(stdout);
3608
+ const truncatedStderr = await truncateToolResult(stderr);
3609
+ resolve({ stdout: truncatedStdout, stderr: truncatedStderr, exitCode });
3501
3610
  };
3502
3611
  abortListener = () => {
3503
3612
  if (isResolved) {
3504
3613
  return;
3505
3614
  }
3506
3615
  if (childProcess?.pid) {
3507
- treeKill(childProcess.pid, "SIGTERM");
3616
+ treeKill(childProcess.pid, "SIGKILL");
3508
3617
  }
3509
3618
  stderr = "Operation was cancelled by user.";
3510
3619
  exitCode = 130;
3511
- resolveWithResult();
3620
+ void resolveWithResult();
3512
3621
  };
3513
3622
  abortSignal?.addEventListener("abort", abortListener);
3514
3623
  try {
@@ -3525,13 +3634,16 @@ Timeout: ${timeout}ms`;
3525
3634
  return;
3526
3635
  }
3527
3636
  if (childProcess?.pid) {
3528
- treeKill(childProcess.pid, "SIGTERM");
3637
+ treeKill(childProcess.pid, "SIGKILL");
3529
3638
  }
3530
3639
  stderr = `Error: Command timed out after ${timeout}ms. Consider increasing the timeout parameter.`;
3531
3640
  exitCode = 124;
3532
- resolveWithResult();
3641
+ void resolveWithResult();
3533
3642
  }, timeout);
3534
3643
  childProcess.stdout?.on("data", (data) => {
3644
+ if (isResolved) {
3645
+ return;
3646
+ }
3535
3647
  const chunk = data.toString("utf-8");
3536
3648
  stdout += chunk;
3537
3649
  task.addToolMessage(
@@ -3548,6 +3660,9 @@ Timeout: ${timeout}ms`;
3548
3660
  );
3549
3661
  });
3550
3662
  childProcess.stderr?.on("data", (data) => {
3663
+ if (isResolved) {
3664
+ return;
3665
+ }
3551
3666
  const chunk = data.toString("utf-8");
3552
3667
  stderr += chunk;
3553
3668
  task.addToolMessage(
@@ -3567,7 +3682,7 @@ Timeout: ${timeout}ms`;
3567
3682
  if (!isResolved) {
3568
3683
  stderr = error.message;
3569
3684
  exitCode = 1;
3570
- resolveWithResult();
3685
+ void resolveWithResult();
3571
3686
  }
3572
3687
  });
3573
3688
  childProcess.on("exit", (code, signal) => {
@@ -3579,14 +3694,14 @@ Timeout: ${timeout}ms`;
3579
3694
  } else {
3580
3695
  exitCode = 1;
3581
3696
  }
3582
- resolveWithResult();
3697
+ void resolveWithResult();
3583
3698
  }
3584
3699
  });
3585
3700
  } catch (error) {
3586
3701
  if (!isResolved) {
3587
3702
  stderr = error instanceof Error ? error.message : String(error);
3588
3703
  exitCode = 1;
3589
- resolveWithResult();
3704
+ void resolveWithResult();
3590
3705
  }
3591
3706
  }
3592
3707
  });
@@ -4059,7 +4174,8 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
4059
4174
  const newTask = await task.getProject().createNewTask({
4060
4175
  parentId: parentTaskId || null,
4061
4176
  name: name || "",
4062
- autoApprove
4177
+ autoApprove,
4178
+ workingMode: worktree ? "worktree" : "local"
4063
4179
  });
4064
4180
  const updates = {};
4065
4181
  if (agentProfileId) {
@@ -4071,9 +4187,6 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
4071
4187
  updates.model = modelParts.join("/");
4072
4188
  updates.mainModel = modelId;
4073
4189
  }
4074
- if (worktree) {
4075
- updates.workingMode = "worktree";
4076
- }
4077
4190
  const taskInstance = task.getProject().getTask(newTask.id);
4078
4191
  if (!taskInstance) {
4079
4192
  throw new Error(`Failed to get task instance for newly created task ${newTask.id}`);
@@ -4685,64 +4798,6 @@ New content: "${content}"`;
4685
4798
  }
4686
4799
  return filteredTools;
4687
4800
  };
4688
- const SKILLS_DIR_NAME = "skills";
4689
- const SKILL_MARKDOWN_FILE = "SKILL.md";
4690
- const parseSkillFrontMatter = (markdown) => {
4691
- const parsed = yamlFrontMatter.loadFront(markdown);
4692
- const name = typeof parsed.name === "string" ? parsed.name : void 0;
4693
- const description = typeof parsed.description === "string" ? parsed.description : void 0;
4694
- if (!name || !description) {
4695
- return null;
4696
- }
4697
- return { name, description };
4698
- };
4699
- const safeReadDir = async (dirPath) => {
4700
- try {
4701
- return await fs.readdir(dirPath);
4702
- } catch {
4703
- return [];
4704
- }
4705
- };
4706
- const safeStat = async (filePath) => {
4707
- try {
4708
- return await fs.stat(filePath);
4709
- } catch {
4710
- return null;
4711
- }
4712
- };
4713
- const loadSkillsFromDir = async (skillsRootDir, location) => {
4714
- const entries = await safeReadDir(skillsRootDir);
4715
- const skills = [];
4716
- for (const entry of entries) {
4717
- const dirPath = path.join(skillsRootDir, entry);
4718
- const stat = await safeStat(dirPath);
4719
- if (!stat?.isDirectory()) {
4720
- continue;
4721
- }
4722
- const skillMdPath = path.join(dirPath, SKILL_MARKDOWN_FILE);
4723
- const skillMdStat = await safeStat(skillMdPath);
4724
- if (!skillMdStat?.isFile()) {
4725
- continue;
4726
- }
4727
- let markdown;
4728
- try {
4729
- markdown = await fs.readFile(skillMdPath, "utf8");
4730
- } catch {
4731
- continue;
4732
- }
4733
- const parsed = parseSkillFrontMatter(markdown);
4734
- if (!parsed) {
4735
- continue;
4736
- }
4737
- skills.push({
4738
- name: parsed.name,
4739
- description: parsed.description,
4740
- location,
4741
- dirPath
4742
- });
4743
- }
4744
- return skills;
4745
- };
4746
4801
  const getActivateSkillDescription = (skills) => {
4747
4802
  const instructions = 'Execute a skill within the main conversation\n\n<skills_instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to invoke:\n- Use this tool with the skill name only (no arguments)\n- Example: {"skill": "pdf"}\n\nImportant:\n- When a skill is relevant, you must invoke this tool IMMEDIATELY as your first action\n- NEVER just announce or mention a skill in your text response without actually calling this tool\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n</skills_instructions>';
4748
4803
  const availableSkills = skills.map((skill) => {
@@ -4766,15 +4821,10 @@ ${availableSkills}
4766
4821
  };
4767
4822
  const createSkillsToolset = async (task, profile, promptContext) => {
4768
4823
  const approvalManager = new ApprovalManager(task, profile);
4824
+ const skillManager = task.getSkillManager();
4769
4825
  const generateActivateSkillDescription = async () => {
4770
- const globalSkillsDir = path.join(os.homedir(), AIDER_DESK_DIR, SKILLS_DIR_NAME);
4771
- const projectSkillsDir = path.join(task.getProjectDir(), AIDER_DESK_DIR, SKILLS_DIR_NAME);
4772
- const [globalSkills, projectSkills, builtinSkills] = await Promise.all([
4773
- loadSkillsFromDir(globalSkillsDir, "global"),
4774
- loadSkillsFromDir(projectSkillsDir, "project"),
4775
- loadSkillsFromDir(AIDER_DESK_BUILTIN_SKILLS_DIR, "builtin")
4776
- ]);
4777
- return getActivateSkillDescription([...projectSkills, ...globalSkills, ...builtinSkills]);
4826
+ const skills = await skillManager.loadAllSkills();
4827
+ return getActivateSkillDescription(skills);
4778
4828
  };
4779
4829
  const activateSkillTool = ai.tool({
4780
4830
  description: await generateActivateSkillDescription(),
@@ -4792,30 +4842,21 @@ const createSkillsToolset = async (task, profile, promptContext) => {
4792
4842
  if (!isApproved) {
4793
4843
  return `Activating skill denied by user. Reason: ${userInput}`;
4794
4844
  }
4795
- const globalSkillsDir = path.join(os.homedir(), AIDER_DESK_DIR, SKILLS_DIR_NAME);
4796
- const projectSkillsDir = path.join(task.getProjectDir(), AIDER_DESK_DIR, SKILLS_DIR_NAME);
4797
- const [globalSkills, projectSkills, builtinSkills] = await Promise.all([
4798
- loadSkillsFromDir(globalSkillsDir, "global"),
4799
- loadSkillsFromDir(projectSkillsDir, "project"),
4800
- loadSkillsFromDir(AIDER_DESK_BUILTIN_SKILLS_DIR, "builtin")
4801
- ]);
4802
- const allSkills = [...projectSkills, ...globalSkills, ...builtinSkills];
4845
+ const allSkills = await skillManager.loadAllSkills();
4803
4846
  const requested = allSkills.find((s) => s.name === skill);
4804
4847
  if (!requested) {
4805
4848
  const available = allSkills.map((s) => s.name).join(", ");
4806
4849
  return `Skill '${skill}' not found. Available skills: ${available || "(none)"}.`;
4807
4850
  }
4808
- const skillMdPath = path.join(requested.dirPath, SKILL_MARKDOWN_FILE);
4809
- let content;
4810
- try {
4811
- content = await fs.readFile(skillMdPath, "utf8");
4812
- } catch {
4813
- return `Failed to read skill content from ${skillMdPath}.`;
4851
+ const content = await skillManager.getSkillContent(skill);
4852
+ if (!content) {
4853
+ return `Skill '${requested.name}' has no content or dirPath.`;
4814
4854
  }
4855
+ const dirInfo = requested.dirPath ? `
4856
+ Skill directory is ${requested.dirPath} - use it as parent directory for relative paths mentioned in the skill description.` : "";
4815
4857
  return `${content}
4816
4858
 
4817
- Skill '${requested.name}' activated.
4818
- Skill directory is ${requested.dirPath} - use it as parent directory for relative paths mentioned in the skill description.`;
4859
+ Skill '${requested.name}' activated.${dirInfo}`;
4819
4860
  }
4820
4861
  });
4821
4862
  const allTools = {
@@ -5252,17 +5293,6 @@ class McpManager {
5252
5293
  }
5253
5294
  }
5254
5295
  }
5255
- const THINKING_RESPONSE_STAR_TAG = "---\n► **THINKING**\n";
5256
- const ANSWER_RESPONSE_START_TAG = "---\n► **ANSWER**\n";
5257
- const extractPromptContextFromToolResult = (toolResult) => {
5258
- if (toolResult && typeof toolResult === "object" && "promptContext" in toolResult) {
5259
- return toolResult.promptContext;
5260
- }
5261
- return void 0;
5262
- };
5263
- const findLastUserMessage = (messages) => {
5264
- return [...messages].reverse().find((msg) => msg.role === MessageRole.User);
5265
- };
5266
5296
  const extractReasoningMiddleware = function extractReasoningMiddleware2({
5267
5297
  tagName,
5268
5298
  separator = "\n"
@@ -5905,16 +5935,6 @@ const removeDuplicateToolCalls = (messages) => {
5905
5935
  }
5906
5936
  return newMessages;
5907
5937
  };
5908
- undici.setGlobalDispatcher(
5909
- new undici.Agent({
5910
- headersTimeout: 30 * 60 * 1e3,
5911
- // 30 minutes
5912
- bodyTimeout: 30 * 60 * 1e3,
5913
- // 30 minutes
5914
- connectTimeout: 30 * 1e3
5915
- // 30 seconds
5916
- })
5917
- );
5918
5938
  const MAX_RETRIES = 3;
5919
5939
  class Agent {
5920
5940
  constructor(store, agentProfileManager, mcpManager, modelManager, telemetryManager, memoryManager, promptsManager, extensionManager) {
@@ -6242,6 +6262,9 @@ ${fileList}`
6242
6262
  options.abortSignal = abortSignal;
6243
6263
  }
6244
6264
  const result = await toolDef.execute(effectiveInput, options);
6265
+ if (options.abortSignal?.aborted) {
6266
+ return result;
6267
+ }
6245
6268
  const toolFinishedExtensionResult = await this.extensionManager.dispatchEvent(
6246
6269
  "onToolFinished",
6247
6270
  { toolName, input: effectiveInput, output: result },
@@ -6291,6 +6314,14 @@ ${fileList}`
6291
6314
  }
6292
6315
  );
6293
6316
  logger.debug(`Tool ${toolDef.name} returned response`, { response });
6317
+ if (response && typeof response === "object" && "content" in response && Array.isArray(response.content)) {
6318
+ for (let i = 0; i < response.content.length; i++) {
6319
+ const part = response.content[i];
6320
+ if (part && typeof part === "object" && part.type === "text" && typeof part.text === "string") {
6321
+ part.text = await truncateToolResult(part.text);
6322
+ }
6323
+ }
6324
+ }
6294
6325
  this.lastToolCallTime = Date.now();
6295
6326
  return response;
6296
6327
  } catch (error) {
@@ -6471,7 +6502,7 @@ ${fileList}`
6471
6502
  this.abortControllers.set(controllerId, newController);
6472
6503
  }
6473
6504
  const effectiveAbortSignal = abortSignal || (controllerId ? this.abortControllers.get(controllerId)?.signal : void 0);
6474
- const cacheControl = this.modelManager.getCacheControl(profile, provider.provider);
6505
+ const cacheControl = this.modelManager.getCacheControl(provider, modelName);
6475
6506
  const providerOptions = this.modelManager.getProviderOptions(provider, modelName);
6476
6507
  const providerParameters = this.modelManager.getProviderParameters(provider, modelName);
6477
6508
  const firstUserMessage = contextMessages.length > 0 ? contextMessages[0] : null;
@@ -6727,6 +6758,9 @@ ${fileList}`
6727
6758
  responseMessageIndex = 0;
6728
6759
  hasReasoning = false;
6729
6760
  streamingMessageIds.clear();
6761
+ if (responseMessages.length > 0) {
6762
+ retryCount = 0;
6763
+ }
6730
6764
  };
6731
6765
  const extensionStepStartedResult = await this.extensionManager.dispatchEvent(
6732
6766
  "onAgentStepStarted",
@@ -7171,6 +7205,7 @@ ${fileList}`
7171
7205
  }
7172
7206
  const settings = this.store.getSettings();
7173
7207
  const model = await this.modelManager.createLlm(provider, modelName, settings, projectDir, void 0, systemPrompt, void 0);
7208
+ const cacheControl = this.modelManager.getCacheControl(provider, modelName);
7174
7209
  const providerOptions = this.modelManager.getProviderOptions(provider, modelName);
7175
7210
  const providerParameters = this.modelManager.getProviderParameters(provider, modelName);
7176
7211
  const controllerId = uuid.v4();
@@ -7195,7 +7230,7 @@ ${fileList}`
7195
7230
  const result = await ai.generateText({
7196
7231
  model,
7197
7232
  system: systemPrompt,
7198
- messages: await optimizeMessages(messages),
7233
+ messages: await optimizeMessages(messages, cacheControl),
7199
7234
  abortSignal: effectiveAbortSignal,
7200
7235
  providerOptions,
7201
7236
  ...providerParameters
@@ -7226,7 +7261,7 @@ ${fileList}`
7226
7261
  const messages = await this.prepareMessages(task, profile, await task.getContextMessages(), await task.getContextFiles());
7227
7262
  const toolSet = await this.getAvailableTools(task, "agent", profile, provider, profile.model);
7228
7263
  const systemPrompt = await this.promptsManager.getSystemPrompt(this.store.getSettings(), task, profile);
7229
- const cacheControl = this.modelManager.getCacheControl(profile, provider.provider);
7264
+ const cacheControl = this.modelManager.getCacheControl(provider, profile.model);
7230
7265
  const lastUserIndex = messages.map((m) => m.role).lastIndexOf("user");
7231
7266
  const userRequestMessageIndex = lastUserIndex >= 0 ? lastUserIndex : 0;
7232
7267
  const optimizedMessages = await optimizeMessages(
@@ -8460,9 +8495,10 @@ const UpdateOpenProjectsOrderSchema = zod.z.object({
8460
8495
  const LoadInputHistorySchema = zod.z.object({
8461
8496
  projectDir: zod.z.string().min(1, "Project directory is required")
8462
8497
  });
8463
- const RedoLastUserPromptSchema = zod.z.object({
8498
+ const RedoUserPromptSchema = zod.z.object({
8464
8499
  projectDir: zod.z.string().min(1, "Project directory is required"),
8465
8500
  taskId: zod.z.string().min(1, "Task id is required"),
8501
+ messageId: zod.z.string().min(1, "Message id is required"),
8466
8502
  mode: zod.z.string().min(1, "Mode is required"),
8467
8503
  updatedPrompt: zod.z.string().optional()
8468
8504
  });
@@ -8571,12 +8607,15 @@ const HandoffConversationSchema = zod.z.object({
8571
8607
  taskId: zod.z.string().min(1, "Task id is required"),
8572
8608
  focus: zod.z.string().optional()
8573
8609
  });
8574
- const RunCodeInlineRequestSchema = zod.z.object({
8575
- projectDir: zod.z.string().min(1, "Project directory is required"),
8576
- taskId: zod.z.string().min(1, "Task id is required"),
8610
+ const ChangeRequestItemSchema = zod.z.object({
8577
8611
  filename: zod.z.string().min(1, "Filename is required"),
8578
8612
  lineNumber: zod.z.number().int().min(1, "Line number is required"),
8579
- userComment: zod.z.string().min(1, "User comment is required"),
8613
+ userComment: zod.z.string().min(1, "User comment is required")
8614
+ });
8615
+ const RunCodeChangeRequestsSchema = zod.z.object({
8616
+ projectDir: zod.z.string().min(1, "Project directory is required"),
8617
+ taskId: zod.z.string().min(1, "Task id is required"),
8618
+ requests: zod.z.array(ChangeRequestItemSchema).min(1, "At least one request is required"),
8580
8619
  createNewTask: zod.z.boolean().optional()
8581
8620
  });
8582
8621
  const ScrapeWebSchema = zod.z.object({
@@ -8592,6 +8631,11 @@ const MergeWorktreeToMainSchema = zod.z.object({
8592
8631
  targetBranch: zod.z.string().optional(),
8593
8632
  commitMessage: zod.z.string().optional()
8594
8633
  });
8634
+ const MergeAndSwitchToLocalSchema = zod.z.object({
8635
+ projectDir: zod.z.string().min(1, "Project directory is required"),
8636
+ taskId: zod.z.string().min(1, "Task id is required"),
8637
+ targetBranch: zod.z.string().optional()
8638
+ });
8595
8639
  const ApplyUncommittedChangesSchema = zod.z.object({
8596
8640
  projectDir: zod.z.string().min(1, "Project directory is required"),
8597
8641
  taskId: zod.z.string().min(1, "Task id is required"),
@@ -8608,6 +8652,7 @@ const RestoreFileSchema = zod.z.object({
8608
8652
  });
8609
8653
  const ReadFileSchema = zod.z.object({
8610
8654
  projectDir: zod.z.string().min(1, "Project directory is required"),
8655
+ taskId: zod.z.string().min(1, "Task id is required"),
8611
8656
  filePath: zod.z.string().min(1, "File path is required")
8612
8657
  });
8613
8658
  const GenerateCommitMessageSchema = zod.z.object({
@@ -8645,6 +8690,11 @@ const ResolveWorktreeConflictsWithAgentSchema = zod.z.object({
8645
8690
  projectDir: zod.z.string().min(1, "Project directory is required"),
8646
8691
  taskId: zod.z.string().min(1, "Task id is required")
8647
8692
  });
8693
+ const RenameWorktreeBranchSchema = zod.z.object({
8694
+ projectDir: zod.z.string().min(1, "Project directory is required"),
8695
+ taskId: zod.z.string().min(1, "Task id is required"),
8696
+ newBranchName: zod.z.string().min(1, "New branch name is required")
8697
+ });
8648
8698
  class ProjectApi extends BaseApi {
8649
8699
  constructor(eventsHandler) {
8650
8700
  super();
@@ -8673,13 +8723,13 @@ class ProjectApi extends BaseApi {
8673
8723
  router.post(
8674
8724
  "/project/redo-prompt",
8675
8725
  this.handleRequest(async (req, res) => {
8676
- const parsed = this.validateRequest(RedoLastUserPromptSchema, req.body, res);
8726
+ const parsed = this.validateRequest(RedoUserPromptSchema, req.body, res);
8677
8727
  if (!parsed) {
8678
8728
  return;
8679
8729
  }
8680
- const { projectDir, taskId, mode, updatedPrompt } = parsed;
8681
- await this.eventsHandler.redoLastUserPrompt(projectDir, taskId, mode, updatedPrompt);
8682
- res.status(200).json({ message: "Redo last user prompt initiated" });
8730
+ const { projectDir, taskId, messageId, mode, updatedPrompt } = parsed;
8731
+ await this.eventsHandler.redoUserPrompt(projectDir, taskId, messageId, mode, updatedPrompt);
8732
+ res.status(200).json({ message: "Redo user prompt initiated" });
8683
8733
  })
8684
8734
  );
8685
8735
  router.post(
@@ -8976,15 +9026,15 @@ class ProjectApi extends BaseApi {
8976
9026
  })
8977
9027
  );
8978
9028
  router.post(
8979
- "/project/run-code-inline-request",
9029
+ "/project/run-code-change-requests",
8980
9030
  this.handleRequest(async (req, res) => {
8981
- const parsed = this.validateRequest(RunCodeInlineRequestSchema, req.body, res);
9031
+ const parsed = this.validateRequest(RunCodeChangeRequestsSchema, req.body, res);
8982
9032
  if (!parsed) {
8983
9033
  return;
8984
9034
  }
8985
- const { projectDir, taskId, filename, lineNumber, userComment, createNewTask } = parsed;
8986
- await this.eventsHandler.runCodeInlineRequest(projectDir, taskId, filename, lineNumber, userComment, createNewTask);
8987
- res.status(200).json({ message: "Code inline request initiated" });
9035
+ const { projectDir, taskId, requests, createNewTask } = parsed;
9036
+ await this.eventsHandler.runCodeChangeRequests(projectDir, taskId, requests, createNewTask);
9037
+ res.status(200).json({ message: "Code change requests initiated" });
8988
9038
  })
8989
9039
  );
8990
9040
  router.post(
@@ -9011,6 +9061,18 @@ class ProjectApi extends BaseApi {
9011
9061
  res.status(200).json({ message: "Worktree merged" });
9012
9062
  })
9013
9063
  );
9064
+ router.post(
9065
+ "/project/worktree/merge-and-switch-to-local",
9066
+ this.handleRequest(async (req, res) => {
9067
+ const parsed = this.validateRequest(MergeAndSwitchToLocalSchema, req.body, res);
9068
+ if (!parsed) {
9069
+ return;
9070
+ }
9071
+ const { projectDir, taskId, targetBranch } = parsed;
9072
+ await this.eventsHandler.mergeAndSwitchToLocal(projectDir, taskId, targetBranch);
9073
+ res.status(200).json({ message: "Worktree merged and switched to local" });
9074
+ })
9075
+ );
9014
9076
  router.post(
9015
9077
  "/project/worktree/apply-uncommitted",
9016
9078
  this.handleRequest(async (req, res) => {
@@ -9054,8 +9116,8 @@ class ProjectApi extends BaseApi {
9054
9116
  if (!parsed) {
9055
9117
  return;
9056
9118
  }
9057
- const { projectDir, filePath } = parsed;
9058
- const content = await this.eventsHandler.readFile(projectDir, filePath);
9119
+ const { projectDir, taskId, filePath } = parsed;
9120
+ const content = await this.eventsHandler.readFile(projectDir, taskId, filePath);
9059
9121
  res.status(200).json({ content });
9060
9122
  })
9061
9123
  );
@@ -9155,6 +9217,18 @@ class ProjectApi extends BaseApi {
9155
9217
  res.status(200).json({ message: "Conflicts resolved" });
9156
9218
  })
9157
9219
  );
9220
+ router.post(
9221
+ "/project/worktree/rename-branch",
9222
+ this.handleRequest(async (req, res) => {
9223
+ const parsed = this.validateRequest(RenameWorktreeBranchSchema, req.body, res);
9224
+ if (!parsed) {
9225
+ return;
9226
+ }
9227
+ const { projectDir, taskId, newBranchName } = parsed;
9228
+ await this.eventsHandler.renameWorktreeBranch(projectDir, taskId, newBranchName);
9229
+ res.status(200).json({ message: "Branch renamed" });
9230
+ })
9231
+ );
9158
9232
  router.post(
9159
9233
  "/project/update-order",
9160
9234
  this.handleRequest(async (req, res) => {
@@ -9488,9 +9562,10 @@ const GetSystemLogsSchema = zod.z.object({
9488
9562
  levels: zod.z.array(zod.z.string()).optional()
9489
9563
  });
9490
9564
  class SystemApi extends BaseApi {
9491
- constructor(eventsHandler) {
9565
+ constructor(eventsHandler, pythonInstaller) {
9492
9566
  super();
9493
9567
  this.eventsHandler = eventsHandler;
9568
+ this.pythonInstaller = pythonInstaller;
9494
9569
  }
9495
9570
  registerRoutes(router) {
9496
9571
  router.get(
@@ -9524,6 +9599,13 @@ class SystemApi extends BaseApi {
9524
9599
  res.status(200).json({ success: true });
9525
9600
  })
9526
9601
  );
9602
+ router.get(
9603
+ "/system/aider-connector-status",
9604
+ this.handleRequest(async (_req, res) => {
9605
+ const status = this.pythonInstaller.getStatus();
9606
+ res.status(200).json(status);
9607
+ })
9608
+ );
9527
9609
  }
9528
9610
  }
9529
9611
  const GetTodosSchema = zod.z.object({
@@ -10100,13 +10182,88 @@ class ExtensionsApi extends BaseApi {
10100
10182
  );
10101
10183
  }
10102
10184
  }
10185
+ const GetSkillsSchema = zod.z.object({
10186
+ projectDir: zod.z.string().min(1, "Project directory is required"),
10187
+ taskId: zod.z.string().min(1, "Task ID is required")
10188
+ });
10189
+ const ActivateSkillSchema = zod.z.object({
10190
+ projectDir: zod.z.string().min(1, "Project directory is required"),
10191
+ taskId: zod.z.string().min(1, "Task ID is required"),
10192
+ skillName: zod.z.string().min(1, "Skill name is required")
10193
+ });
10194
+ class SkillsApi extends BaseApi {
10195
+ constructor(eventsHandler) {
10196
+ super();
10197
+ this.eventsHandler = eventsHandler;
10198
+ }
10199
+ registerRoutes(router) {
10200
+ router.get(
10201
+ "/skills",
10202
+ this.handleRequest(async (req, res) => {
10203
+ const parsed = this.validateRequest(GetSkillsSchema, req.query, res);
10204
+ if (!parsed) {
10205
+ return;
10206
+ }
10207
+ const { projectDir, taskId } = parsed;
10208
+ const skills = await this.eventsHandler.getSkills(projectDir, taskId);
10209
+ res.status(200).json(skills);
10210
+ })
10211
+ );
10212
+ router.post(
10213
+ "/skills/activate",
10214
+ this.handleRequest(async (req, res) => {
10215
+ const parsed = this.validateRequest(ActivateSkillSchema, req.body, res);
10216
+ if (!parsed) {
10217
+ return;
10218
+ }
10219
+ const { projectDir, taskId, skillName } = parsed;
10220
+ await this.eventsHandler.activateSkill(projectDir, taskId, skillName);
10221
+ res.status(200).json({ success: true });
10222
+ })
10223
+ );
10224
+ router.post(
10225
+ "/skills/deactivate",
10226
+ this.handleRequest(async (req, res) => {
10227
+ const parsed = this.validateRequest(ActivateSkillSchema, req.body, res);
10228
+ if (!parsed) {
10229
+ return;
10230
+ }
10231
+ const { projectDir, taskId, skillName } = parsed;
10232
+ await this.eventsHandler.deactivateSkill(projectDir, taskId, skillName);
10233
+ res.status(200).json({ success: true });
10234
+ })
10235
+ );
10236
+ }
10237
+ }
10238
+ const createCorsOriginValidator = (store) => (origin, callback) => {
10239
+ if (CORS_ALLOWED_ORIGINS) {
10240
+ const origins = CORS_ALLOWED_ORIGINS.split(",").map((o) => o.trim()).filter(Boolean);
10241
+ if (!origin || origins.includes(origin)) {
10242
+ callback(null, true);
10243
+ } else {
10244
+ callback(null, false);
10245
+ }
10246
+ return;
10247
+ }
10248
+ const corsSettings = store.getSettings().server.cors;
10249
+ if (!corsSettings.enabled || corsSettings.origins.length === 0) {
10250
+ callback(null, false);
10251
+ return;
10252
+ }
10253
+ if (!origin || corsSettings.origins.includes(origin)) {
10254
+ callback(null, true);
10255
+ } else {
10256
+ callback(null, false);
10257
+ }
10258
+ };
10103
10259
  const REQUEST_TIMEOUT_MS = 5 * 60 * 1e3;
10104
10260
  class ServerController {
10105
- constructor(server, projectManager, eventsHandler, store) {
10261
+ constructor(server, projectManager, eventsHandler, store, pythonInstaller) {
10106
10262
  this.server = server;
10107
10263
  this.projectManager = projectManager;
10108
10264
  this.eventsHandler = eventsHandler;
10109
10265
  this.store = store;
10266
+ this.pythonInstaller = pythonInstaller;
10110
10267
  this.init();
10111
10268
  }
10112
10269
  app = express();
@@ -10162,7 +10319,7 @@ class ServerController {
10162
10319
  new ProjectApi(this.eventsHandler).registerRoutes(apiRouter);
10163
10320
  new CommandsApi(this.eventsHandler).registerRoutes(apiRouter);
10164
10321
  new UsageApi(this.eventsHandler).registerRoutes(apiRouter);
10165
- new SystemApi(this.eventsHandler).registerRoutes(apiRouter);
10322
+ new SystemApi(this.eventsHandler, this.pythonInstaller).registerRoutes(apiRouter);
10166
10323
  new TodoApi(this.eventsHandler).registerRoutes(apiRouter);
10167
10324
  new McpApi(this.eventsHandler).registerRoutes(apiRouter);
10168
10325
  new ProvidersApi(this.eventsHandler).registerRoutes(apiRouter);
@@ -10171,11 +10328,15 @@ class ServerController {
10171
10328
  new VoiceApi(this.eventsHandler).registerRoutes(apiRouter);
10172
10329
  new TerminalApi(this.eventsHandler).registerRoutes(apiRouter);
10173
10330
  new ExtensionsApi(this.eventsHandler).registerRoutes(apiRouter);
10331
+ new SkillsApi(this.eventsHandler).registerRoutes(apiRouter);
10174
10332
  this.app.use("/api", apiRouter);
10175
10333
  }
10334
+ setupCors() {
10335
+ this.app.use(cors({ origin: createCorsOriginValidator(this.store) }));
10336
+ }
10176
10337
  init() {
10177
10338
  this.app.use(express.json({ limit: "50mb" }));
10178
- this.app.use(cors());
10339
+ this.setupCors();
10179
10340
  this.app.use(this.serverGuardMiddleware.bind(this));
10180
10341
  this.app.use(this.timeoutMiddleware.bind(this));
10181
10342
  this.app.use(this.basicAuthMiddleware.bind(this));
@@ -10442,9 +10603,10 @@ const isUnsubscribeEventsMessage = (message) => {
10442
10603
  return message.action === "unsubscribe-events";
10443
10604
  };
10444
10605
  class ConnectorManager {
10445
- constructor(httpServer, projectManager, eventManager) {
10606
+ constructor(httpServer, projectManager, eventManager, store) {
10446
10607
  this.projectManager = projectManager;
10447
10608
  this.eventManager = eventManager;
10609
+ this.store = store;
10448
10610
  this.init(httpServer);
10449
10611
  }
10450
10612
  io = null;
@@ -10452,7 +10614,7 @@ class ConnectorManager {
10452
10614
  init(httpServer) {
10453
10615
  this.io = new socket_io.Server(httpServer, {
10454
10616
  cors: {
10455
- origin: "*",
10617
+ origin: createCorsOriginValidator(this.store),
10456
10618
  methods: ["GET", "POST"]
10457
10619
  },
10458
10620
  pingTimeout: 6e5,
@@ -11286,6 +11448,15 @@ class ContextManager {
11286
11448
  }
11287
11449
  return this.removeByToolCallId(messageId);
11288
11450
  }
11451
+ removeMessagesByIds(ids) {
11452
+ for (const id of ids) {
11453
+ const index = this.messages.findIndex((msg) => msg.id === id);
11454
+ if (index !== -1) {
11455
+ this.messages.splice(index, 1);
11456
+ }
11457
+ }
11458
+ this.autosave();
11459
+ }
11289
11460
  removeMessageByIndex(index, messageId) {
11290
11461
  const removedIds = [];
11291
11462
  removedIds.push(messageId);
@@ -11415,16 +11586,17 @@ class ContextManager {
11415
11586
  }
11416
11587
  this.autosave();
11417
11588
  }
11418
- removeMessagesUpToLastUserMessage() {
11419
- const lastUserMessageIndex = this.messages.findLastIndex((msg) => msg.role === MessageRole.User);
11420
- if (lastUserMessageIndex === -1) {
11421
- logger.warn("No user message found to remove up to.", {
11422
- taskId: this.taskId
11589
+ removeMessagesUpToUserMessage(messageId) {
11590
+ const userMessageIndex = this.messages.findIndex((msg) => msg.id === messageId && msg.role === MessageRole.User);
11591
+ if (userMessageIndex === -1) {
11592
+ logger.warn("No user message found with the given ID to remove up to.", {
11593
+ taskId: this.taskId,
11594
+ messageId
11423
11595
  });
11424
11596
  return [];
11425
11597
  }
11426
- const removedMessages = this.messages.splice(lastUserMessageIndex);
11427
- logger.debug(`Task ${this.taskId}: Removed ${removedMessages.length} messages up to last user message. Total messages: ${this.messages.length}`);
11598
+ const removedMessages = this.messages.splice(userMessageIndex);
11599
+ logger.debug(`Task ${this.taskId}: Removed ${removedMessages.length} messages up to user message ${messageId}. Total messages: ${this.messages.length}`);
11428
11600
  this.autosave();
11429
11601
  return removedMessages;
11430
11602
  }
@@ -12078,6 +12250,82 @@ ${JSON.stringify(part.output.value, null, 2)}
12078
12250
  return removedIds;
12079
12251
  }
12080
12252
  }
12253
+ const PROXY_ENV_VAR_NAMES = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"];
12254
+ const getProxyEnvVars = (settings) => {
12255
+ if (settings.proxy?.enabled && settings.proxy?.url) {
12256
+ const url = settings.proxy.url;
12257
+ return {
12258
+ HTTP_PROXY: url,
12259
+ HTTPS_PROXY: url,
12260
+ ALL_PROXY: url,
12261
+ http_proxy: url,
12262
+ https_proxy: url,
12263
+ all_proxy: url
12264
+ };
12265
+ }
12266
+ return Object.fromEntries(PROXY_ENV_VAR_NAMES.map((key) => [key, ""]));
12267
+ };
12268
+ class ProxyManager {
12269
+ currentUrl = null;
12270
+ /**
12271
+ * Initialize proxy from settings. Called once during app startup (first in managers init).
12272
+ */
12273
+ init(settings) {
12274
+ globalAgent.bootstrap();
12275
+ if (settings.proxy?.enabled && settings.proxy?.url) {
12276
+ this.applyProxy(settings.proxy.url);
12277
+ } else {
12278
+ this.clearProxy();
12279
+ }
12280
+ }
12281
+ /**
12282
+ * React to settings changes. Called on every saveSettings().
12283
+ * Re-initializes the proxy if the config changed.
12284
+ */
12285
+ settingsChanged(oldSettings, newSettings) {
12286
+ const oldProxy = oldSettings.proxy;
12287
+ const newProxy = newSettings.proxy;
12288
+ if (oldProxy?.enabled !== newProxy?.enabled || oldProxy?.url !== newProxy?.url) {
12289
+ if (newProxy?.enabled && newProxy?.url) {
12290
+ logger.info(`[ProxyManager] Applying proxy: ${newProxy.url}`);
12291
+ this.applyProxy(newProxy.url);
12292
+ } else if (this.currentUrl !== null) {
12293
+ logger.info("[ProxyManager] Clearing proxy");
12294
+ this.clearProxy();
12295
+ }
12296
+ }
12297
+ }
12298
+ applyProxy(url) {
12299
+ try {
12300
+ global.GLOBAL_AGENT.HTTP_PROXY = url;
12301
+ const proxyAgent = new undici.ProxyAgent(url);
12302
+ undici.setGlobalDispatcher(proxyAgent);
12303
+ this.currentUrl = url;
12304
+ logger.info(`[ProxyManager] Proxy initialized: ${url}`);
12305
+ } catch (error) {
12306
+ logger.error("[ProxyManager] Failed to initialize proxy", { error: error instanceof Error ? error.message : String(error) });
12307
+ }
12308
+ }
12309
+ clearProxy() {
12310
+ try {
12311
+ global.GLOBAL_AGENT.HTTP_PROXY = void 0;
12312
+ undici.setGlobalDispatcher(
12313
+ new undici.Agent({
12314
+ headersTimeout: 30 * 60 * 1e3,
12315
+ // 30 minutes
12316
+ bodyTimeout: 30 * 60 * 1e3,
12317
+ // 30 minutes
12318
+ connectTimeout: 30 * 1e3
12319
+ // 30 seconds
12320
+ })
12321
+ );
12322
+ this.currentUrl = null;
12323
+ logger.info("[ProxyManager] Proxy cleared");
12324
+ } catch (error) {
12325
+ logger.error("[ProxyManager] Failed to clear proxy", { error: error instanceof Error ? error.message : String(error) });
12326
+ }
12327
+ }
12328
+ }
12081
12329
  class AiderManager {
12082
12330
  constructor(task, store, modelManager, eventManager, getConnectors, pythonInstaller) {
12083
12331
  this.task = task;
@@ -12186,11 +12434,13 @@ class AiderManager {
12186
12434
  taskId: this.task.taskId,
12187
12435
  args
12188
12436
  });
12437
+ const proxyEnvVars = getProxyEnvVars(settings);
12189
12438
  const env = {
12190
12439
  ...process.env,
12191
12440
  ...environmentVariables,
12192
12441
  ...envFromMain,
12193
12442
  ...envFromWeak,
12443
+ ...proxyEnvVars,
12194
12444
  PYTHONPATH: AIDER_DESK_CONNECTOR_DIR,
12195
12445
  PYTHONUTF8: process.env.AIDER_DESK_OMIT_PYTHONUTF8 ? void 0 : "1",
12196
12446
  BASE_DIR: this.task.getProjectDir(),
@@ -12486,6 +12736,156 @@ class AiderManager {
12486
12736
  connectors.filter((connector) => connector.listenTo.includes("update-env-vars")).forEach((connector) => connector.sendUpdateEnvVarsMessage(environmentVariables));
12487
12737
  }
12488
12738
  }
12739
+ const SKILLS_DIR_NAME = "skills";
12740
+ const SKILL_MARKDOWN_FILE = "SKILL.md";
12741
+ const TOOL_NAME = `${SKILLS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${SKILLS_TOOL_ACTIVATE_SKILL}`;
12742
+ const parseSkillFrontMatter = (markdown) => {
12743
+ const parsed = yamlFrontMatter.loadFront(markdown);
12744
+ const name = typeof parsed.name === "string" ? parsed.name : void 0;
12745
+ const description = typeof parsed.description === "string" ? parsed.description : void 0;
12746
+ if (!name || !description) {
12747
+ return null;
12748
+ }
12749
+ return { name, description };
12750
+ };
12751
+ const safeReadDir = async (dirPath) => {
12752
+ try {
12753
+ return await fs.readdir(dirPath);
12754
+ } catch {
12755
+ return [];
12756
+ }
12757
+ };
12758
+ const safeStat = async (filePath) => {
12759
+ try {
12760
+ return await fs.stat(filePath);
12761
+ } catch {
12762
+ return null;
12763
+ }
12764
+ };
12765
+ const loadSkillsFromDir = async (skillsRootDir, location) => {
12766
+ const entries = await safeReadDir(skillsRootDir);
12767
+ const skills = [];
12768
+ for (const entry of entries) {
12769
+ const dirPath = path.join(skillsRootDir, entry);
12770
+ const stat = await safeStat(dirPath);
12771
+ if (!stat?.isDirectory()) {
12772
+ continue;
12773
+ }
12774
+ const skillMdPath = path.join(dirPath, SKILL_MARKDOWN_FILE);
12775
+ const skillMdStat = await safeStat(skillMdPath);
12776
+ if (!skillMdStat?.isFile()) {
12777
+ continue;
12778
+ }
12779
+ let markdown;
12780
+ try {
12781
+ markdown = await fs.readFile(skillMdPath, "utf8");
12782
+ } catch {
12783
+ continue;
12784
+ }
12785
+ const parsed = parseSkillFrontMatter(markdown);
12786
+ if (!parsed) {
12787
+ continue;
12788
+ }
12789
+ skills.push({
12790
+ name: parsed.name,
12791
+ description: parsed.description,
12792
+ location,
12793
+ dirPath
12794
+ });
12795
+ }
12796
+ return skills;
12797
+ };
12798
+ class SkillManager {
12799
+ extensionManager;
12800
+ projectDir;
12801
+ constructor(projectDir, extensionManager) {
12802
+ this.projectDir = projectDir;
12803
+ this.extensionManager = extensionManager;
12804
+ }
12805
+ async loadAllSkills() {
12806
+ const globalSkillsDir = path.join(os.homedir(), AIDER_DESK_DIR, SKILLS_DIR_NAME);
12807
+ const projectSkillsDir = path.join(this.projectDir, AIDER_DESK_DIR, SKILLS_DIR_NAME);
12808
+ const extensionSkills = this.extensionManager ? this.extensionManager.getSkills({ baseDir: this.projectDir }, { getTaskDir: () => this.projectDir }) : [];
12809
+ const [globalSkills, projectSkills, builtinSkills] = await Promise.all([
12810
+ loadSkillsFromDir(globalSkillsDir, "global"),
12811
+ loadSkillsFromDir(projectSkillsDir, "project"),
12812
+ loadSkillsFromDir(AIDER_DESK_BUILTIN_SKILLS_DIR, "builtin")
12813
+ ]);
12814
+ return [...projectSkills, ...globalSkills, ...builtinSkills, ...extensionSkills];
12815
+ }
12816
+ async getSkills(contextMessages) {
12817
+ const skills = await this.loadAllSkills();
12818
+ const activatedSkillNames = contextMessages ? this.getActivatedSkillNames(contextMessages) : /* @__PURE__ */ new Set();
12819
+ return skills.map((skill) => ({
12820
+ ...skill,
12821
+ activated: activatedSkillNames.has(skill.name)
12822
+ }));
12823
+ }
12824
+ async getSkillContent(skillName) {
12825
+ const skills = await this.loadAllSkills();
12826
+ const skill = skills.find((s) => s.name === skillName);
12827
+ if (!skill) {
12828
+ return null;
12829
+ }
12830
+ if (skill.content) {
12831
+ return skill.content;
12832
+ }
12833
+ if (skill.dirPath) {
12834
+ const skillMdPath = path.join(skill.dirPath, SKILL_MARKDOWN_FILE);
12835
+ try {
12836
+ return await fs.readFile(skillMdPath, "utf8");
12837
+ } catch {
12838
+ return null;
12839
+ }
12840
+ }
12841
+ return null;
12842
+ }
12843
+ getActivatedSkillNames(contextMessages) {
12844
+ const activatedNames = /* @__PURE__ */ new Set();
12845
+ for (const message of contextMessages) {
12846
+ if (message.role === "assistant" && Array.isArray(message.content)) {
12847
+ for (const part of message.content) {
12848
+ if (part.type === "tool-call" && part.toolName === TOOL_NAME && part.input?.skill) {
12849
+ activatedNames.add(part.input.skill);
12850
+ }
12851
+ }
12852
+ }
12853
+ }
12854
+ return activatedNames;
12855
+ }
12856
+ buildActivateSkillMessages(skillName, content) {
12857
+ const toolCallId = uuid.v4();
12858
+ const assistantMessage = {
12859
+ id: uuid.v4(),
12860
+ role: "assistant",
12861
+ content: [
12862
+ {
12863
+ type: "text",
12864
+ text: "User requested the skill activation."
12865
+ },
12866
+ {
12867
+ type: "tool-call",
12868
+ toolCallId,
12869
+ toolName: TOOL_NAME,
12870
+ input: { skill: skillName }
12871
+ }
12872
+ ]
12873
+ };
12874
+ const toolMessage = {
12875
+ id: uuid.v4(),
12876
+ role: "tool",
12877
+ content: [
12878
+ {
12879
+ type: "tool-result",
12880
+ toolCallId,
12881
+ toolName: TOOL_NAME,
12882
+ output: { type: "text", value: content }
12883
+ }
12884
+ ]
12885
+ };
12886
+ return [assistantMessage, toolMessage];
12887
+ }
12888
+ }
12489
12889
  class GitError extends Error {
12490
12890
  name = "GitError";
12491
12891
  gitCommands;
@@ -12563,7 +12963,7 @@ class WorktreeManager {
12563
12963
  await execWithShellPath('git commit -m "Initial commit" --allow-empty', { cwd: projectPath });
12564
12964
  }
12565
12965
  let baseCommit;
12566
- let actualBaseBranch;
12966
+ let newBranchName;
12567
12967
  const baseRef = baseBranch;
12568
12968
  if (branch) {
12569
12969
  let branchExists = false;
@@ -12577,7 +12977,7 @@ class WorktreeManager {
12577
12977
  baseCommit = (await execWithShellPath(`git rev-parse ${branch}`, {
12578
12978
  cwd: projectPath
12579
12979
  })).stdout.trim();
12580
- actualBaseBranch = branch;
12980
+ newBranchName = branch;
12581
12981
  } else {
12582
12982
  if (baseBranch !== "HEAD") {
12583
12983
  try {
@@ -12590,7 +12990,7 @@ class WorktreeManager {
12590
12990
  cwd: projectPath
12591
12991
  })).stdout.trim();
12592
12992
  await execWithShellPath(`git worktree add -b ${branch} "${worktreePath}" ${baseRef}`, { cwd: projectPath });
12593
- actualBaseBranch = branch;
12993
+ newBranchName = branch;
12594
12994
  }
12595
12995
  } else {
12596
12996
  await execWithShellPath(`git worktree add "${worktreePath}" ${baseRef}`, { cwd: projectPath });
@@ -12599,25 +12999,38 @@ class WorktreeManager {
12599
12999
  })).stdout.trim();
12600
13000
  if (baseRef === "HEAD") {
12601
13001
  try {
12602
- actualBaseBranch = (await execWithShellPath("git rev-parse --abbrev-ref HEAD", {
13002
+ newBranchName = (await execWithShellPath("git rev-parse --abbrev-ref HEAD", {
12603
13003
  cwd: projectPath
12604
13004
  })).stdout.trim();
12605
- if (actualBaseBranch === "HEAD") {
12606
- actualBaseBranch = "DETACHED HEAD";
13005
+ if (newBranchName === "HEAD") {
13006
+ newBranchName = "DETACHED HEAD";
12607
13007
  }
12608
13008
  } catch {
12609
- actualBaseBranch = "DETACHED HEAD";
13009
+ newBranchName = "DETACHED HEAD";
12610
13010
  }
12611
13011
  } else {
12612
- actualBaseBranch = `${baseRef} (DETACHED)`;
13012
+ newBranchName = `${baseRef} (DETACHED)`;
12613
13013
  }
12614
13014
  logger.info(`Worktree created in DETACHED HEAD mode from commit: ${baseCommit}`);
12615
13015
  }
13016
+ let resolvedBaseBranch;
13017
+ if (baseRef === "HEAD") {
13018
+ try {
13019
+ const result = await execWithShellPath("git rev-parse --abbrev-ref HEAD", { cwd: projectPath });
13020
+ const headBranch = result.stdout.trim();
13021
+ resolvedBaseBranch = headBranch !== "HEAD" ? headBranch : void 0;
13022
+ } catch {
13023
+ resolvedBaseBranch = void 0;
13024
+ }
13025
+ } else {
13026
+ resolvedBaseBranch = baseRef;
13027
+ }
12616
13028
  logger.info(`Worktree created successfully at: ${worktreePath}`);
12617
13029
  return {
12618
13030
  path: worktreePath,
12619
13031
  baseCommit,
12620
- baseBranch: actualBaseBranch
13032
+ baseBranch: resolvedBaseBranch,
13033
+ branch: newBranchName
12621
13034
  };
12622
13035
  } catch (error) {
12623
13036
  logger.error("Failed to create worktree:", error);
@@ -12625,6 +13038,29 @@ class WorktreeManager {
12625
13038
  }
12626
13039
  });
12627
13040
  }
13041
+ async renameBranch(projectPath, oldBranch, newBranch) {
13042
+ try {
13043
+ const finalBranchName = await this.findUniqueBranchName(projectPath, newBranch);
13044
+ await execWithShellPath(`git branch -m ${oldBranch} ${finalBranchName}`, { cwd: projectPath });
13045
+ logger.info(`Renamed branch: ${oldBranch} -> ${finalBranchName}`);
13046
+ return finalBranchName;
13047
+ } catch (error) {
13048
+ logger.warn(`Failed to rename branch ${oldBranch} to ${newBranch}:`, error);
13049
+ return newBranch;
13050
+ }
13051
+ }
13052
+ async findUniqueBranchName(projectPath, baseName) {
13053
+ const existingBranches = await this.listBranches(projectPath);
13054
+ const branchNames = new Set(existingBranches.map((b) => b.name));
13055
+ if (!branchNames.has(baseName)) {
13056
+ return baseName;
13057
+ }
13058
+ let suffix = 2;
13059
+ while (branchNames.has(`${baseName}-${suffix}`)) {
13060
+ suffix++;
13061
+ }
13062
+ return `${baseName}-${suffix}`;
13063
+ }
12628
13064
  async createSymlinks(projectPath, worktreePath, folderNames) {
12629
13065
  if (folderNames.length === 0) {
12630
13066
  logger.debug("No symlink folders configured, skipping symlink creation");
@@ -12678,14 +13114,14 @@ class WorktreeManager {
12678
13114
  return await withLock(`worktree-remove-${projectDir}-${worktree.path}`, async () => {
12679
13115
  try {
12680
13116
  await execWithShellPath(`git worktree remove "${worktree.path}" --force`, { cwd: projectDir });
12681
- if (worktree.baseBranch) {
13117
+ if (worktree.branch) {
12682
13118
  try {
12683
- await execWithShellPath(`git branch -D ${worktree.baseBranch}`, {
13119
+ await execWithShellPath(`git branch -D ${worktree.branch}`, {
12684
13120
  cwd: projectDir
12685
13121
  });
12686
- logger.info(`Deleted task branch: ${worktree.baseBranch}`);
13122
+ logger.info(`Deleted task branch: ${worktree.branch}`);
12687
13123
  } catch (error) {
12688
- logger.debug(`Could not delete branch ${worktree.baseBranch}:`, error);
13124
+ logger.debug(`Could not delete branch ${worktree.branch}:`, error);
12689
13125
  }
12690
13126
  }
12691
13127
  } catch (error) {
@@ -12712,12 +13148,12 @@ class WorktreeManager {
12712
13148
  ...currentWorktree
12713
13149
  });
12714
13150
  }
12715
- currentWorktree = { path: line.substring(9), baseBranch: "" };
13151
+ currentWorktree = { path: line.substring(9), branch: "" };
12716
13152
  } else if (line.startsWith("branch ")) {
12717
13153
  currentWorktree = {
12718
13154
  ...currentWorktree || {},
12719
13155
  path: currentWorktree ? currentWorktree.path : "",
12720
- baseBranch: line.substring(7).replace("refs/heads/", "")
13156
+ branch: line.substring(7).replace("refs/heads/", "")
12721
13157
  };
12722
13158
  } else if (line.startsWith("HEAD ")) {
12723
13159
  currentWorktree = {
@@ -12729,7 +13165,7 @@ class WorktreeManager {
12729
13165
  currentWorktree = {
12730
13166
  ...currentWorktree || {},
12731
13167
  path: currentWorktree ? currentWorktree.path : "",
12732
- baseBranch: void 0
13168
+ branch: void 0
12733
13169
  };
12734
13170
  } else if (line.startsWith("prunable")) {
12735
13171
  currentWorktree = {
@@ -12758,7 +13194,7 @@ class WorktreeManager {
12758
13194
  cwd: projectPath
12759
13195
  });
12760
13196
  const worktrees = await this.listWorktrees(projectPath);
12761
- const worktreeBranches = new Set(worktrees.map((w) => w.baseBranch));
13197
+ const worktreeBranches = new Set(worktrees.map((w) => w.branch));
12762
13198
  const branches = [];
12763
13199
  const lines = branchOutput.split("\n").filter((line) => line.trim());
12764
13200
  for (const line of lines) {
@@ -12812,6 +13248,22 @@ class WorktreeManager {
12812
13248
  logger.warn("getEffectiveMainBranch is deprecated, use getProjectMainBranch instead");
12813
13249
  return await this.getProjectMainBranch(project.path);
12814
13250
  }
13251
+ async getHeadCommit(worktreePath) {
13252
+ try {
13253
+ const { stdout } = await execWithShellPath("git rev-parse HEAD", { cwd: worktreePath });
13254
+ return stdout.trim();
13255
+ } catch {
13256
+ return void 0;
13257
+ }
13258
+ }
13259
+ async getBranchesContainingCommit(projectPath, commit) {
13260
+ try {
13261
+ const { stdout } = await execWithShellPath(`git branch --contains ${commit} --format='%(refname:short)'`, { cwd: projectPath });
13262
+ return stdout.trim().split("\n").map((b) => b.trim()).filter((b) => b);
13263
+ } catch {
13264
+ return [];
13265
+ }
13266
+ }
12815
13267
  async hasChangesToRebase(worktreePath, mainBranch) {
12816
13268
  try {
12817
13269
  let stdout = "0";
@@ -12893,7 +13345,7 @@ class WorktreeManager {
12893
13345
  };
12894
13346
  }
12895
13347
  }
12896
- async rebaseMainIntoWorktree(worktreePath, mainBranch) {
13348
+ async rebaseMainIntoWorktree(worktreePath, mainBranch, baseCommit) {
12897
13349
  return await withLock(`git-rebase-${worktreePath}`, async () => {
12898
13350
  const executedCommands = [];
12899
13351
  let lastOutput = "";
@@ -12905,14 +13357,14 @@ class WorktreeManager {
12905
13357
  const addCommand = "git add -A";
12906
13358
  executedCommands.push(`${addCommand} (in ${worktreePath})`);
12907
13359
  await execWithShellPath(addCommand, { cwd: worktreePath });
12908
- const commitCommand = `git commit -m "TEMP_UNCOMMITTED_${Date.now()}"`;
13360
+ const commitCommand = `git commit --no-verify -m "TEMP_UNCOMMITTED_${Date.now()}"`;
12909
13361
  executedCommands.push(`${commitCommand} (in ${worktreePath})`);
12910
13362
  await execWithShellPath(commitCommand, {
12911
13363
  cwd: worktreePath
12912
13364
  });
12913
13365
  logger.info("Created temporary commit for uncommitted changes");
12914
13366
  }
12915
- const command = `git rebase ${mainBranch}`;
13367
+ const command = baseCommit ? `git rebase --onto ${mainBranch} ${baseCommit}` : `git rebase ${mainBranch}`;
12916
13368
  executedCommands.push(`${command} (in ${worktreePath})`);
12917
13369
  const rebaseResult = await execWithShellPath(command, {
12918
13370
  cwd: worktreePath
@@ -12987,7 +13439,7 @@ class WorktreeManager {
12987
13439
  }
12988
13440
  });
12989
13441
  }
12990
- async squashAndMergeWorktreeToMain(projectPath, worktreePath, mainBranch, commitMessage) {
13442
+ async squashAndMergeWorktreeToMain(projectPath, worktreePath, mainBranch, commitMessage, baseCommit) {
12991
13443
  const executedCommands = [];
12992
13444
  let lastOutput = "";
12993
13445
  try {
@@ -13003,8 +13455,8 @@ class WorktreeManager {
13003
13455
  if (!commits.trim()) {
13004
13456
  return;
13005
13457
  }
13006
- command = `git rebase ${mainBranch}`;
13007
- executedCommands.push(`git rebase ${mainBranch} (in ${worktreePath})`);
13458
+ command = baseCommit ? `git rebase --onto ${mainBranch} ${baseCommit}` : `git rebase ${mainBranch}`;
13459
+ executedCommands.push(`${command} (in ${worktreePath})`);
13008
13460
  try {
13009
13461
  const rebaseWorktreeResult = await execWithShellPath(command, {
13010
13462
  cwd: worktreePath
@@ -13313,10 +13765,12 @@ Git output: ${err.stderr || err.stdout || err.message}`
13313
13765
  */
13314
13766
  async hasUncommittedChanges(path2) {
13315
13767
  try {
13316
- const { stdout } = await execWithShellPath("git status --porcelain=v1", {
13768
+ const { stdout } = await execWithShellPath("git status --porcelain=v1 -z", {
13317
13769
  cwd: path2
13318
13770
  });
13319
- return stdout.trim().length > 0;
13771
+ const filePaths = this.parseGitStatusEntries(stdout);
13772
+ const realChanges = filePaths.filter((filePath) => !this.isSymlinkPath(path2, filePath));
13773
+ return realChanges.length > 0;
13320
13774
  } catch (error) {
13321
13775
  logger.error("Failed to check for uncommitted changes:", error);
13322
13776
  return false;
@@ -13408,7 +13862,7 @@ Git output: ${err.stderr || err.stdout || err.message}`
13408
13862
  * Merge worktree to main branch with uncommitted changes support
13409
13863
  * Returns MergeState for potential revert
13410
13864
  */
13411
- async mergeWorktreeToMainWithUncommitted(projectPath, taskId, worktreePath, squash, commitMessage, targetBranch, symlinkFolders = []) {
13865
+ async mergeWorktreeToMainWithUncommitted(projectPath, taskId, worktreePath, squash, commitMessage, targetBranch, symlinkFolders = [], baseCommit) {
13412
13866
  return await withLock(`git-merge-worktree-${worktreePath}`, async () => {
13413
13867
  const timestamp = Date.now();
13414
13868
  const worktreeStashId = `worktree-${taskId.length > 24 ? taskId.substring(24) : taskId}-merge-${timestamp}`;
@@ -13436,7 +13890,7 @@ Git output: ${err.stderr || err.stdout || err.message}`
13436
13890
  if (!commitMessage) {
13437
13891
  throw new Error("Commit message is required for squash merge");
13438
13892
  }
13439
- await this.squashAndMergeWorktreeToMain(projectPath, worktreePath, mainBranch, commitMessage);
13893
+ await this.squashAndMergeWorktreeToMain(projectPath, worktreePath, mainBranch, commitMessage, baseCommit);
13440
13894
  } else {
13441
13895
  await this.mergeWorktreeToMain(projectPath, worktreePath, mainBranch);
13442
13896
  }
@@ -13490,10 +13944,15 @@ Git output: ${err.stderr || err.stdout || err.message}`
13490
13944
  * Check if worktree has uncommitted changes or unmerged commits
13491
13945
  * Returns information about unsaved work in the worktree
13492
13946
  */
13493
- async checkWorktreeForUnmergedWork(projectPath, worktreePath, targetBranch) {
13947
+ async checkWorktreeForUnmergedWork(projectPath, worktreePath, targetBranch, symlinkFolders = []) {
13494
13948
  try {
13495
- const hasUncommittedChanges = await this.hasUncommittedChanges(worktreePath);
13496
13949
  const { files: uncommittedFiles } = await this.getUncommittedFiles(worktreePath);
13950
+ const filteredUncommittedFiles = uncommittedFiles.filter((file) => {
13951
+ const pathPart = file.replace(/^..\s*/, "").trim();
13952
+ const normalizedPath = pathPart.replace(/\\/g, "/");
13953
+ return !symlinkFolders.some((folder) => normalizedPath.startsWith(`${folder}/`) || normalizedPath === folder);
13954
+ });
13955
+ const actualHasUncommittedChanges = filteredUncommittedFiles.length > 0;
13497
13956
  const effectiveTargetBranch = targetBranch || await this.getProjectMainBranch(projectPath);
13498
13957
  let unmergedCommitCount = 0;
13499
13958
  let unmergedCommits = [];
@@ -13507,11 +13966,11 @@ Git output: ${err.stderr || err.stdout || err.message}`
13507
13966
  }
13508
13967
  const hasUnmergedCommits = unmergedCommitCount > 0;
13509
13968
  return {
13510
- hasUncommittedChanges,
13969
+ hasUncommittedChanges: actualHasUncommittedChanges,
13511
13970
  hasUnmergedCommits,
13512
13971
  unmergedCommitCount,
13513
13972
  unmergedCommits,
13514
- uncommittedFiles
13973
+ uncommittedFiles: filteredUncommittedFiles
13515
13974
  };
13516
13975
  } catch (error) {
13517
13976
  logger.error("Failed to check worktree for unmerged work:", error);
@@ -13536,12 +13995,25 @@ Git output: ${err.stderr || err.stdout || err.message}`
13536
13995
  const { stdout } = await execWithShellPath("git status --porcelain=v1 -z", {
13537
13996
  cwd: worktreePath
13538
13997
  });
13539
- const files = stdout.split("\0").map((l) => l.trim()).filter((l) => l.length > 0);
13998
+ const filePaths = this.parseGitStatusEntries(stdout);
13999
+ const files = filePaths.filter((filePath) => !this.isSymlinkPath(worktreePath, filePath));
13540
14000
  return {
13541
14001
  count: files.length,
13542
14002
  files: Array.from(new Set(files))
13543
14003
  };
13544
14004
  }
14005
+ parseGitStatusEntries(stdout) {
14006
+ return stdout.split("\0").map((entry) => entry.substring(3).trim()).filter((filePath) => filePath.length > 0);
14007
+ }
14008
+ isSymlinkPath(cwd, filePath) {
14009
+ try {
14010
+ const fullPath = path.join(cwd, filePath);
14011
+ const stat = fs$1.lstatSync(fullPath);
14012
+ return stat.isSymbolicLink();
14013
+ } catch {
14014
+ return false;
14015
+ }
14016
+ }
13545
14017
  /**
13546
14018
  * Get updated files with per-commit and uncommitted diffs.
13547
14019
  *
@@ -13553,13 +14025,17 @@ Git output: ${err.stderr || err.stdout || err.message}`
13553
14025
  */
13554
14026
  async getUpdatedFiles(worktreePath, workingMode, mainBranch, groupMode = UpdatedFilesGroupMode.Grouped) {
13555
14027
  try {
14028
+ let files;
13556
14029
  if (workingMode === "worktree" && mainBranch) {
13557
14030
  if (groupMode === UpdatedFilesGroupMode.Flat) {
13558
- return await this.getWorktreeFlatUpdatedFiles(worktreePath, mainBranch);
14031
+ files = await this.getWorktreeFlatUpdatedFiles(worktreePath, mainBranch);
14032
+ } else {
14033
+ files = await this.getWorktreeUpdatedFiles(worktreePath, mainBranch);
13559
14034
  }
13560
- return await this.getWorktreeUpdatedFiles(worktreePath, mainBranch);
14035
+ } else {
14036
+ files = await this.getNonWorktreeUpdatedFiles(worktreePath);
13561
14037
  }
13562
- return await this.getNonWorktreeUpdatedFiles(worktreePath);
14038
+ return await this.markConflictingFiles(worktreePath, files);
13563
14039
  } catch (error) {
13564
14040
  logger.warn("Failed to get updated files:", error);
13565
14041
  return [];
@@ -13799,6 +14275,20 @@ Git output: ${err.stderr || err.stdout || err.message}`
13799
14275
  }
13800
14276
  return fileDiffs;
13801
14277
  }
14278
+ async markConflictingFiles(worktreePath, files) {
14279
+ try {
14280
+ const { stdout } = await execWithShellPath("git diff --name-only --diff-filter=U", { cwd: worktreePath });
14281
+ const unmergedFiles = new Set(
14282
+ stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0)
14283
+ );
14284
+ if (unmergedFiles.size === 0) {
14285
+ return files;
14286
+ }
14287
+ return files.map((f) => unmergedFiles.has(f.path) ? { ...f, hasConflicts: true } : f);
14288
+ } catch {
14289
+ return files;
14290
+ }
14291
+ }
13802
14292
  async restoreFile(worktreePath, filePath) {
13803
14293
  try {
13804
14294
  logger.info(`Restoring file: ${filePath}`, { worktreePath });
@@ -14166,6 +14656,7 @@ class Task {
14166
14656
  };
14167
14657
  this.taskDataPath = path.join(this.project.baseDir, AIDER_DESK_TASKS_DIR, this.taskId, "settings.json");
14168
14658
  this.contextManager = new ContextManager(this, this.taskId);
14659
+ this.skillManager = new SkillManager(project.baseDir, extensionManager);
14169
14660
  this.agent = new Agent(
14170
14661
  this.store,
14171
14662
  this.agentProfileManager,
@@ -14211,6 +14702,7 @@ class Task {
14211
14702
  contextManager;
14212
14703
  agent;
14213
14704
  aiderManager;
14705
+ skillManager;
14214
14706
  task;
14215
14707
  async getTaskAgentProfile() {
14216
14708
  let agentProfileId = this.task.agentProfileId;
@@ -14264,10 +14756,56 @@ class Task {
14264
14756
  * Generate a branch name from task name (first 7 words, separated by '-')
14265
14757
  */
14266
14758
  generateBranchName() {
14759
+ const settings = this.store.getSettings();
14760
+ const branchPrefix = settings.taskSettings.worktreeBranchPrefix || WORKTREE_BRANCH_PREFIX;
14267
14761
  const words = this.task.name.toLowerCase().replace(/[^a-z0-9\s-]/g, "").split(/\s+/).filter((word) => word.length > 0).slice(0, 7);
14268
14762
  const branchName = words.join("-");
14269
14763
  const cleanBranchName = branchName.replace(/^[.-]+/, "").replace(/-+/g, "-").replace(/-$/, "");
14270
- return `${WORKTREE_BRANCH_PREFIX}${cleanBranchName || this.taskId}`;
14764
+ const fallbackId = /^[0-9a-f]{8}-/i.test(this.taskId) ? this.taskId.split("-")[0] : this.taskId;
14765
+ return `${branchPrefix}${cleanBranchName || fallbackId}`;
14766
+ }
14767
+ async renameWorktreeBranchIfNeeded() {
14768
+ if (this.task.workingMode !== "worktree" || !this.task.worktree?.branch) {
14769
+ return;
14770
+ }
14771
+ const settings = this.store.getSettings();
14772
+ if (!settings.taskSettings.renameBranchOnNameGeneration) {
14773
+ return;
14774
+ }
14775
+ const oldBranch = this.task.worktree.branch;
14776
+ const newBranch = this.generateBranchName();
14777
+ if (oldBranch === newBranch) {
14778
+ return;
14779
+ }
14780
+ await this.renameWorktreeBranch(newBranch);
14781
+ }
14782
+ /**
14783
+ * @deprecated This migration ensures older task data has the `branch` field
14784
+ * and `baseBranch` stores the branch the worktree was created from.
14785
+ * Can be removed once all users have migrated past v0.64.0.
14786
+ */
14787
+ async migrateWorktreeData() {
14788
+ if (!this.task.worktree || this.task.worktree.branch) {
14789
+ return;
14790
+ }
14791
+ const currentBranch = this.task.worktree.baseBranch;
14792
+ this.task.worktree.branch = currentBranch;
14793
+ let resolvedBase = "";
14794
+ if (this.task.worktree.baseCommit) {
14795
+ const branches = await this.worktreeManager.getBranchesContainingCommit(this.project.baseDir, this.task.worktree.baseCommit);
14796
+ if (branches.length === 1) {
14797
+ resolvedBase = branches[0];
14798
+ }
14799
+ }
14800
+ if (!resolvedBase) {
14801
+ try {
14802
+ resolvedBase = await this.worktreeManager.getProjectMainBranch(this.project.baseDir);
14803
+ } catch {
14804
+ resolvedBase = "";
14805
+ }
14806
+ }
14807
+ this.task.worktree.baseBranch = resolvedBase || void 0;
14808
+ await this.saveTask({ worktree: this.task.worktree });
14271
14809
  }
14272
14810
  isInternal() {
14273
14811
  return this.taskId === INTERNAL_TASK_ID;
@@ -14343,14 +14881,18 @@ class Task {
14343
14881
  worktreePath: this.task.worktree.path
14344
14882
  });
14345
14883
  } else {
14346
- const branchName = this.generateBranchName();
14347
- this.task.worktree = await this.worktreeManager.createWorktree(this.project.baseDir, this.taskId, branchName);
14884
+ await this.initWorktree();
14348
14885
  void this.sendUpdatedFilesUpdated();
14886
+ void this.sendWorktreeIntegrationStatusUpdated();
14349
14887
  }
14350
14888
  } else if (workingMode === "local") {
14351
14889
  if (existingWorktree) {
14352
- await this.worktreeManager.removeWorktree(this.project.baseDir, existingWorktree);
14890
+ const isShared = this.project.isWorktreeSharedWithOtherTasks(existingWorktree.path, this.taskId);
14891
+ if (!isShared) {
14892
+ await this.worktreeManager.removeWorktree(this.project.baseDir, existingWorktree);
14893
+ }
14353
14894
  void this.sendUpdatedFilesUpdated();
14895
+ void this.sendWorktreeIntegrationStatusUpdated();
14354
14896
  }
14355
14897
  } else {
14356
14898
  logger.debug("Empty workingMode, setting to local", {
@@ -14367,6 +14909,7 @@ class Task {
14367
14909
  this.task.workingMode = "local";
14368
14910
  }
14369
14911
  }
14912
+ await this.migrateWorktreeData();
14370
14913
  if (await fileExists(this.getTaskDir())) {
14371
14914
  this.git = simpleGit.simpleGit(this.getTaskDir());
14372
14915
  }
@@ -14741,7 +15284,9 @@ class Task {
14741
15284
  await this.saveTask({
14742
15285
  name: this.task.name || this.getTaskNameFromPrompt(prompt || ""),
14743
15286
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
14744
- state: DefaultTaskState.InProgress
15287
+ state: DefaultTaskState.InProgress,
15288
+ provider: this.task.provider || profile.provider,
15289
+ model: this.task.model || profile.model
14745
15290
  });
14746
15291
  const agentMessages = await this.agent.runAgent(this, profile, prompt, mode, promptContext, contextMessages, contextFiles, systemPrompt);
14747
15292
  if (agentMessages.length > 0) {
@@ -14752,6 +15297,7 @@ class Task {
14752
15297
  void this.sendRequestContextInfo();
14753
15298
  void this.sendWorktreeIntegrationStatusUpdated();
14754
15299
  void this.sendUpdatedFilesUpdated();
15300
+ void this.sendSkillsUpdated();
14755
15301
  this.resolveAgentRunPromises();
14756
15302
  if (waitForCurrentAgentToFinish) {
14757
15303
  await this.runNextQueuedPrompt();
@@ -14782,14 +15328,11 @@ class Task {
14782
15328
  const settings = this.store.getSettings();
14783
15329
  if (settings.taskSettings.autoGenerateTaskName) {
14784
15330
  this.generateTaskNameInBackground(prompt).then((taskName) => {
14785
- if (taskName) {
14786
- void this.saveTask({ name: taskName });
14787
- } else {
14788
- void this.saveTask({ name: fallbackName });
14789
- }
15331
+ const newName = taskName || fallbackName;
15332
+ void this.saveTask({ name: newName }).then(() => this.renameWorktreeBranchIfNeeded());
14790
15333
  }).catch((error) => {
14791
15334
  logger.warn("Failed to generate task name:", error);
14792
- void this.saveTask({ name: fallbackName });
15335
+ void this.saveTask({ name: fallbackName }).then(() => this.renameWorktreeBranchIfNeeded());
14793
15336
  });
14794
15337
  return "<<generating>>";
14795
15338
  } else {
@@ -15565,10 +16108,10 @@ ${contentText}</agent-response>`;
15565
16108
  return contextFiles;
15566
16109
  }
15567
16110
  const profile = await this.getTaskAgentProfile();
15568
- const ruleFiles = await this.getRuleFilesAsContextFiles(profile || void 0);
16111
+ const ruleFiles = await this.getRuleFilesAsContextFiles(profile || void 0, true);
15569
16112
  return [...contextFiles, ...ruleFiles];
15570
16113
  }
15571
- async getRuleFilesAsContextFiles(profile) {
16114
+ async getRuleFilesAsContextFiles(profile, includeDisabled = false) {
15572
16115
  const ruleFiles = [];
15573
16116
  const homeDir = os.homedir();
15574
16117
  if (await fileExists(AIDER_DESK_GLOBAL_RULES_DIR)) {
@@ -15639,7 +16182,8 @@ ${contentText}</agent-response>`;
15639
16182
  }
15640
16183
  }
15641
16184
  const extensionResult = await this.extensionManager.dispatchEvent("onRuleFilesRetrieved", { files: ruleFiles }, this.project, this);
15642
- return extensionResult.files;
16185
+ const disabledRuleFiles = this.project.getProjectSettings().disabledRuleFiles ?? [];
16186
+ return includeDisabled ? extensionResult.files : extensionResult.files.filter((f) => !disabledRuleFiles.includes(f.path));
15643
16187
  }
15644
16188
  getRepoMap() {
15645
16189
  return this.aiderManager.getRepoMap();
@@ -15668,6 +16212,92 @@ ${contentText}</agent-response>`;
15668
16212
  getContextMessages() {
15669
16213
  return this.contextManager.getContextMessages();
15670
16214
  }
16215
+ getSkillManager() {
16216
+ return this.skillManager;
16217
+ }
16218
+ async getSkills() {
16219
+ const contextMessages = await this.contextManager.getContextMessages();
16220
+ return this.skillManager.getSkills(contextMessages);
16221
+ }
16222
+ async activateSkill(skillName) {
16223
+ const contextMessages = await this.contextManager.getContextMessages();
16224
+ const activatedNames = this.skillManager.getActivatedSkillNames(contextMessages);
16225
+ if (activatedNames.has(skillName)) {
16226
+ logger.debug("Skill already activated, skipping", { skillName });
16227
+ return;
16228
+ }
16229
+ const content = await this.skillManager.getSkillContent(skillName);
16230
+ if (!content) {
16231
+ throw new Error(`Skill '${skillName}' not found`);
16232
+ }
16233
+ const [assistantMessage, toolMessage] = this.skillManager.buildActivateSkillMessages(skillName, content);
16234
+ this.contextManager.addContextMessage(assistantMessage);
16235
+ this.contextManager.addContextMessage(toolMessage);
16236
+ await this.processResponseMessage(
16237
+ {
16238
+ id: assistantMessage.id,
16239
+ action: "response",
16240
+ content: "User requested the skill activation.",
16241
+ finished: true
16242
+ },
16243
+ false
16244
+ );
16245
+ const toolCallId = toolMessage.content[0].toolCallId;
16246
+ this.addToolMessage(
16247
+ toolCallId,
16248
+ SKILLS_TOOL_GROUP_NAME,
16249
+ SKILLS_TOOL_ACTIVATE_SKILL,
16250
+ { skill: skillName },
16251
+ JSON.stringify(content),
16252
+ void 0,
16253
+ void 0,
16254
+ false,
16255
+ true
16256
+ );
16257
+ await this.updateContextInfo();
16258
+ }
16259
+ async deactivateSkill(skillName) {
16260
+ const contextMessages = await this.contextManager.getContextMessages();
16261
+ const toolName = `${SKILLS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${SKILLS_TOOL_ACTIVATE_SKILL}`;
16262
+ for (let i = contextMessages.length - 1; i >= 0; i--) {
16263
+ const message = contextMessages[i];
16264
+ if (message.role === "assistant" && Array.isArray(message.content)) {
16265
+ const toolCallPart = message.content.find(
16266
+ (part) => part.type === "tool-call" && part.toolName === toolName && part.input?.skill === skillName
16267
+ );
16268
+ if (!toolCallPart || toolCallPart.type !== "tool-call") {
16269
+ continue;
16270
+ }
16271
+ const toolCallId = toolCallPart.toolCallId;
16272
+ const toolMessage = contextMessages.find(
16273
+ (msg) => msg.role === "tool" && Array.isArray(msg.content) && msg.content.some((part) => part.type === "tool-result" && part.toolCallId === toolCallId)
16274
+ );
16275
+ const removedIds = [];
16276
+ const idsToRemoveFromContext = [];
16277
+ if (toolMessage) {
16278
+ removedIds.push(toolMessage.id);
16279
+ removedIds.push(toolCallId);
16280
+ idsToRemoveFromContext.push(toolMessage.id);
16281
+ }
16282
+ const otherToolCalls = message.content.filter((part) => part.type === "tool-call" && part !== toolCallPart);
16283
+ if (otherToolCalls.length > 0) {
16284
+ this.contextManager.removeMessageById(toolCallId);
16285
+ } else {
16286
+ removedIds.push(message.id);
16287
+ idsToRemoveFromContext.push(message.id);
16288
+ this.contextManager.removeMessagesByIds(idsToRemoveFromContext);
16289
+ }
16290
+ if (removedIds.length > 0) {
16291
+ await this.reloadConnectorMessages();
16292
+ await this.updateContextInfo();
16293
+ void this.sendSkillsUpdated();
16294
+ }
16295
+ return removedIds;
16296
+ }
16297
+ }
16298
+ logger.debug(`No activation found for skill '${skillName}' to deactivate.`);
16299
+ return [];
16300
+ }
15671
16301
  async addRoleContextMessage(role, content, usageReport) {
15672
16302
  logger.debug("Adding role message to session:", {
15673
16303
  baseDir: this.project.baseDir,
@@ -15948,12 +16578,18 @@ ${contentText}</agent-response>`;
15948
16578
  const removedIds = this.contextManager.removeMessageById(messageId);
15949
16579
  await this.reloadConnectorMessages();
15950
16580
  await this.updateContextInfo();
16581
+ if (removedIds.length > 0) {
16582
+ void this.sendSkillsUpdated();
16583
+ }
15951
16584
  return removedIds;
15952
16585
  }
15953
16586
  async removeMessagesUpTo(messageId) {
15954
16587
  const removedIds = this.contextManager.removeMessagesAfter(messageId);
15955
16588
  await this.reloadConnectorMessages();
15956
16589
  await this.updateContextInfo();
16590
+ if (removedIds.length > 0) {
16591
+ void this.sendSkillsUpdated();
16592
+ }
15957
16593
  return removedIds;
15958
16594
  }
15959
16595
  sendTaskMessageRemoved(messageIds) {
@@ -15961,26 +16597,27 @@ ${contentText}</agent-response>`;
15961
16597
  this.eventManager.sendTaskMessageRemoved(this.project.baseDir, this.taskId, messageIds);
15962
16598
  }
15963
16599
  }
15964
- async redoLastUserPrompt(mode, updatedPrompt) {
15965
- logger.info("Redoing last user prompt:", {
16600
+ async redoUserPrompt(messageId, mode, updatedPrompt) {
16601
+ logger.info("Redoing user prompt:", {
15966
16602
  baseDir: this.project.baseDir,
16603
+ messageId,
15967
16604
  mode,
15968
16605
  hasUpdatedPrompt: !!updatedPrompt
15969
16606
  });
15970
- const removedMessages = this.contextManager.removeMessagesUpToLastUserMessage();
15971
- const originalLastUserMessage = removedMessages.findLast((msg) => msg.role === MessageRole.User);
15972
- if (!originalLastUserMessage) {
15973
- logger.warn("Could not find original last user message content to redo.");
16607
+ const removedMessages = this.contextManager.removeMessagesUpToUserMessage(messageId);
16608
+ const originalUserMessage = removedMessages[0];
16609
+ if (!originalUserMessage || originalUserMessage.role !== MessageRole.User) {
16610
+ logger.warn("Could not find the specified user message to redo.", { messageId });
15974
16611
  return;
15975
16612
  }
15976
- const promptToRun = updatedPrompt ?? originalLastUserMessage.content;
16613
+ const promptToRun = updatedPrompt ?? originalUserMessage.content;
15977
16614
  if (promptToRun) {
15978
16615
  logger.info("Found message content to run, reloading and re-running prompt.", {
15979
16616
  remainingMessagesCount: (await this.contextManager.getContextMessages()).length
15980
16617
  });
15981
- this.sendTaskMessageRemoved(removedMessages.slice(0, -1).map((msg) => msg.id));
16618
+ this.sendTaskMessageRemoved(removedMessages.slice(1).map((msg) => msg.id));
15982
16619
  await this.updateContextInfo();
15983
- void this.runPrompt(promptToRun, mode, false, originalLastUserMessage.id);
16620
+ void this.runPrompt(promptToRun, mode, false, originalUserMessage.id);
15984
16621
  } else {
15985
16622
  logger.warn("Could not find a previous user message to redo or an updated prompt to run.");
15986
16623
  }
@@ -16007,7 +16644,7 @@ ${contentText}</agent-response>`;
16007
16644
  if (lastMessage && lastMessage.role === MessageRole.User) {
16008
16645
  logger.info("Last message is from user, redoing prompt");
16009
16646
  this.addLogMessage("loading", "Resuming task...");
16010
- void this.redoLastUserPrompt(mode);
16647
+ void this.redoUserPrompt(lastMessage.id, mode);
16011
16648
  } else {
16012
16649
  logger.info("Last message is not from user, sending Continue prompt");
16013
16650
  void this.runPrompt("Continue", mode, false);
@@ -16320,12 +16957,16 @@ ${contentText}</agent-response>`;
16320
16957
  const aiderWatchFilesChanged = oldSettings.aider.watchFiles !== newSettings?.aider.watchFiles;
16321
16958
  const aiderCachingEnabledChanged = oldSettings.aider.cachingEnabled !== newSettings?.aider.cachingEnabled;
16322
16959
  const aiderConfirmBeforeEditChanged = oldSettings.aider.confirmBeforeEdit !== newSettings?.aider.confirmBeforeEdit;
16960
+ const proxyChanged = oldSettings.proxy?.enabled !== newSettings.proxy?.enabled || oldSettings.proxy?.url !== newSettings.proxy?.url;
16323
16961
  if ((aiderOptionsChanged || aiderAutoCommitsChanged || aiderWatchFilesChanged || aiderCachingEnabledChanged || aiderConfirmBeforeEditChanged) && await this.shouldStartAider()) {
16324
16962
  logger.debug("Aider options changed, restarting Aider.");
16325
16963
  void this.aiderManager.start(true);
16326
- } else if (aiderEnvVarsChanged) {
16964
+ } else if (aiderEnvVarsChanged || proxyChanged) {
16327
16965
  logger.debug("Aider environment variables changed, updating connectors.");
16328
- const updatedEnvironmentVariables = getEnvironmentVariablesForAider(newSettings, this.project.baseDir);
16966
+ const updatedEnvironmentVariables = {
16967
+ ...getEnvironmentVariablesForAider(newSettings, this.project.baseDir),
16968
+ ...getProxyEnvVars(newSettings)
16969
+ };
16329
16970
  this.sendUpdateEnvVars(updatedEnvironmentVariables);
16330
16971
  }
16331
16972
  }
@@ -16335,9 +16976,13 @@ ${contentText}</agent-response>`;
16335
16976
  async projectSettingsChanged(oldSettings, newSettings) {
16336
16977
  const modeChanged = oldSettings.currentMode !== newSettings.currentMode;
16337
16978
  const agentProfileIdChanged = oldSettings.agentProfileId !== newSettings.agentProfileId;
16338
- if (agentProfileIdChanged || modeChanged) {
16979
+ const disabledRulesChanged = JSON.stringify(oldSettings.disabledRuleFiles) !== JSON.stringify(newSettings.disabledRuleFiles);
16980
+ if (agentProfileIdChanged || modeChanged || disabledRulesChanged) {
16339
16981
  void this.sendContextFilesUpdated();
16340
16982
  }
16983
+ if (disabledRulesChanged) {
16984
+ void this.updateAgentEstimatedTokens();
16985
+ }
16341
16986
  }
16342
16987
  sendUpdateEnvVars(environmentVariables) {
16343
16988
  this.aiderManager.sendUpdateEnvVars(environmentVariables);
@@ -16614,6 +17259,18 @@ ${error.stderr}`,
16614
17259
  });
16615
17260
  this.eventManager.sendUpdatedFilesUpdated(this.project.baseDir, this.taskId, updatedFiles);
16616
17261
  }
17262
+ async sendSkillsUpdated() {
17263
+ const skills = await this.getSkills();
17264
+ this.eventManager.sendSkillsUpdated(this.project.baseDir, this.taskId, skills);
17265
+ }
17266
+ async initWorktree() {
17267
+ const branchName = this.generateBranchName();
17268
+ this.task.worktree = await this.worktreeManager.createWorktree(this.project.baseDir, this.taskId, branchName);
17269
+ const settings = this.store.getSettings();
17270
+ if (settings.taskSettings.worktreeSymlinkFolders && settings.taskSettings.worktreeSymlinkFolders.length > 0) {
17271
+ await this.worktreeManager.createSymlinks(this.project.baseDir, this.task.worktree.path, settings.taskSettings.worktreeSymlinkFolders);
17272
+ }
17273
+ }
16617
17274
  async applyWorkingMode(mode) {
16618
17275
  logger.info("Applying workingMode configuration", {
16619
17276
  baseDir: this.project.baseDir,
@@ -16624,17 +17281,15 @@ ${error.stderr}`,
16624
17281
  const currentWorktree = await this.worktreeManager.getTaskWorktree(this.project.baseDir, this.taskId);
16625
17282
  if (mode === "worktree") {
16626
17283
  if (!currentWorktree) {
16627
- const branchName = this.generateBranchName();
16628
- this.task.worktree = await this.worktreeManager.createWorktree(this.project.baseDir, this.taskId, branchName);
16629
- const settings = this.store.getSettings();
16630
- if (settings.taskSettings.worktreeSymlinkFolders && settings.taskSettings.worktreeSymlinkFolders.length > 0) {
16631
- await this.worktreeManager.createSymlinks(this.project.baseDir, this.task.worktree.path, settings.taskSettings.worktreeSymlinkFolders);
16632
- }
17284
+ await this.initWorktree();
16633
17285
  }
16634
17286
  this.task.workingMode = mode;
16635
17287
  } else if (mode === "local") {
16636
17288
  if (currentWorktree) {
16637
- await this.worktreeManager.removeWorktree(this.project.baseDir, currentWorktree);
17289
+ const isShared = this.project.isWorktreeSharedWithOtherTasks(currentWorktree.path, this.taskId);
17290
+ if (!isShared) {
17291
+ await this.worktreeManager.removeWorktree(this.project.baseDir, currentWorktree);
17292
+ }
16638
17293
  }
16639
17294
  this.task.worktree = void 0;
16640
17295
  this.task.lastMergeState = void 0;
@@ -16706,7 +17361,8 @@ Only answer with the commit message, nothing else.`,
16706
17361
  squash,
16707
17362
  effectiveCommitMessage || this.task.name || `Task ${this.taskId} changes`,
16708
17363
  targetBranch,
16709
- symlinkFolders
17364
+ symlinkFolders,
17365
+ this.task.worktree.baseCommit
16710
17366
  );
16711
17367
  await this.saveTask({ lastMergeState: mergeState });
16712
17368
  this.addLogMessage(
@@ -16728,6 +17384,47 @@ Only answer with the commit message, nothing else.`,
16728
17384
  await this.sendUpdatedFilesUpdated();
16729
17385
  await this.sendWorktreeIntegrationStatusUpdated();
16730
17386
  }
17387
+ async mergeAndSwitchToLocal(targetBranch) {
17388
+ if (!this.task.worktree) {
17389
+ throw new Error("No worktree exists for this task");
17390
+ }
17391
+ logger.info("Merging worktree and switching to local mode", {
17392
+ baseDir: this.project.baseDir,
17393
+ taskId: this.taskId
17394
+ });
17395
+ await this.waitForCurrentPromptToFinish();
17396
+ try {
17397
+ const effectiveTargetBranch = targetBranch || await this.worktreeManager.getProjectMainBranch(this.project.baseDir);
17398
+ this.addLogMessage("loading", `Merging worktree to ${effectiveTargetBranch} branch and switching to local mode...`);
17399
+ const settings = this.store.getSettings();
17400
+ const symlinkFolders = settings.taskSettings.worktreeSymlinkFolders || [];
17401
+ const mergeState = await this.worktreeManager.mergeWorktreeToMainWithUncommitted(
17402
+ this.project.baseDir,
17403
+ this.task.id,
17404
+ this.task.worktree.path,
17405
+ false,
17406
+ this.task.name || `Task ${this.taskId} changes`,
17407
+ targetBranch,
17408
+ symlinkFolders
17409
+ );
17410
+ await this.saveTask({ lastMergeState: mergeState });
17411
+ this.addLogMessage("info", `Successfully merged worktree to ${effectiveTargetBranch} branch`, true);
17412
+ await this.updateTask({ workingMode: "local" });
17413
+ } catch (error) {
17414
+ logger.error("Failed to merge worktree and switch to local:", { error });
17415
+ const isConflict = error instanceof GitError && (error.gitOutput?.toLowerCase().includes("resolve all conflicts") || error.message?.toLowerCase().includes("conflicts must be resolved first") || error.gitOutput?.toLowerCase().includes("conflicts must be resolved first"));
17416
+ this.addLogMessage(
17417
+ "error",
17418
+ isConflict ? "worktree.mergeConflicts" : error instanceof GitError ? error.getErrorDetails() : `Failed to merge worktree: ${error instanceof Error ? error.message : String(error)}`,
17419
+ true,
17420
+ void 0,
17421
+ isConflict ? ["rebase-worktree"] : void 0
17422
+ );
17423
+ await this.sendUpdatedFilesUpdated();
17424
+ await this.sendWorktreeIntegrationStatusUpdated();
17425
+ throw error;
17426
+ }
17427
+ }
16731
17428
  async applyUncommittedChanges(targetBranch) {
16732
17429
  if (!this.task.worktree) {
16733
17430
  throw new Error("No worktree exists for this task");
@@ -16857,10 +17554,18 @@ ${diff}
16857
17554
  taskId: this.taskId,
16858
17555
  amend
16859
17556
  });
17557
+ const beforeResult = await this.extensionManager.dispatchEvent("onBeforeCommit", { message, amend }, this.project, this);
17558
+ if (beforeResult.blocked) {
17559
+ logger.debug("Commit blocked by extension");
17560
+ return;
17561
+ }
17562
+ message = beforeResult.message;
17563
+ amend = beforeResult.amend;
16860
17564
  const taskDir = this.getTaskDir();
16861
17565
  await this.worktreeManager.commitChanges(taskDir, message, amend);
16862
17566
  await this.sendUpdatedFilesUpdated();
16863
17567
  await this.sendWorktreeIntegrationStatusUpdated();
17568
+ await this.extensionManager.dispatchEvent("onAfterCommit", { message, amend }, this.project, this);
16864
17569
  }
16865
17570
  async getWorktreeIntegrationStatus(targetBranch) {
16866
17571
  if (!this.task.worktree) {
@@ -16868,12 +17573,16 @@ ${diff}
16868
17573
  }
16869
17574
  const effectiveTargetBranch = targetBranch || await this.worktreeManager.getProjectMainBranch(this.project.baseDir);
16870
17575
  const worktreePath = this.task.worktree.path;
17576
+ const settings = this.store.getSettings();
17577
+ const symlinkFolders = settings.taskSettings.worktreeSymlinkFolders || [];
16871
17578
  const [unmergedWork, predictedConflicts, rebaseState] = await Promise.all([
16872
- this.worktreeManager.checkWorktreeForUnmergedWork(this.project.baseDir, worktreePath, effectiveTargetBranch),
17579
+ this.worktreeManager.checkWorktreeForUnmergedWork(this.project.baseDir, worktreePath, effectiveTargetBranch, symlinkFolders),
16873
17580
  this.worktreeManager.checkForRebaseConflicts(worktreePath, effectiveTargetBranch),
16874
17581
  this.worktreeManager.getRebaseState(worktreePath)
16875
17582
  ]);
16876
17583
  return {
17584
+ currentBranch: this.task.worktree.branch || "",
17585
+ baseBranch: this.task.worktree.baseBranch || "",
16877
17586
  targetBranch: effectiveTargetBranch,
16878
17587
  aheadCommits: {
16879
17588
  count: unmergedWork.unmergedCommitCount,
@@ -16900,22 +17609,24 @@ ${diff}
16900
17609
  await this.waitForCurrentPromptToFinish();
16901
17610
  try {
16902
17611
  this.addLogMessage("loading", `Rebasing worktree from ${effectiveFromBranch}...`);
16903
- const { success, error } = await this.worktreeManager.rebaseMainIntoWorktree(this.task.worktree.path, effectiveFromBranch);
17612
+ const { success, error } = await this.worktreeManager.rebaseMainIntoWorktree(this.task.worktree.path, effectiveFromBranch, this.task.worktree.baseCommit);
16904
17613
  if (success) {
17614
+ const newHead = await this.worktreeManager.getHeadCommit(this.task.worktree.path);
17615
+ if (newHead) {
17616
+ await this.saveTask({ worktree: { ...this.task.worktree, baseCommit: newHead, baseBranch: effectiveFromBranch } });
17617
+ }
16905
17618
  this.addLogMessage("info", "Worktree rebased successfully", true);
16906
17619
  return;
16907
17620
  }
16908
17621
  if (error) {
17622
+ this.addLogMessage("loading", void 0, true);
16909
17623
  const isConflict = error.gitOutput?.includes("Resolve all conflicts");
16910
- this.addLogMessage(
16911
- "error",
16912
- isConflict ? "worktree.rebaseConflicts" : error.getErrorDetails(),
16913
- true,
16914
- void 0,
16915
- isConflict ? ["abort-rebase", "resolve-conflicts-with-agent"] : void 0
16916
- );
17624
+ if (!isConflict) {
17625
+ this.addLogMessage("error", error.getErrorDetails(), true);
17626
+ }
16917
17627
  }
16918
17628
  } catch (error) {
17629
+ this.addLogMessage("loading", void 0, true);
16919
17630
  logger.error("Failed to rebase worktree:", {
16920
17631
  error: error instanceof Error ? error.message : String(error)
16921
17632
  });
@@ -16944,11 +17655,26 @@ ${diff}
16944
17655
  await this.sendUpdatedFilesUpdated();
16945
17656
  await this.sendWorktreeIntegrationStatusUpdated();
16946
17657
  }
17658
+ async renameWorktreeBranch(newBranchName) {
17659
+ if (!this.task.worktree) {
17660
+ throw new Error("No worktree exists for this task");
17661
+ }
17662
+ const oldBranchName = this.task.worktree.branch;
17663
+ if (!oldBranchName) {
17664
+ throw new Error("Cannot determine current branch name");
17665
+ }
17666
+ const actualBranchName = await this.worktreeManager.renameBranch(this.project.baseDir, oldBranchName, newBranchName);
17667
+ this.task.worktree.branch = actualBranchName;
17668
+ await this.saveTask({ worktree: this.task.worktree });
17669
+ void this.sendWorktreeIntegrationStatusUpdated();
17670
+ }
16947
17671
  async executeConflictResolution(directoryPath, directoryName) {
16948
17672
  const activeProfile = await this.getTaskAgentProfile();
16949
17673
  if (!activeProfile) {
16950
17674
  throw new Error("No active agent profile found");
16951
17675
  }
17676
+ const previousTaskState = this.task.state;
17677
+ await this.saveTask({ state: DefaultTaskState.InProgress });
16952
17678
  try {
16953
17679
  this.addLogMessage("loading", `Resolving conflicts in ${directoryName}...`);
16954
17680
  const files = await this.worktreeManager.listConflictedFiles(directoryPath);
@@ -17033,13 +17759,8 @@ ${diff}
17033
17759
  }
17034
17760
  });
17035
17761
  await Promise.all(resolutionPromises);
17036
- if (interruptedCount === 0) {
17037
- this.addLogMessage("info", "Conflicts resolved and staged. You can now continue the rebase.", true, void 0, ["continue-rebase", "abort-rebase"]);
17038
- } else if (interruptedCount < files.length) {
17039
- this.addLogMessage("warning", "Some conflicts were resolved, but some were interrupted. You can continue the rebase.", true, void 0, [
17040
- "continue-rebase",
17041
- "abort-rebase"
17042
- ]);
17762
+ if (interruptedCount > 0 && interruptedCount < files.length) {
17763
+ this.addLogMessage("warning", "Some conflicts were resolved, but some were interrupted. You can continue the rebase.", true, void 0, []);
17043
17764
  }
17044
17765
  } catch (error) {
17045
17766
  logger.error("Failed to resolve conflicts with agent:", error);
@@ -17048,6 +17769,8 @@ ${diff}
17048
17769
  error instanceof GitError ? error.getErrorDetails() : `Failed to resolve conflicts with agent: ${error instanceof Error ? error.message : String(error)}`,
17049
17770
  true
17050
17771
  );
17772
+ } finally {
17773
+ await this.saveTask({ state: previousTaskState });
17051
17774
  }
17052
17775
  await this.sendWorktreeIntegrationStatusUpdated();
17053
17776
  }
@@ -17084,17 +17807,17 @@ ${diff}
17084
17807
  this.addLogMessage("loading", "Continuing rebase...");
17085
17808
  await this.worktreeManager.continueRebase(this.task.worktree.path);
17086
17809
  await this.saveTask({ lastMergeState: void 0 });
17087
- this.addLogMessage("info", "Rebase continued", true);
17810
+ this.addLogMessage("info", "Rebase completed", true);
17088
17811
  } catch (error) {
17089
17812
  logger.error("Failed to continue rebase:", error);
17090
17813
  const isConflict = error instanceof GitError && error.gitOutput?.includes("Resolve all conflicts manually");
17091
- this.addLogMessage(
17092
- "error",
17093
- isConflict ? "worktree.rebaseConflicts" : error instanceof GitError ? error.getErrorDetails() : `Failed to continue rebase: ${error instanceof Error ? error.message : String(error)}`,
17094
- true,
17095
- void 0,
17096
- isConflict ? ["abort-rebase", "resolve-conflicts-with-agent"] : void 0
17097
- );
17814
+ if (!isConflict) {
17815
+ this.addLogMessage(
17816
+ "error",
17817
+ error instanceof GitError ? error.getErrorDetails() : `Failed to continue rebase: ${error instanceof Error ? error.message : String(error)}`,
17818
+ true
17819
+ );
17820
+ }
17098
17821
  }
17099
17822
  await this.sendUpdatedFilesUpdated();
17100
17823
  await this.sendWorktreeIntegrationStatusUpdated();
@@ -17158,50 +17881,53 @@ ${diff}
17158
17881
  async generateText(modelId, systemPrompt, prompt) {
17159
17882
  return this.agent.generateText(modelId, systemPrompt, prompt, this.getProjectDir());
17160
17883
  }
17161
- async runCodeInlineRequest(filename, lineNumber, userComment, createNewTask, contextSize = 5) {
17162
- const filePath = path.isAbsolute(filename) ? filename : path.join(this.getTaskDir(), filename);
17163
- const fileExtension = path.extname(filename).slice(1) || "";
17164
- let contextLines = [];
17165
- try {
17166
- const fileContent = await fs.readFile(filePath, "utf-8");
17167
- const lines = fileContent.split("\n");
17168
- const startLine = Math.max(0, lineNumber - contextSize - 1);
17169
- const endLine = Math.min(lines.length, lineNumber + contextSize);
17170
- contextLines = lines.slice(startLine, endLine).map((content, index) => ({
17171
- lineNumber: startLine + index + 1,
17172
- content
17173
- }));
17174
- } catch (error) {
17175
- logger.warn("Failed to read file for context extraction", {
17176
- filePath,
17177
- error
17178
- });
17179
- }
17180
- const prompt = await this.promptsManager.getCodeInlineRequestPrompt(this, {
17181
- filename,
17182
- lineNumber,
17183
- fileExtension,
17184
- contextLines,
17185
- userComment
17186
- });
17884
+ async runCodeChangeRequests(requests, contextSize = 5, createNewTask) {
17187
17885
  const mode = this.getCurrentMode();
17886
+ const promptRequests = await Promise.all(
17887
+ requests.map(async (request) => {
17888
+ const filePath = path.isAbsolute(request.filename) ? request.filename : path.join(this.getTaskDir(), request.filename);
17889
+ const fileExtension = path.extname(request.filename).slice(1) || "";
17890
+ let contextLines = [];
17891
+ try {
17892
+ const fileContent = await fs.readFile(filePath, "utf-8");
17893
+ const lines = fileContent.split("\n");
17894
+ const startLine = Math.max(0, request.lineNumber - contextSize - 1);
17895
+ const endLine = Math.min(lines.length, request.lineNumber + contextSize);
17896
+ contextLines = lines.slice(startLine, endLine).map((content, index) => ({
17897
+ lineNumber: startLine + index + 1,
17898
+ content
17899
+ }));
17900
+ } catch (error) {
17901
+ logger.warn("Failed to read file for context extraction", {
17902
+ filePath,
17903
+ error
17904
+ });
17905
+ }
17906
+ return {
17907
+ filename: request.filename,
17908
+ lineNumber: request.lineNumber,
17909
+ fileExtension,
17910
+ contextLines,
17911
+ userComment: request.userComment
17912
+ };
17913
+ })
17914
+ );
17915
+ const prompt = await this.promptsManager.getCodeChangeRequestsPrompt(this, {
17916
+ requests: promptRequests
17917
+ });
17188
17918
  if (!createNewTask) {
17919
+ const uniqueFiles = [...new Set(requests.map((r) => r.filename))];
17189
17920
  if (AIDER_MODES.includes(mode)) {
17190
- await this.addFiles({
17191
- path: filename
17192
- });
17921
+ for (const filename of uniqueFiles) {
17922
+ await this.addFiles({ path: filename });
17923
+ }
17193
17924
  }
17194
17925
  void this.runPrompt(prompt, mode, false);
17195
17926
  return;
17196
17927
  }
17197
- this.eventManager.sendLog({
17198
- baseDir: this.project.baseDir,
17199
- taskId: INTERNAL_TASK_ID,
17200
- level: "loading",
17201
- message: "Creating task for inline code request..."
17202
- });
17928
+ const taskName = requests.length === 1 ? `${requests[0].filename}:${requests[0].lineNumber}` : `${requests.length} change requests`;
17203
17929
  const newTaskData = await this.project.createNewTask({
17204
- name: `${filename}:${lineNumber}`,
17930
+ name: taskName,
17205
17931
  sendEvent: false,
17206
17932
  autoApprove: true,
17207
17933
  activate: true,
@@ -17215,9 +17941,10 @@ ${diff}
17215
17941
  }
17216
17942
  await newTask.init();
17217
17943
  if (AIDER_MODES.includes(mode)) {
17218
- await newTask.addFiles({
17219
- path: filename
17220
- });
17944
+ const uniqueFiles = [...new Set(requests.map((r) => r.filename))];
17945
+ for (const filename of uniqueFiles) {
17946
+ await newTask.addFiles({ path: filename });
17947
+ }
17221
17948
  }
17222
17949
  this.eventManager.sendTaskCreated(newTask.task, true);
17223
17950
  void newTask.runPrompt(prompt, mode, false);
@@ -17379,6 +18106,9 @@ class Project {
17379
18106
  if (!parentTask) {
17380
18107
  throw new Error(`Parent task with id ${normalizedParams.parentId} not found`);
17381
18108
  }
18109
+ if (!parentTask.task.createdAt) {
18110
+ await parentTask.saveTask();
18111
+ }
17382
18112
  }
17383
18113
  const sourceTask = parentTask || this.getMostRecentTask();
17384
18114
  const defaultWorkingMode = this.store.getSettings().taskSettings.defaultWorkingMode || "local";
@@ -17603,6 +18333,17 @@ class Project {
17603
18333
  getAgentProfiles() {
17604
18334
  return this.agentProfileManager.getProjectProfiles(this);
17605
18335
  }
18336
+ /**
18337
+ * Checks if any other task (excluding the specified taskId) uses the given worktree path.
18338
+ */
18339
+ isWorktreeSharedWithOtherTasks(worktreePath, excludeTaskId) {
18340
+ for (const [id, task] of this.tasks.entries()) {
18341
+ if (id !== excludeTaskId && task.task.worktree?.path === worktreePath) {
18342
+ return true;
18343
+ }
18344
+ }
18345
+ return false;
18346
+ }
17606
18347
  async deleteTaskInternal(taskId) {
17607
18348
  const taskDir = path.join(this.baseDir, ".aider-desk", "tasks", taskId);
17608
18349
  const task = this.tasks.get(taskId);
@@ -17611,6 +18352,19 @@ class Project {
17611
18352
  this.tasks.delete(taskId);
17612
18353
  this.eventManager.sendTaskDeleted(task.task);
17613
18354
  }
18355
+ const taskData = task?.task;
18356
+ if (taskData?.worktree && !this.isWorktreeSharedWithOtherTasks(taskData.worktree.path, taskId)) {
18357
+ try {
18358
+ await this.worktreeManager.removeWorktree(this.baseDir, taskData.worktree);
18359
+ } catch (error) {
18360
+ logger.warn("Failed to remove worktree during task deletion", {
18361
+ baseDir: this.baseDir,
18362
+ taskId,
18363
+ worktreePath: taskData.worktree.path,
18364
+ error: error instanceof Error ? error.message : String(error)
18365
+ });
18366
+ }
18367
+ }
17614
18368
  await fs.rm(taskDir, { recursive: true, force: true });
17615
18369
  }
17616
18370
  async deleteTask(taskId) {
@@ -17645,8 +18399,12 @@ class Project {
17645
18399
  if (!sourceTask) {
17646
18400
  throw new Error(`Task with id ${taskId} not found`);
17647
18401
  }
18402
+ const hasWorktree = sourceTask.task.worktree && sourceTask.task.workingMode === "worktree";
17648
18403
  const newTask = await this.prepareTask(void 0, {
17649
18404
  ...sourceTask.task,
18405
+ // When the source task has a worktree, make the duplicate a subtask
18406
+ // so both tasks sharing the same worktree are clearly related
18407
+ ...hasWorktree ? { parentId: sourceTask.task.parentId || taskId } : {},
17650
18408
  state: sourceTask.task.state === DefaultTaskState.InProgress ? DefaultTaskState.Todo : sourceTask.task.state
17651
18409
  });
17652
18410
  await newTask.init();
@@ -17858,6 +18616,15 @@ class EventManager {
17858
18616
  this.sendToWindows("updated-files-updated", data);
17859
18617
  this.broadcastToEventConnectors("updated-files-updated", data);
17860
18618
  }
18619
+ sendSkillsUpdated(baseDir, taskId, skills) {
18620
+ const data = {
18621
+ baseDir,
18622
+ taskId,
18623
+ skills
18624
+ };
18625
+ this.sendToWindows("skills-updated", data);
18626
+ this.broadcastToEventConnectors("skills-updated", data);
18627
+ }
17861
18628
  // Response events
17862
18629
  sendResponseChunk(data) {
17863
18630
  this.sendToWindows("response-chunk", data);
@@ -18361,8 +19128,7 @@ const loadAnthropicCompatibleModels = async (profile, settings) => {
18361
19128
  const models = data.data?.map((model) => {
18362
19129
  return {
18363
19130
  id: model.id,
18364
- providerId: profile.id,
18365
- temperature: DEFAULT_MODEL_TEMPERATURE
19131
+ providerId: profile.id
18366
19132
  };
18367
19133
  }) || [];
18368
19134
  logger.info(`Loaded ${models.length} Anthropic-compatible models for profile ${profile.id}`);
@@ -18475,6 +19241,11 @@ const AUGGIE_MODELS = [
18475
19241
  maxInputTokens: 2e5,
18476
19242
  maxOutputTokensLimit: 32768
18477
19243
  },
19244
+ {
19245
+ id: "claude-opus-4-7",
19246
+ maxInputTokens: 2e5,
19247
+ maxOutputTokensLimit: 32768
19248
+ },
18478
19249
  { id: "gpt-5-1", maxInputTokens: 2e5, maxOutputTokensLimit: 16384 },
18479
19250
  { id: "gpt-5-2", maxInputTokens: 2e5, maxOutputTokensLimit: 16384 },
18480
19251
  { id: "gpt-5-4", maxInputTokens: 2e5, maxOutputTokensLimit: 16384 }
@@ -18786,8 +19557,7 @@ const loadBedrockModels = async (profile, settings) => {
18786
19557
  if (response.authorizationStatus === "AUTHORIZED" && response.entitlementAvailability === "AVAILABLE" && response.regionAvailability === "AVAILABLE") {
18787
19558
  availableModels.push({
18788
19559
  id: inferenceProfile.inferenceProfileId,
18789
- providerId: profile.id,
18790
- temperature: DEFAULT_MODEL_TEMPERATURE
19560
+ providerId: profile.id
18791
19561
  });
18792
19562
  logger.debug(`Profile ${inferenceProfile.inferenceProfileId} with model ${modelId} is available and authorized`);
18793
19563
  } else {
@@ -18941,8 +19711,7 @@ const loadCerebrasModels = async (profile, settings) => {
18941
19711
  return {
18942
19712
  id: model.id,
18943
19713
  providerId: profile.id,
18944
- maxInputTokens: model.max_context_length,
18945
- temperature: DEFAULT_MODEL_TEMPERATURE
19714
+ maxInputTokens: model.max_context_length
18946
19715
  };
18947
19716
  }) || [];
18948
19717
  logger.info(`Loaded ${models.length} Cerebras models for profile ${profile.id}`);
@@ -19212,8 +19981,7 @@ const loadDeepseekModels = async (profile, settings) => {
19212
19981
  const models = data.data?.map((m) => {
19213
19982
  return {
19214
19983
  id: m.id,
19215
- providerId: profile.id,
19216
- temperature: DEFAULT_MODEL_TEMPERATURE
19984
+ providerId: profile.id
19217
19985
  };
19218
19986
  }) || [];
19219
19987
  logger.info(`Loaded ${models.length} DeepSeek models for profile ${profile.id}`);
@@ -19257,6 +20025,34 @@ const createDeepseekLlm = (profile, model, settings, projectDir) => {
19257
20025
  });
19258
20026
  return deepseekProvider(model.id);
19259
20027
  };
20028
+ const getDeepseekProviderOptions = (llmProvider, model) => {
20029
+ if (!isDeepseekProvider(llmProvider)) {
20030
+ return void 0;
20031
+ }
20032
+ const providerOverrides = model.providerOverrides;
20033
+ const thinkingEnabled = providerOverrides?.thinkingEnabled ?? llmProvider.thinkingEnabled ?? true;
20034
+ const reasoningEffort = providerOverrides?.reasoningEffort ?? llmProvider.reasoningEffort ?? "high";
20035
+ return {
20036
+ deepseek: {
20037
+ thinking: { type: thinkingEnabled ? "enabled" : "disabled" },
20038
+ ...thinkingEnabled && { reasoningEffort }
20039
+ }
20040
+ };
20041
+ };
20042
+ const getDeepseekProviderParameters = (llmProvider, model) => {
20043
+ if (!isDeepseekProvider(llmProvider)) {
20044
+ return {};
20045
+ }
20046
+ const providerOverrides = model.providerOverrides;
20047
+ const thinkingEnabled = providerOverrides?.thinkingEnabled ?? llmProvider.thinkingEnabled ?? true;
20048
+ if (thinkingEnabled) {
20049
+ return {
20050
+ temperature: void 0,
20051
+ topP: void 0
20052
+ };
20053
+ }
20054
+ return {};
20055
+ };
19260
20056
  const deepseekProviderStrategy = {
19261
20057
  // Core LLM functions
19262
20058
  createLlm: createDeepseekLlm,
@@ -19265,7 +20061,9 @@ const deepseekProviderStrategy = {
19265
20061
  loadModels: loadDeepseekModels,
19266
20062
  hasEnvVars: hasDeepseekEnvVars,
19267
20063
  getAiderMapping: getDeepseekAiderMapping,
19268
- getModelInfo: getDefaultModelInfo
20064
+ getModelInfo: getDefaultModelInfo,
20065
+ getProviderOptions: getDeepseekProviderOptions,
20066
+ getProviderParameters: getDeepseekProviderParameters
19269
20067
  };
19270
20068
  const loadGeminiModels = async (profile, settings) => {
19271
20069
  if (!isGeminiProvider(profile.provider)) {
@@ -19619,8 +20417,7 @@ const loadGpustackModels = async (profile, settings) => {
19619
20417
  id: model.name,
19620
20418
  providerId: profile.id,
19621
20419
  // Extract max_model_len from meta if available
19622
- maxInputTokens: model.meta?.max_model_len,
19623
- temperature: DEFAULT_MODEL_TEMPERATURE
20420
+ maxInputTokens: model.meta?.max_model_len
19624
20421
  };
19625
20422
  }) || [];
19626
20423
  logger.info(`Loaded ${models.length} GPUStack models for profile ${profile.id}`);
@@ -19740,8 +20537,7 @@ const loadGroqModels = async (profile, settings) => {
19740
20537
  const models = data.data?.map((model) => {
19741
20538
  return {
19742
20539
  id: model.id,
19743
- providerId: profile.id,
19744
- temperature: DEFAULT_MODEL_TEMPERATURE
20540
+ providerId: profile.id
19745
20541
  };
19746
20542
  }) || [];
19747
20543
  logger.info(`Loaded ${models.length} Groq models for profile ${profile.id}`);
@@ -19892,7 +20688,6 @@ const alibabaPlanProviderStrategy = {
19892
20688
  getProviderOptions: getAlibabaPlanProviderOptions
19893
20689
  };
19894
20690
  const KIMI_PLAN_BASE_URL = "https://api.kimi.com/coding/v1";
19895
- const KIMI_PLAN_MODEL_ID = "k2p5";
19896
20691
  const loadKimiPlanModels = async (profile, settings) => {
19897
20692
  if (!isKimiPlanProvider(profile.provider)) {
19898
20693
  return { models: [], success: false };
@@ -19906,7 +20701,19 @@ const loadKimiPlanModels = async (profile, settings) => {
19906
20701
  }
19907
20702
  const models = [
19908
20703
  {
19909
- id: KIMI_PLAN_MODEL_ID,
20704
+ id: "kimi-k2-thinking",
20705
+ providerId: profile.id,
20706
+ maxInputTokens: 262144,
20707
+ maxOutputTokensLimit: 32768
20708
+ },
20709
+ {
20710
+ id: "k2p5",
20711
+ providerId: profile.id,
20712
+ maxInputTokens: 262144,
20713
+ maxOutputTokensLimit: 32768
20714
+ },
20715
+ {
20716
+ id: "k2p6",
19910
20717
  providerId: profile.id,
19911
20718
  maxInputTokens: 262144,
19912
20719
  maxOutputTokensLimit: 32768
@@ -20129,8 +20936,7 @@ const loadLmStudioModels = async (profile, settings) => {
20129
20936
  return {
20130
20937
  id: model.id,
20131
20938
  providerId: profile.id,
20132
- maxInputTokens: model.max_context_length,
20133
- temperature: DEFAULT_MODEL_TEMPERATURE
20939
+ maxInputTokens: model.max_context_length
20134
20940
  };
20135
20941
  }) || [];
20136
20942
  logger.info(`Loaded ${models.length} LM Studio models from ${effectiveBaseUrl} for profile ${profile.id}`);
@@ -20210,7 +21016,63 @@ const loadMinimaxModels = async (profile) => {
20210
21016
  }
20211
21017
  const hardcodedModels = [
20212
21018
  {
20213
- id: "MiniMax-M2",
21019
+ id: "MiniMax-M2.7",
21020
+ providerId: profile.id,
21021
+ maxInputTokens: 204800,
21022
+ maxOutputTokensLimit: 131072,
21023
+ inputCostPerToken: 3e-7,
21024
+ // 0.3 per 1M tokens
21025
+ outputCostPerToken: 12e-7,
21026
+ // 1.2 per 1M tokens
21027
+ cacheReadInputTokenCost: 6e-8,
21028
+ // 0.06 per 1M tokens
21029
+ cacheWriteInputTokenCost: 375e-9
21030
+ // 0.375 per 1M tokens
21031
+ },
21032
+ {
21033
+ id: "MiniMax-M2.7-highspeed",
21034
+ providerId: profile.id,
21035
+ maxInputTokens: 204800,
21036
+ maxOutputTokensLimit: 131072,
21037
+ inputCostPerToken: 6e-7,
21038
+ // 0.6 per 1M tokens
21039
+ outputCostPerToken: 24e-7,
21040
+ // 2.4 per 1M tokens
21041
+ cacheReadInputTokenCost: 6e-8,
21042
+ // 0.06 per 1M tokens
21043
+ cacheWriteInputTokenCost: 375e-9
21044
+ // 0.375 per 1M tokens
21045
+ },
21046
+ {
21047
+ id: "MiniMax-M2.5",
21048
+ providerId: profile.id,
21049
+ maxInputTokens: 204800,
21050
+ maxOutputTokensLimit: 131072,
21051
+ inputCostPerToken: 3e-7,
21052
+ // 0.3 per 1M tokens
21053
+ outputCostPerToken: 12e-7,
21054
+ // 1.2 per 1M tokens
21055
+ cacheReadInputTokenCost: 3e-8,
21056
+ // 0.03 per 1M tokens
21057
+ cacheWriteInputTokenCost: 375e-9
21058
+ // 0.375 per 1M tokens
21059
+ },
21060
+ {
21061
+ id: "MiniMax-M2.5-highspeed",
21062
+ providerId: profile.id,
21063
+ maxInputTokens: 204800,
21064
+ maxOutputTokensLimit: 131072,
21065
+ inputCostPerToken: 6e-7,
21066
+ // 0.6 per 1M tokens
21067
+ outputCostPerToken: 24e-7,
21068
+ // 2.4 per 1M tokens
21069
+ cacheReadInputTokenCost: 3e-8,
21070
+ // 0.03 per 1M tokens
21071
+ cacheWriteInputTokenCost: 375e-9
21072
+ // 0.375 per 1M tokens
21073
+ },
21074
+ {
21075
+ id: "MiniMax-M2.1",
20214
21076
  providerId: profile.id,
20215
21077
  maxInputTokens: 204800,
20216
21078
  maxOutputTokensLimit: 131072,
@@ -20220,12 +21082,25 @@ const loadMinimaxModels = async (profile) => {
20220
21082
  // 1.2 per 1M tokens
20221
21083
  cacheReadInputTokenCost: 3e-8,
20222
21084
  // 0.03 per 1M tokens
20223
- cacheWriteInputTokenCost: 4e-8,
20224
- // 0.04 per 1M tokens
20225
- temperature: 0.5
21085
+ cacheWriteInputTokenCost: 375e-9
21086
+ // 0.375 per 1M tokens
21087
+ },
21088
+ {
21089
+ id: "MiniMax-M2.1-highspeed",
21090
+ providerId: profile.id,
21091
+ maxInputTokens: 204800,
21092
+ maxOutputTokensLimit: 131072,
21093
+ inputCostPerToken: 6e-7,
21094
+ // 0.6 per 1M tokens
21095
+ outputCostPerToken: 24e-7,
21096
+ // 2.4 per 1M tokens
21097
+ cacheReadInputTokenCost: 3e-8,
21098
+ // 0.03 per 1M tokens
21099
+ cacheWriteInputTokenCost: 375e-9
21100
+ // 0.375 per 1M tokens
20226
21101
  },
20227
21102
  {
20228
- id: "MiniMax-M2-Stable",
21103
+ id: "MiniMax-M2",
20229
21104
  providerId: profile.id,
20230
21105
  maxInputTokens: 204800,
20231
21106
  maxOutputTokensLimit: 131072,
@@ -20235,9 +21110,8 @@ const loadMinimaxModels = async (profile) => {
20235
21110
  // 1.2 per 1M tokens
20236
21111
  cacheReadInputTokenCost: 3e-8,
20237
21112
  // 0.03 per 1M tokens
20238
- cacheWriteInputTokenCost: 4e-8,
20239
- // 0.04 per 1M tokens
20240
- temperature: 0.5
21113
+ cacheWriteInputTokenCost: 375e-9
21114
+ // 0.375 per 1M tokens
20241
21115
  }
20242
21116
  ];
20243
21117
  return { models: hardcodedModels, success: true };
@@ -20333,6 +21207,90 @@ const minimaxProviderStrategy = {
20333
21207
  // Configuration helpers
20334
21208
  getCacheControl: getMinimaxCacheControl
20335
21209
  };
21210
+ const loadMistralModels = async (profile, settings) => {
21211
+ if (!isMistralProvider(profile.provider)) {
21212
+ return { models: [], success: false };
21213
+ }
21214
+ const provider = profile.provider;
21215
+ const apiKey = provider.apiKey || "";
21216
+ const apiKeyEnv = getEffectiveEnvironmentVariable("MISTRAL_API_KEY", settings);
21217
+ const effectiveApiKey = apiKey || apiKeyEnv?.value || "";
21218
+ if (!effectiveApiKey) {
21219
+ const errorMsg = "Mistral API key is required. Please set it in Providers settings or via MISTRAL_API_KEY environment variable.";
21220
+ logger.debug(errorMsg);
21221
+ return { models: [], success: false };
21222
+ }
21223
+ try {
21224
+ const response = await fetch("https://api.mistral.ai/v1/models", {
21225
+ headers: { Authorization: `Bearer ${effectiveApiKey}` }
21226
+ });
21227
+ if (!response.ok) {
21228
+ const errorMsg = `Mistral models API response failed: ${response.status} ${response.statusText} ${await response.text()}`;
21229
+ logger.error(errorMsg, {
21230
+ status: response.status,
21231
+ statusText: response.statusText
21232
+ });
21233
+ return { models: [], success: false, error: errorMsg };
21234
+ }
21235
+ const data = await response.json();
21236
+ const models = data.data?.map((model) => {
21237
+ return {
21238
+ id: model.id,
21239
+ providerId: profile.id,
21240
+ temperature: 0.7
21241
+ };
21242
+ }) || [];
21243
+ logger.info(`Loaded ${models.length} Mistral models for profile ${profile.id}`);
21244
+ return { models, success: true };
21245
+ } catch (error) {
21246
+ const errorMsg = typeof error === "string" ? error : error instanceof Error ? error.message : "Unknown error loading Mistral models";
21247
+ logger.error("Error loading Mistral models:", error);
21248
+ return { models: [], success: false, error: errorMsg };
21249
+ }
21250
+ };
21251
+ const hasMistralEnvVars = (settings) => {
21252
+ return !!getEffectiveEnvironmentVariable("MISTRAL_API_KEY", settings, void 0)?.value;
21253
+ };
21254
+ const getMistralAiderMapping = (provider, modelId) => {
21255
+ const mistralProvider = provider.provider;
21256
+ const envVars = {};
21257
+ if (mistralProvider.apiKey) {
21258
+ envVars.MISTRAL_API_KEY = mistralProvider.apiKey;
21259
+ }
21260
+ return {
21261
+ modelName: `mistral/${modelId}`,
21262
+ environmentVariables: envVars
21263
+ };
21264
+ };
21265
+ const createMistralLlm = (profile, model, settings, projectDir) => {
21266
+ const provider = profile.provider;
21267
+ let apiKey = provider.apiKey;
21268
+ if (!apiKey) {
21269
+ const effectiveVar = getEffectiveEnvironmentVariable("MISTRAL_API_KEY", settings, projectDir);
21270
+ if (effectiveVar) {
21271
+ apiKey = effectiveVar.value;
21272
+ logger.debug(`Loaded MISTRAL_API_KEY from ${effectiveVar.source}`);
21273
+ }
21274
+ }
21275
+ if (!apiKey) {
21276
+ throw new Error("Mistral API key is required in Providers settings or Aider environment variables (MISTRAL_API_KEY)");
21277
+ }
21278
+ const mistralProvider = mistral.createMistral({
21279
+ apiKey,
21280
+ headers: profile.headers
21281
+ });
21282
+ return mistralProvider(model.id);
21283
+ };
21284
+ const mistralProviderStrategy = {
21285
+ // Core LLM functions
21286
+ createLlm: createMistralLlm,
21287
+ getUsageReport: getDefaultUsageReport,
21288
+ // Model discovery functions
21289
+ loadModels: loadMistralModels,
21290
+ hasEnvVars: hasMistralEnvVars,
21291
+ getAiderMapping: getMistralAiderMapping,
21292
+ getModelInfo: getDefaultModelInfo
21293
+ };
20336
21294
  const loadOllamaModels = async (profile, settings) => {
20337
21295
  if (!isOllamaProvider(profile.provider)) {
20338
21296
  return { models: [], success: false };
@@ -20359,8 +21317,7 @@ const loadOllamaModels = async (profile, settings) => {
20359
21317
  const models = data?.models?.map((m) => {
20360
21318
  return {
20361
21319
  id: m.name,
20362
- providerId: profile.id,
20363
- temperature: DEFAULT_MODEL_TEMPERATURE
21320
+ providerId: profile.id
20364
21321
  };
20365
21322
  }) || [];
20366
21323
  logger.info(`Loaded ${models.length} Ollama models from ${effectiveBaseUrl} for profile ${profile.id}`);
@@ -20698,8 +21655,7 @@ const loadOpenaiCompatibleModels = async (profile, settings) => {
20698
21655
  const models = data.data?.map((model) => {
20699
21656
  return {
20700
21657
  id: model.id,
20701
- providerId: profile.id,
20702
- temperature: DEFAULT_MODEL_TEMPERATURE
21658
+ providerId: profile.id
20703
21659
  };
20704
21660
  }) || [];
20705
21661
  logger.info(`Loaded ${models.length} OpenAI-compatible models for profile ${profile.id}`);
@@ -20818,7 +21774,7 @@ const getDefaultModelTemperature$2 = (modelId) => {
20818
21774
  if (modelId.includes("glm-")) {
20819
21775
  return 0.7;
20820
21776
  }
20821
- return DEFAULT_MODEL_TEMPERATURE;
21777
+ return void 0;
20822
21778
  };
20823
21779
  const loadOpencodeModels = async (profile, settings) => {
20824
21780
  if (!isOpenCodeProvider(profile.provider)) {
@@ -20949,7 +21905,7 @@ const getDefaultModelTemperature$1 = (modelId) => {
20949
21905
  if (modelId.includes("qwen")) {
20950
21906
  return 0.55;
20951
21907
  }
20952
- return DEFAULT_MODEL_TEMPERATURE;
21908
+ return void 0;
20953
21909
  };
20954
21910
  const loadOpenrouterModels = async (profile, settings) => {
20955
21911
  if (!isOpenRouterProvider(profile.provider)) {
@@ -21074,9 +22030,9 @@ const getOpenRouterUsageReport = (task, provider, model, usage, providerMetadata
21074
22030
  agentTotalCost: task.task.agentTotalCost + messageCost
21075
22031
  };
21076
22032
  };
21077
- const getOpenRouterCacheControl = (profile, llmProvider) => {
22033
+ const getOpenRouterCacheControl = (llmProvider, model) => {
21078
22034
  if (isOpenRouterProvider(llmProvider)) {
21079
- if (profile.model?.startsWith("anthropic/")) {
22035
+ if (model.id?.startsWith("anthropic/")) {
21080
22036
  return {
21081
22037
  providerOptions: {
21082
22038
  openrouter: {
@@ -21113,7 +22069,7 @@ const getDefaultModelTemperature = (modelId) => {
21113
22069
  if (modelId.includes("qwen")) {
21114
22070
  return 0.55;
21115
22071
  }
21116
- return DEFAULT_MODEL_TEMPERATURE;
22072
+ return void 0;
21117
22073
  };
21118
22074
  const loadRequestyModels = async (profile, settings) => {
21119
22075
  if (!isRequestyProvider(profile.provider)) {
@@ -21265,9 +22221,9 @@ const normalizeRequestyMessages = (_provider, model, messages) => {
21265
22221
  }
21266
22222
  return messages;
21267
22223
  };
21268
- const getRequestyCacheControl = (profile, llmProvider) => {
22224
+ const getRequestyCacheControl = (llmProvider, model) => {
21269
22225
  if (isRequestyProvider(llmProvider) && !llmProvider.useAutoCache) {
21270
- if (profile.model?.startsWith("anthropic/")) {
22226
+ if (model.id?.startsWith("anthropic/")) {
21271
22227
  return {
21272
22228
  providerOptions: {
21273
22229
  requesty: {
@@ -21317,8 +22273,7 @@ const loadSyntheticModels = async (profile, settings) => {
21317
22273
  const models = data.data?.map((model) => {
21318
22274
  return {
21319
22275
  id: model.id,
21320
- providerId: profile.id,
21321
- temperature: DEFAULT_MODEL_TEMPERATURE
22276
+ providerId: profile.id
21322
22277
  };
21323
22278
  }) || [];
21324
22279
  logger.info(`Loaded ${models.length} Synthetic models for profile ${profile.id}`);
@@ -21657,6 +22612,8 @@ const zaiPlanProviderStrategy = {
21657
22612
  };
21658
22613
  const MODELS_META_URL = "https://models.dev/api.json";
21659
22614
  const MODELS_FILE = path.join(AIDER_DESK_DATA_DIR, "models.json");
22615
+ const PROVIDER_MODELS_CACHE_FILE = path.join(AIDER_DESK_CACHE_DIR, "provider-models.json");
22616
+ const PROVIDER_MODELS_CACHE_VERSION = 1;
21660
22617
  class ModelManager {
21661
22618
  constructor(store, eventManager) {
21662
22619
  this.store = store;
@@ -21687,6 +22644,7 @@ class ModelManager {
21687
22644
  litellm: litellmProviderStrategy,
21688
22645
  lmstudio: lmStudioProviderStrategy,
21689
22646
  minimax: minimaxProviderStrategy,
22647
+ mistral: mistralProviderStrategy,
21690
22648
  ollama: ollamaProviderStrategy,
21691
22649
  openai: openaiProviderStrategy,
21692
22650
  "openai-compatible": openaiCompatibleProviderStrategy,
@@ -21704,9 +22662,20 @@ class ModelManager {
21704
22662
  this.updateEnvVarsProviders();
21705
22663
  await this.loadModelsInfo();
21706
22664
  await this.loadModelOverrides();
21707
- await this.loadProviderModels(this.getProviders().filter((p) => !p.disabled));
22665
+ const cacheLoaded = await this.loadProviderModelsFromCache();
22666
+ if (cacheLoaded) {
22667
+ this.eventManager.sendProviderModelsUpdated({
22668
+ models: Object.values(this.providerModels).flat(),
22669
+ loading: true,
22670
+ errors: this.providerErrors
22671
+ });
22672
+ this.loadProviderModelsInBackground(this.getProviders().filter((p) => !p.disabled));
22673
+ } else {
22674
+ await this.loadProviderModels(this.getProviders().filter((p) => !p.disabled));
22675
+ }
21708
22676
  logger.info("ModelInfoManager initialized successfully.", {
21709
- modelCount: Object.keys(this.modelsInfo).length
22677
+ modelCount: Object.keys(this.modelsInfo).length,
22678
+ cacheLoaded
21710
22679
  });
21711
22680
  } catch (error) {
21712
22681
  logger.error("Error initializing ModelInfoManager:", error);
@@ -21753,6 +22722,44 @@ class ModelManager {
21753
22722
  await freshDataPromise;
21754
22723
  }
21755
22724
  }
22725
+ async loadProviderModelsFromCache() {
22726
+ try {
22727
+ const cacheData = await fs$1.promises.readFile(PROVIDER_MODELS_CACHE_FILE, "utf-8");
22728
+ const cache = JSON.parse(cacheData);
22729
+ if (cache.version !== PROVIDER_MODELS_CACHE_VERSION) {
22730
+ logger.info("Provider models cache version mismatch, ignoring cache");
22731
+ return false;
22732
+ }
22733
+ this.providerModels = cache.providerModels;
22734
+ this.providerErrors = cache.providerErrors;
22735
+ logger.info("Loaded provider models from cache", {
22736
+ providerCount: Object.keys(cache.providerModels).length
22737
+ });
22738
+ return true;
22739
+ } catch {
22740
+ logger.info("Provider models cache not found or invalid");
22741
+ return false;
22742
+ }
22743
+ }
22744
+ async saveProviderModelsToCache() {
22745
+ try {
22746
+ const cache = {
22747
+ version: PROVIDER_MODELS_CACHE_VERSION,
22748
+ providerModels: this.providerModels,
22749
+ providerErrors: this.providerErrors
22750
+ };
22751
+ await fs$1.promises.mkdir(AIDER_DESK_CACHE_DIR, { recursive: true });
22752
+ await fs$1.promises.writeFile(PROVIDER_MODELS_CACHE_FILE, JSON.stringify(cache));
22753
+ logger.info("Saved provider models to cache");
22754
+ } catch (error) {
22755
+ logger.error("Failed to save provider models to cache:", error);
22756
+ }
22757
+ }
22758
+ loadProviderModelsInBackground(providers) {
22759
+ this.loadProviderModels(providers).catch((error) => {
22760
+ logger.error("Background loading of provider models failed:", error);
22761
+ });
22762
+ }
21756
22763
  processModelsMeta(data) {
21757
22764
  for (const providerId in data) {
21758
22765
  const providerData = data[providerId];
@@ -21795,6 +22802,21 @@ class ModelManager {
21795
22802
  }
21796
22803
  return Array.from(changed);
21797
22804
  }
22805
+ async loadModelsWithRetry(strategy, profile, retryCount = 3) {
22806
+ let lastResponse;
22807
+ for (let attempt = 0; attempt <= retryCount; attempt++) {
22808
+ if (attempt > 0) {
22809
+ const delayMs = Math.pow(2, attempt - 1) * 1e3;
22810
+ logger.info(`Retrying load models for provider profile ${profile.id} in ${delayMs}ms (attempt ${attempt + 1}/${retryCount + 1})`);
22811
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
22812
+ }
22813
+ lastResponse = await strategy.loadModels(profile, this.store.getSettings());
22814
+ if (lastResponse.success) {
22815
+ return lastResponse;
22816
+ }
22817
+ }
22818
+ return lastResponse;
22819
+ }
21798
22820
  async providersChanged(oldProviders, newProviders) {
21799
22821
  await this.initPromise;
21800
22822
  const removedProviders = oldProviders.filter((p) => !newProviders.find((np) => np.id === p.id));
@@ -21836,7 +22858,7 @@ class ModelManager {
21836
22858
  continue;
21837
22859
  }
21838
22860
  let providerModels = [];
21839
- const response = await strategy.loadModels(profile, this.store.getSettings());
22861
+ const response = await this.loadModelsWithRetry(strategy, profile);
21840
22862
  delete this.providerErrors[profile.id];
21841
22863
  if (response.success) {
21842
22864
  providerModels.push(...response.models);
@@ -21865,6 +22887,7 @@ class ModelManager {
21865
22887
  errors: this.providerErrors
21866
22888
  });
21867
22889
  this.eventManager.sendSettingsUpdated(this.store.getSettings());
22890
+ await this.saveProviderModelsToCache();
21868
22891
  }
21869
22892
  enrichWithModelInfo(models, profile, strategy) {
21870
22893
  const enrichedModels = [...models];
@@ -22132,12 +23155,22 @@ class ModelManager {
22132
23155
  }
22133
23156
  return strategy.getUsageReport(task, provider, modelObj, usage, providerMetadata);
22134
23157
  }
22135
- getCacheControl(profile, llmProvider) {
23158
+ getCacheControl(provider, modelId) {
23159
+ const llmProvider = provider.provider;
22136
23160
  const strategy = this.providerRegistry[llmProvider.name];
22137
23161
  if (!strategy?.getCacheControl) {
22138
23162
  return void 0;
22139
23163
  }
22140
- return strategy.getCacheControl(profile, llmProvider);
23164
+ const models = this.providerModels[provider.id] || [];
23165
+ const modelObj = models.find((m) => m.id === modelId);
23166
+ if (!modelObj) {
23167
+ const fallbackModel = {
23168
+ id: modelId,
23169
+ providerId: provider.id
23170
+ };
23171
+ return strategy.getCacheControl(llmProvider, fallbackModel);
23172
+ }
23173
+ return strategy.getCacheControl(llmProvider, modelObj);
22141
23174
  }
22142
23175
  isStreamingDisabled(provider, modelId) {
22143
23176
  const llmProvider = provider.provider;
@@ -22271,7 +23304,7 @@ class ModelManager {
22271
23304
  getProviderOptions: provider.strategy.getProviderOptions ? (_provider, model) => provider.strategy.getProviderOptions(model) : void 0,
22272
23305
  getProviderTools: provider.strategy.getProviderTools ? (_provider, model) => provider.strategy.getProviderTools(model) : void 0,
22273
23306
  getProviderParameters: provider.strategy.getProviderParameters ? (_provider, model) => provider.strategy.getProviderParameters(model) : void 0,
22274
- getCacheControl: provider.strategy.getCacheControl ? (profile2) => provider.strategy.getCacheControl(profile2) : void 0,
23307
+ getCacheControl: provider.strategy.getCacheControl ? (_provider, model) => provider.strategy.getCacheControl(model) : void 0,
22275
23308
  hasEnvVars: () => false,
22276
23309
  getAiderMapping: provider.strategy.getAiderMapping ? provider.strategy.getAiderMapping : (_provider, modelId) => ({
22277
23310
  modelName: modelId,
@@ -23171,12 +24204,13 @@ class MemoryManager {
23171
24204
  */
23172
24205
  async storeMemory(projectId, taskId, type, content) {
23173
24206
  if (!await this.waitForInit() || !this.isMemoryEnabled() || !this.db) {
23174
- return;
24207
+ return "";
23175
24208
  }
23176
24209
  try {
23177
24210
  const embedding = await this.getEmbedding(content);
24211
+ const id = uuid.v4();
23178
24212
  const memoryWithVector = {
23179
- id: uuid.v4(),
24213
+ id,
23180
24214
  type,
23181
24215
  content,
23182
24216
  taskid: taskId,
@@ -23196,8 +24230,10 @@ class MemoryManager {
23196
24230
  taskId: memoryWithVector.taskid,
23197
24231
  content: memoryWithVector.content.substring(0, 100)
23198
24232
  });
24233
+ return id;
23199
24234
  } catch (error) {
23200
24235
  logger.error("Failed to store memory:", error);
24236
+ return "";
23201
24237
  }
23202
24238
  }
23203
24239
  /**
@@ -23353,6 +24389,16 @@ class MemoryManager {
23353
24389
  isMemoryEnabled() {
23354
24390
  return this.isInitialized && this.store.getSettings().memory.enabled || false;
23355
24391
  }
24392
+ setMemoryEnabled(enabled) {
24393
+ const settings = this.store.getSettings();
24394
+ this.store.saveSettings({
24395
+ ...settings,
24396
+ memory: {
24397
+ ...settings.memory,
24398
+ enabled
24399
+ }
24400
+ });
24401
+ }
23356
24402
  }
23357
24403
  const AIDER_DESK_EXTENSIONS_REPO_URL = "https://github.com/hotovo/aider-desk/tree/main/packages/extensions/extensions/";
23358
24404
  const baseJitiOptions = {
@@ -23517,8 +24563,16 @@ class TaskContextImpl {
23517
24563
  async loadContextMessages(messages) {
23518
24564
  await this.task.loadContextMessages(messages);
23519
24565
  }
24566
+ async redoUserPrompt(messageId, mode, updatedPrompt) {
24567
+ await this.task.redoUserPrompt(messageId, mode || "agent", updatedPrompt);
24568
+ }
23520
24569
  async redoLastUserPrompt(mode, updatedPrompt) {
23521
- await this.task.redoLastUserPrompt(mode || "agent", updatedPrompt);
24570
+ const messages = await this.task.getContextMessages();
24571
+ const lastUserMessage = messages.findLast((msg) => msg.role === "user");
24572
+ if (!lastUserMessage) {
24573
+ return;
24574
+ }
24575
+ await this.task.redoUserPrompt(lastUserMessage.id, mode || "agent", updatedPrompt);
23522
24576
  }
23523
24577
  async removeMessagesUpTo(messageId) {
23524
24578
  await this.task.removeMessagesUpTo(messageId);
@@ -23721,15 +24775,20 @@ class ProjectContextImpl {
23721
24775
  }
23722
24776
  }
23723
24777
  class ExtensionContextImpl {
23724
- constructor(extensionId, extensionName, store, modelManager, eventManager, project, task) {
24778
+ constructor(extensionId, extensionName, store, modelManager, eventManager, memoryManager, project, task) {
23725
24779
  this.extensionId = extensionId;
23726
24780
  this.extensionName = extensionName;
23727
24781
  this.store = store;
23728
24782
  this.modelManager = modelManager;
23729
24783
  this.eventManager = eventManager;
24784
+ this.memoryManager = memoryManager;
23730
24785
  this.project = project;
23731
24786
  this.task = task;
24787
+ this.taskContext = this.task ? new TaskContextImpl(this.task) : null;
24788
+ this.projectContext = this.project ? new ProjectContextImpl(this.project) : null;
23732
24789
  }
24790
+ taskContext;
24791
+ projectContext;
23733
24792
  log(message, type = "info") {
23734
24793
  const logFn = logger[type];
23735
24794
  logFn(`[Extension:${this.extensionName}] ${message}`);
@@ -23738,13 +24797,13 @@ class ExtensionContextImpl {
23738
24797
  return this.project?.baseDir ?? "";
23739
24798
  }
23740
24799
  getTaskContext() {
23741
- return this.task ? new TaskContextImpl(this.task) : null;
24800
+ return this.taskContext;
23742
24801
  }
23743
24802
  getProjectContext() {
23744
- if (!this.project) {
24803
+ if (!this.projectContext) {
23745
24804
  throw new Error("Project context not available");
23746
24805
  }
23747
- return new ProjectContextImpl(this.project);
24806
+ return this.projectContext;
23748
24807
  }
23749
24808
  async getModelConfigs() {
23750
24809
  if (!this.modelManager) {
@@ -23843,6 +24902,12 @@ class ExtensionContextImpl {
23843
24902
  return false;
23844
24903
  }
23845
24904
  }
24905
+ getMemoryContext() {
24906
+ if (!this.memoryManager) {
24907
+ throw new Error("MemoryManager not available");
24908
+ }
24909
+ return this.memoryManager;
24910
+ }
23846
24911
  }
23847
24912
  const CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
23848
24913
  class ExtensionFetcher {
@@ -24142,11 +25207,12 @@ class ExtensionFetcher {
24142
25207
  }
24143
25208
  }
24144
25209
  class ExtensionManager {
24145
- constructor(store, modelManager, eventManager, telemetryManager, registry = new ExtensionRegistry()) {
25210
+ constructor(store, modelManager, eventManager, telemetryManager, memoryManager, registry = new ExtensionRegistry()) {
24146
25211
  this.store = store;
24147
25212
  this.modelManager = modelManager;
24148
25213
  this.eventManager = eventManager;
24149
25214
  this.telemetryManager = telemetryManager;
25215
+ this.memoryManager = memoryManager;
24150
25216
  this.registry = registry;
24151
25217
  this.loader = new ExtensionLoader();
24152
25218
  this.fetcher = new ExtensionFetcher();
@@ -24171,7 +25237,7 @@ class ExtensionManager {
24171
25237
  filterEnabledExtensions(extensions) {
24172
25238
  const settings = this.store.getSettings();
24173
25239
  const disabledExtensions = settings.extensions?.disabled || [];
24174
- return extensions.filter((ext) => !disabledExtensions.includes(ext.metadata.name));
25240
+ return extensions.filter((ext) => !disabledExtensions.includes(ext.filePath));
24175
25241
  }
24176
25242
  /**
24177
25243
  * Handle settings changes. Detects when extensions with UI components
@@ -24189,7 +25255,7 @@ class ExtensionManager {
24189
25255
  const changedExtensions = [...newlyDisabled, ...newlyEnabled];
24190
25256
  if (changedExtensions.length > 0) {
24191
25257
  const allExtensions = this.registry.getExtensions();
24192
- const hasUIComponentsChange = allExtensions.some((ext) => changedExtensions.includes(ext.metadata.name) && ext.instance.getUIComponents !== void 0);
25258
+ const hasUIComponentsChange = allExtensions.some((ext) => changedExtensions.includes(ext.filePath) && ext.instance.getUIComponents !== void 0);
24193
25259
  if (hasUIComponentsChange) {
24194
25260
  logger.debug("[Extensions] Extensions with UI components changed, triggering UI refresh");
24195
25261
  this.eventManager.sendExtensionUIRefresh({ reloadComponents: true });
@@ -24217,6 +25283,7 @@ class ExtensionManager {
24217
25283
  this.registry.clear();
24218
25284
  await this.loadExtensionsForDir(AIDER_DESK_GLOBAL_EXTENSIONS_DIR);
24219
25285
  this.initialized = true;
25286
+ this.migrateDisabledExtensions();
24220
25287
  await this.startHotReloadWatcher();
24221
25288
  this.captureExtensionsTelemetry();
24222
25289
  this.preloadAvailableExtensions().catch((error) => {
@@ -24253,7 +25320,7 @@ class ExtensionManager {
24253
25320
  return true;
24254
25321
  }
24255
25322
  try {
24256
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
25323
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project);
24257
25324
  await instance.onLoad(context);
24258
25325
  this.registry.setInitialized(filePath, true);
24259
25326
  this.eventManager.sendExtensionUIRefresh({
@@ -24347,13 +25414,51 @@ class ExtensionManager {
24347
25414
  isInitialized() {
24348
25415
  return this.initialized;
24349
25416
  }
25417
+ /**
25418
+ * @deprecated Migration helper: converts old name-based disabled list to filePath-based.
25419
+ * Will be removed in a future version.
25420
+ */
25421
+ migrateDisabledExtensions() {
25422
+ const settings = this.store.getSettings();
25423
+ const disabled = settings.extensions?.disabled;
25424
+ if (!disabled || disabled.length === 0) {
25425
+ return;
25426
+ }
25427
+ const allExtensions = this.registry.getExtensions();
25428
+ const filePaths = new Set(allExtensions.map((ext) => ext.filePath));
25429
+ const migrated = [];
25430
+ let changed = false;
25431
+ for (const item of disabled) {
25432
+ if (filePaths.has(item)) {
25433
+ migrated.push(item);
25434
+ } else {
25435
+ const match = allExtensions.find((ext) => ext.metadata.name === item);
25436
+ if (match) {
25437
+ migrated.push(match.filePath);
25438
+ changed = true;
25439
+ } else {
25440
+ migrated.push(item);
25441
+ }
25442
+ }
25443
+ }
25444
+ if (changed) {
25445
+ logger.info("[Extensions] Migrated disabled extensions from name-based to filePath-based identifiers");
25446
+ this.store.saveSettings({
25447
+ ...settings,
25448
+ extensions: {
25449
+ ...settings.extensions,
25450
+ disabled: migrated
25451
+ }
25452
+ });
25453
+ }
25454
+ }
24350
25455
  captureExtensionsTelemetry() {
24351
25456
  const allExtensions = this.registry.getExtensions();
24352
25457
  const settings = this.store.getSettings();
24353
25458
  const disabledExtensions = settings.extensions?.disabled || [];
24354
25459
  const globalExtensions = allExtensions.filter((ext) => !ext.projectDir).length;
24355
25460
  const projectExtensions = allExtensions.filter((ext) => ext.projectDir).length;
24356
- const enabledCount = allExtensions.filter((ext) => !disabledExtensions.includes(ext.metadata.name)).length;
25461
+ const enabledCount = allExtensions.filter((ext) => !disabledExtensions.includes(ext.filePath)).length;
24357
25462
  this.telemetryManager.captureExtensionsLoaded(allExtensions.length, globalExtensions, projectExtensions, enabledCount, disabledExtensions.length);
24358
25463
  }
24359
25464
  async dispose() {
@@ -24588,7 +25693,16 @@ class ExtensionManager {
24588
25693
  continue;
24589
25694
  }
24590
25695
  try {
24591
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, task.project, task);
25696
+ const context = new ExtensionContextImpl(
25697
+ loaded.id,
25698
+ metadata.name,
25699
+ this.store,
25700
+ this.modelManager,
25701
+ this.eventManager,
25702
+ this.memoryManager,
25703
+ task.project,
25704
+ task
25705
+ );
24592
25706
  const tools = instance.getTools(context, mode, profile);
24593
25707
  if (!Array.isArray(tools)) {
24594
25708
  logger.error(`[Extensions] Extension '${metadata.name}' getTools() did not return an array`);
@@ -24628,7 +25742,16 @@ class ExtensionManager {
24628
25742
  const registeredTools = this.getTools(task, mode, profile);
24629
25743
  for (const { extensionId, extensionName, tool } of registeredTools) {
24630
25744
  const toolId = tool.name;
24631
- const context = new ExtensionContextImpl(extensionId, extensionName, this.store, this.modelManager, this.eventManager, task.project, task);
25745
+ const context = new ExtensionContextImpl(
25746
+ extensionId,
25747
+ extensionName,
25748
+ this.store,
25749
+ this.modelManager,
25750
+ this.eventManager,
25751
+ this.memoryManager,
25752
+ task.project,
25753
+ task
25754
+ );
24632
25755
  if (profile.toolApprovals?.[toolId] === ToolApprovalState.Never) {
24633
25756
  logger.debug(`[Extensions] Skipping tool '${tool.name}' (marked as Never approved)`);
24634
25757
  continue;
@@ -24709,7 +25832,7 @@ class ExtensionManager {
24709
25832
  continue;
24710
25833
  }
24711
25834
  try {
24712
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
25835
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project);
24713
25836
  const commands = instance.getCommands(context);
24714
25837
  if (!Array.isArray(commands)) {
24715
25838
  logger.error(`[Extensions] Extension '${metadata.name}' getCommands() did not return an array`);
@@ -24743,7 +25866,7 @@ class ExtensionManager {
24743
25866
  continue;
24744
25867
  }
24745
25868
  try {
24746
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
25869
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project);
24747
25870
  const agents = instance.getAgents(context);
24748
25871
  if (!Array.isArray(agents)) {
24749
25872
  logger.error(`[Extensions] Extension '${metadata.name}' getAgents() did not return an array`);
@@ -24783,7 +25906,7 @@ class ExtensionManager {
24783
25906
  continue;
24784
25907
  }
24785
25908
  try {
24786
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
25909
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project);
24787
25910
  const modes = instance.getModes(context);
24788
25911
  if (!Array.isArray(modes)) {
24789
25912
  logger.error(`[Extensions] Extension '${metadata.name}' getModes() did not return an array`);
@@ -24836,7 +25959,7 @@ class ExtensionManager {
24836
25959
  continue;
24837
25960
  }
24838
25961
  try {
24839
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
25962
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project);
24840
25963
  const providers = instance.getProviders(context);
24841
25964
  if (!Array.isArray(providers)) {
24842
25965
  logger.error(`[Extensions] Extension '${metadata.name}' getProviders() did not return an array`);
@@ -24859,6 +25982,42 @@ class ExtensionManager {
24859
25982
  }
24860
25983
  return collectedProviders;
24861
25984
  }
25985
+ getSkills(project, task) {
25986
+ const collectedSkills = [];
25987
+ const allExtensions = this.registry.getExtensions(project.baseDir);
25988
+ const extensions = this.filterEnabledExtensions(allExtensions);
25989
+ for (const loaded of extensions) {
25990
+ const { instance, metadata } = loaded;
25991
+ if (!instance.getSkills) {
25992
+ continue;
25993
+ }
25994
+ try {
25995
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
25996
+ const skills = instance.getSkills(context);
25997
+ if (!Array.isArray(skills)) {
25998
+ logger.error(`[Extensions] Extension '${metadata.name}' getSkills() did not return an array`);
25999
+ continue;
26000
+ }
26001
+ for (const skill of skills) {
26002
+ if (!skill.name || !skill.description) {
26003
+ logger.error(`[Extensions] Invalid skill from extension '${metadata.name}': missing name or description`);
26004
+ continue;
26005
+ }
26006
+ if (!skill.dirPath && !skill.content) {
26007
+ logger.error(`[Extensions] Invalid skill from extension '${metadata.name}': must have dirPath or content`);
26008
+ continue;
26009
+ }
26010
+ collectedSkills.push({
26011
+ ...skill,
26012
+ location: "extension"
26013
+ });
26014
+ }
26015
+ } catch (error) {
26016
+ logger.error(`[Extensions] Failed to get skills from extension '${metadata.name}':`, error);
26017
+ }
26018
+ }
26019
+ return collectedSkills;
26020
+ }
24862
26021
  getUIComponents(project, task) {
24863
26022
  const collectedComponents = [];
24864
26023
  const allExtensions = this.registry.getExtensions(project?.baseDir);
@@ -24872,7 +26031,7 @@ class ExtensionManager {
24872
26031
  continue;
24873
26032
  }
24874
26033
  try {
24875
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, task);
26034
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
24876
26035
  const components = instance.getUIComponents(context);
24877
26036
  if (!Array.isArray(components)) {
24878
26037
  logger.error(`[Extensions] Extension '${metadata.name}' getUIComponents() did not return an array`);
@@ -24906,7 +26065,7 @@ class ExtensionManager {
24906
26065
  return false;
24907
26066
  }
24908
26067
  try {
24909
- const context = new ExtensionContextImpl(loadedExt.id, loadedExt.metadata.name, this.store, this.modelManager, this.eventManager);
26068
+ const context = new ExtensionContextImpl(loadedExt.id, loadedExt.metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager);
24910
26069
  const jsx = instance.getConfigComponent(context);
24911
26070
  return typeof jsx === "string" && jsx.length > 0;
24912
26071
  } catch {
@@ -24930,7 +26089,7 @@ class ExtensionManager {
24930
26089
  }
24931
26090
  try {
24932
26091
  logger.debug(`[Extensions] Getting UI extension data from '${id}' for component '${componentId}'`);
24933
- const context = new ExtensionContextImpl(id, metadata.name, this.store, this.modelManager, this.eventManager, project, task);
26092
+ const context = new ExtensionContextImpl(id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
24934
26093
  return await instance.getUIExtensionData(componentId, context);
24935
26094
  } catch (error) {
24936
26095
  logger.error(`[Extensions] Failed to get UI extension data from '${id}' for component '${componentId}':`, error);
@@ -24956,7 +26115,7 @@ class ExtensionManager {
24956
26115
  }
24957
26116
  try {
24958
26117
  logger.debug(`[Extensions] Executing UI extension action '${action}' from '${id}' for component '${componentId}'`);
24959
- const context = new ExtensionContextImpl(id, metadata.name, this.store, this.modelManager, this.eventManager, project, task);
26118
+ const context = new ExtensionContextImpl(id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
24960
26119
  return await instance.executeUIExtensionAction(componentId, action, args, context);
24961
26120
  } catch (error) {
24962
26121
  logger.error(`[Extensions] Failed to execute UI extension action '${action}' from '${id}' for component '${componentId}':`, error);
@@ -24979,7 +26138,15 @@ class ExtensionManager {
24979
26138
  return null;
24980
26139
  }
24981
26140
  try {
24982
- const context = new ExtensionContextImpl(loaded.id, loaded.metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
26141
+ const context = new ExtensionContextImpl(
26142
+ loaded.id,
26143
+ loaded.metadata.name,
26144
+ this.store,
26145
+ this.modelManager,
26146
+ this.eventManager,
26147
+ this.memoryManager,
26148
+ project
26149
+ );
24983
26150
  const jsx = loaded.instance.getConfigComponent(context);
24984
26151
  if (typeof jsx !== "string" || jsx.length === 0) {
24985
26152
  return null;
@@ -25007,7 +26174,15 @@ class ExtensionManager {
25007
26174
  return null;
25008
26175
  }
25009
26176
  try {
25010
- const context = new ExtensionContextImpl(loaded.id, loaded.metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
26177
+ const context = new ExtensionContextImpl(
26178
+ loaded.id,
26179
+ loaded.metadata.name,
26180
+ this.store,
26181
+ this.modelManager,
26182
+ this.eventManager,
26183
+ this.memoryManager,
26184
+ project
26185
+ );
25011
26186
  return await loaded.instance.getConfigData(context);
25012
26187
  } catch (error) {
25013
26188
  logger.error(`[Extensions] Failed to get config data from extension '${extensionId}':`, error);
@@ -25031,7 +26206,15 @@ class ExtensionManager {
25031
26206
  return null;
25032
26207
  }
25033
26208
  try {
25034
- const context = new ExtensionContextImpl(loaded.id, loaded.metadata.name, this.store, this.modelManager, this.eventManager, project, void 0);
26209
+ const context = new ExtensionContextImpl(
26210
+ loaded.id,
26211
+ loaded.metadata.name,
26212
+ this.store,
26213
+ this.modelManager,
26214
+ this.eventManager,
26215
+ this.memoryManager,
26216
+ project
26217
+ );
25035
26218
  return await loaded.instance.saveConfigData(configData, context);
25036
26219
  } catch (error) {
25037
26220
  logger.error(`[Extensions] Failed to save config data for extension '${extensionId}':`, error);
@@ -25064,7 +26247,7 @@ class ExtensionManager {
25064
26247
  continue;
25065
26248
  }
25066
26249
  try {
25067
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, void 0, void 0);
26250
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager);
25068
26251
  const agents = instance.getAgents(context);
25069
26252
  if (!Array.isArray(agents)) {
25070
26253
  continue;
@@ -25100,7 +26283,7 @@ class ExtensionManager {
25100
26283
  }
25101
26284
  const { extensionId, extensionName, command } = registered;
25102
26285
  try {
25103
- const context = new ExtensionContextImpl(extensionId, extensionName, this.store, this.modelManager, this.eventManager, project, task);
26286
+ const context = new ExtensionContextImpl(extensionId, extensionName, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
25104
26287
  logger.debug(`[Extensions] Executing command '${commandName}' from extension '${extensionName}'`);
25105
26288
  await command.execute(args, context);
25106
26289
  logger.debug(`[Extensions] Command '${commandName}' executed successfully`);
@@ -25275,6 +26458,15 @@ class ExtensionManager {
25275
26458
  throw new Error("Invalid GitHub repository URL");
25276
26459
  }
25277
26460
  await this.unloadExtensionsForDir(targetDir);
26461
+ const parsedExistingPath = path.parse(existingExtension.filePath);
26462
+ const existingIsFolder = parsedExistingPath.name === "index";
26463
+ if (extension.type === "folder" && !existingIsFolder) {
26464
+ await fs.unlink(existingExtension.filePath);
26465
+ logger.debug(`[Extensions] Removed old single-file extension: ${existingExtension.filePath}`);
26466
+ } else if (extension.type === "single" && existingIsFolder) {
26467
+ await fs.rm(parsedExistingPath.dir, { recursive: true, force: true });
26468
+ logger.debug(`[Extensions] Removed old folder extension: ${parsedExistingPath.dir}`);
26469
+ }
25278
26470
  if (extension.type === "single" && extension.file) {
25279
26471
  const url = `${githubRawBase}/${extension.file}`;
25280
26472
  const response = await fetch(url);
@@ -25338,7 +26530,7 @@ class ExtensionManager {
25338
26530
  }
25339
26531
  logger.debug(`[Extensions] Dispatching event '${String(eventName)}' to extension '${metadata.name}'`);
25340
26532
  try {
25341
- const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, project, task);
26533
+ const context = new ExtensionContextImpl(loaded.id, metadata.name, this.store, this.modelManager, this.eventManager, this.memoryManager, project, task);
25342
26534
  const result = await handler.call(instance, currentEvent, context);
25343
26535
  if (result && typeof result === "object") {
25344
26536
  const partialEvent = result;
@@ -25361,13 +26553,13 @@ class ExtensionManager {
25361
26553
  * @returns Sorted array of extensions
25362
26554
  */
25363
26555
  sortExtensionsForDispatch(extensions, projectDir) {
25364
- const global = extensions.filter((e) => !e.projectDir);
26556
+ const global2 = extensions.filter((e) => !e.projectDir);
25365
26557
  const projectSpecific = extensions.filter((e) => e.projectDir === projectDir);
25366
- return [...global, ...projectSpecific];
26558
+ return [...global2, ...projectSpecific];
25367
26559
  }
25368
26560
  }
25369
26561
  class EventsHandler {
25370
- constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, windowManager) {
26562
+ constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, proxyManager, windowManager) {
25371
26563
  this.projectManager = projectManager;
25372
26564
  this.store = store;
25373
26565
  this.mcpManager = mcpManager;
@@ -25381,6 +26573,7 @@ class EventsHandler {
25381
26573
  this.agentProfileManager = agentProfileManager;
25382
26574
  this.memoryManager = memoryManager;
25383
26575
  this.extensionManager = extensionManager;
26576
+ this.proxyManager = proxyManager;
25384
26577
  this.windowManager = windowManager;
25385
26578
  }
25386
26579
  loadSettings() {
@@ -25389,6 +26582,7 @@ class EventsHandler {
25389
26582
  async saveSettings(newSettings) {
25390
26583
  const oldSettings = this.store.getSettings();
25391
26584
  this.store.saveSettings(newSettings);
26585
+ this.proxyManager.settingsChanged(oldSettings, newSettings);
25392
26586
  void this.projectManager.settingsChanged(oldSettings, newSettings);
25393
26587
  this.telemetryManager.settingsChanged(oldSettings, newSettings);
25394
26588
  void this.memoryManager.settingsChanged(oldSettings, newSettings);
@@ -25443,7 +26637,7 @@ class EventsHandler {
25443
26637
  }
25444
26638
  async addOpenProject(baseDir) {
25445
26639
  const projects = this.store.getOpenProjects();
25446
- const existingProject = projects.find((p) => normalizeBaseDir(p.baseDir) === normalizeBaseDir(baseDir));
26640
+ const existingProject = projects.find((p) => compareBaseDirs$1(p.baseDir, baseDir));
25447
26641
  if (!existingProject) {
25448
26642
  logger.info("EventsHandler: addOpenProject", { baseDir });
25449
26643
  const providerModels = await this.modelManager.getProviderModels();
@@ -25460,7 +26654,7 @@ class EventsHandler {
25460
26654
  }
25461
26655
  removeOpenProject(baseDir) {
25462
26656
  const projects = this.store.getOpenProjects();
25463
- const updatedProjects = projects.filter((project) => normalizeBaseDir(project.baseDir) !== normalizeBaseDir(baseDir));
26657
+ const updatedProjects = projects.filter((project) => !compareBaseDirs$1(project.baseDir, baseDir));
25464
26658
  if (updatedProjects.length > 0) {
25465
26659
  if (!updatedProjects.some((p) => p.active)) {
25466
26660
  updatedProjects[updatedProjects.length - 1].active = true;
@@ -25510,8 +26704,8 @@ class EventsHandler {
25510
26704
  const removedIds = await this.projectManager.getProject(baseDir).getTask(taskId)?.removeMessagesUpTo(messageId) ?? [];
25511
26705
  this.eventManager.sendTaskMessageRemoved(baseDir, taskId, removedIds);
25512
26706
  }
25513
- async redoLastUserPrompt(baseDir, taskId, mode, updatedPrompt) {
25514
- void this.projectManager.getProject(baseDir).getTask(taskId)?.redoLastUserPrompt(mode, updatedPrompt);
26707
+ async redoUserPrompt(baseDir, taskId, messageId, mode, updatedPrompt) {
26708
+ void this.projectManager.getProject(baseDir).getTask(taskId)?.redoUserPrompt(messageId, mode, updatedPrompt);
25515
26709
  }
25516
26710
  async resumeTask(baseDir, taskId) {
25517
26711
  void this.projectManager.getProject(baseDir).getTask(taskId)?.resumeTask();
@@ -25530,8 +26724,8 @@ class EventsHandler {
25530
26724
  const mode = this.store.getProjectSettings(baseDir).currentMode || "agent";
25531
26725
  await task.handoffConversation(mode, focus);
25532
26726
  }
25533
- async runCodeInlineRequest(baseDir, taskId, filename, lineNumber, userComment, createNewTask) {
25534
- await this.projectManager.getProject(baseDir).getTask(taskId)?.runCodeInlineRequest(filename, lineNumber, userComment, createNewTask);
26727
+ async runCodeChangeRequests(baseDir, taskId, requests, createNewTask) {
26728
+ await this.projectManager.getProject(baseDir).getTask(taskId)?.runCodeChangeRequests(requests, 5, createNewTask);
25535
26729
  }
25536
26730
  async loadInputHistory(baseDir) {
25537
26731
  return await this.projectManager.getProject(baseDir).loadInputHistory();
@@ -25740,6 +26934,13 @@ class EventsHandler {
25740
26934
  }
25741
26935
  await task.mergeWorktreeToMain(squash, targetBranch, commitMessage);
25742
26936
  }
26937
+ async mergeAndSwitchToLocal(baseDir, taskId, targetBranch) {
26938
+ const task = this.projectManager.getProject(baseDir).getTask(taskId);
26939
+ if (!task) {
26940
+ throw new Error(`Task ${taskId} not found`);
26941
+ }
26942
+ await task.mergeAndSwitchToLocal(targetBranch);
26943
+ }
25743
26944
  async applyUncommittedChanges(baseDir, taskId, targetBranch) {
25744
26945
  const task = this.projectManager.getProject(baseDir).getTask(taskId);
25745
26946
  if (!task) {
@@ -25761,8 +26962,9 @@ class EventsHandler {
25761
26962
  }
25762
26963
  await task.restoreFile(filePath);
25763
26964
  }
25764
- async readFile(baseDir, filePath) {
25765
- const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(baseDir, filePath);
26965
+ async readFile(baseDir, taskId, filePath) {
26966
+ const task = this.projectManager.getProject(baseDir).getTask(taskId);
26967
+ const absolutePath = path.isAbsolute(filePath) ? filePath : task ? await task.resolveContextFilePath(filePath) ?? path.join(baseDir, filePath) : path.join(baseDir, filePath);
25766
26968
  const fileContentBuffer = await fs.readFile(absolutePath);
25767
26969
  if (istextorbinary.isBinary(filePath, fileContentBuffer)) {
25768
26970
  throw new Error("Cannot read binary file");
@@ -25821,6 +27023,13 @@ class EventsHandler {
25821
27023
  }
25822
27024
  await task.resolveConflictsWithAgent();
25823
27025
  }
27026
+ async renameWorktreeBranch(baseDir, taskId, newBranchName) {
27027
+ const task = this.projectManager.getProject(baseDir).getTask(taskId);
27028
+ if (!task) {
27029
+ throw new Error(`Task ${taskId} not found`);
27030
+ }
27031
+ await task.renameWorktreeBranch(newBranchName);
27032
+ }
25824
27033
  async scrapeWeb(baseDir, taskId, url, filePath) {
25825
27034
  const content = await scrapeWeb(url);
25826
27035
  const project = this.projectManager.getProject(baseDir);
@@ -26099,6 +27308,17 @@ ${error instanceof Error ? error.message : String(error)}`);
26099
27308
  async initProjectRulesFile(baseDir, taskId, args) {
26100
27309
  return this.projectManager.getProject(baseDir).getTask(taskId)?.initProjectAgentsFile(args);
26101
27310
  }
27311
+ async getSkills(baseDir, taskId) {
27312
+ return await this.projectManager.getProject(baseDir).getTask(taskId)?.getSkills() || [];
27313
+ }
27314
+ async activateSkill(baseDir, taskId, skillName) {
27315
+ await this.projectManager.getProject(baseDir).getTask(taskId)?.activateSkill(skillName);
27316
+ void this.projectManager.getProject(baseDir).getTask(taskId)?.sendSkillsUpdated();
27317
+ }
27318
+ async deactivateSkill(baseDir, taskId, skillName) {
27319
+ const removedIds = await this.projectManager.getProject(baseDir).getTask(taskId)?.deactivateSkill(skillName) ?? [];
27320
+ this.eventManager.sendTaskMessageRemoved(baseDir, taskId, removedIds);
27321
+ }
26102
27322
  async enableServer(username, password) {
26103
27323
  const currentSettings = this.store.getSettings();
26104
27324
  const updatedSettings = {
@@ -26387,7 +27607,7 @@ class PromptsManager {
26387
27607
  "conflict-resolution-system",
26388
27608
  "update-task-state",
26389
27609
  "handoff",
26390
- "code-inline-request"
27610
+ "code-change-requests"
26391
27611
  ];
26392
27612
  }
26393
27613
  async loadGlobalTemplateSource(name) {
@@ -26594,6 +27814,7 @@ class PromptsManager {
26594
27814
  };
26595
27815
  getRulesContent = async (task, agentProfile) => {
26596
27816
  const ruleFiles = await task.getRuleFilesAsContextFiles(agentProfile);
27817
+ logger.debug("Rule files for prompt content:", { ruleFiles });
26597
27818
  const ruleFilesContent = await Promise.all(
26598
27819
  ruleFiles.map(async (file) => {
26599
27820
  try {
@@ -26664,8 +27885,8 @@ ${content}
26664
27885
  };
26665
27886
  return await this.render("handoff", data, task.getProjectDir(), task);
26666
27887
  };
26667
- getCodeInlineRequestPrompt = async (task, data) => {
26668
- return await this.render("code-inline-request", data, task.getProjectDir(), task);
27888
+ getCodeChangeRequestsPrompt = async (task, data) => {
27889
+ return await this.render("code-change-requests", data, task.getProjectDir(), task);
26669
27890
  };
26670
27891
  }
26671
27892
  const execAsync = util.promisify(child_process.exec);
@@ -26925,6 +28146,8 @@ class PythonDependenciesInstaller {
26925
28146
  }
26926
28147
  }
26927
28148
  const initManagers = async (store, windowManager) => {
28149
+ const proxyManager = new ProxyManager();
28150
+ proxyManager.init(store.getSettings());
26928
28151
  const telemetryManager = new TelemetryManager(store);
26929
28152
  telemetryManager.init().catch((error) => {
26930
28153
  logger.error("[Telemetry] Telemetry initialization failed, continuing without analytics:", error);
@@ -26943,7 +28166,7 @@ const initManagers = async (store, windowManager) => {
26943
28166
  memoryManager.init().catch((error) => {
26944
28167
  logger.error("[Memory] Memory system initialization failed, continuing without memories:", error);
26945
28168
  });
26946
- const extensionManager = new ExtensionManager(store, modelManager, eventManager, telemetryManager);
28169
+ const extensionManager = new ExtensionManager(store, modelManager, eventManager, telemetryManager, memoryManager);
26947
28170
  extensionManager.init().catch((error) => {
26948
28171
  logger.error("[Extensions] Extension system initialization failed, continuing without extensions:", error);
26949
28172
  });
@@ -26988,10 +28211,11 @@ const initManagers = async (store, windowManager) => {
26988
28211
  agentProfileManager,
26989
28212
  memoryManager,
26990
28213
  extensionManager,
28214
+ proxyManager,
26991
28215
  windowManager
26992
28216
  );
26993
- const serverController = new ServerController(httpServer, projectManager, eventsHandler, store);
26994
- const connectorManager = new ConnectorManager(httpServer, projectManager, eventManager);
28217
+ const serverController = new ServerController(httpServer, projectManager, eventsHandler, store, pythonInstaller);
28218
+ const connectorManager = new ConnectorManager(httpServer, projectManager, eventManager, store);
26995
28219
  httpServer.listen(SERVER_PORT);
26996
28220
  logger.info(`AiderDesk headless server listening on http://localhost:${SERVER_PORT}`);
26997
28221
  let cleanedUp = false;
@@ -27579,6 +28803,10 @@ const DEFAULT_SETTINGS = {
27579
28803
  enabled: false,
27580
28804
  username: "",
27581
28805
  password: ""
28806
+ },
28807
+ cors: {
28808
+ enabled: false,
28809
+ origins: []
27582
28810
  }
27583
28811
  },
27584
28812
  memory: {
@@ -27594,11 +28822,17 @@ const DEFAULT_SETTINGS = {
27594
28822
  worktreeSymlinkFolders: ["node_modules", "vendor", "__pycache__", ".venv", "venv"],
27595
28823
  contextCompactingThreshold: 0,
27596
28824
  contextCompactionType: ContextCompactionType.Compact,
27597
- defaultWorkingMode: "local"
28825
+ defaultWorkingMode: "local",
28826
+ worktreeBranchPrefix: "aider-desk/task/",
28827
+ renameBranchOnNameGeneration: true
27598
28828
  },
27599
28829
  extensions: {
27600
28830
  repositories: [AIDER_DESK_EXTENSIONS_REPO_URL],
27601
28831
  disabled: []
28832
+ },
28833
+ proxy: {
28834
+ enabled: false,
28835
+ url: ""
27602
28836
  }
27603
28837
  };
27604
28838
  const compareBaseDirs = (baseDir1, baseDir2) => {
@@ -27654,7 +28888,14 @@ class Store {
27654
28888
  }
27655
28889
  },
27656
28890
  mcpServers: settings.mcpServers || DEFAULT_SETTINGS.mcpServers,
27657
- server: settings.server || DEFAULT_SETTINGS.server,
28891
+ server: {
28892
+ ...DEFAULT_SETTINGS.server,
28893
+ ...settings.server,
28894
+ cors: {
28895
+ ...DEFAULT_SETTINGS.server.cors,
28896
+ ...settings.server?.cors
28897
+ }
28898
+ },
27658
28899
  memory: {
27659
28900
  ...DEFAULT_SETTINGS.memory,
27660
28901
  ...settings?.memory