autohand-cli 0.7.14 → 0.8.2

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 (414) hide show
  1. package/README.md +97 -2
  2. package/assets/icon.png +0 -0
  3. package/dist/AgentRegistry-7LDL5HJH.js +10 -0
  4. package/dist/AgentRegistry-NQCLWABO.cjs +10 -0
  5. package/dist/{AutomodeManager-NGRAO2MH.js → AutomodeManager-MWLKGPZK.js} +2 -0
  6. package/dist/{AutomodeManager-ZKQMBM4T.cjs → AutomodeManager-NYIZNODK.cjs} +3 -1
  7. package/dist/CommunitySkillsCache-6QPRMTJO.js +8 -0
  8. package/dist/CommunitySkillsCache-GTQMOCCO.cjs +8 -0
  9. package/dist/{GitHubRegistryFetcher-US2JJID4.js → GitHubRegistryFetcher-6JQ5JEDZ.js} +1 -0
  10. package/dist/{GitHubRegistryFetcher-K744NNAJ.cjs → GitHubRegistryFetcher-S7QFUEKV.cjs} +1 -0
  11. package/dist/HookManager-Q2KYMCP4.cjs +7 -0
  12. package/dist/HookManager-TTP4Y6DC.js +7 -0
  13. package/dist/ImportWizard-35YBJ4AM.cjs +466 -0
  14. package/dist/ImportWizard-XH7CINCH.js +466 -0
  15. package/dist/LearnAdvisor-A4Q5PPBI.js +9 -0
  16. package/dist/LearnAdvisor-GASQD7HT.cjs +9 -0
  17. package/dist/McpClientManager-7RM6YT35.js +8 -0
  18. package/dist/McpClientManager-RKD7C6OY.cjs +8 -0
  19. package/dist/MemoryManager-GUNLRP5S.js +8 -0
  20. package/dist/MemoryManager-TNSGKDKX.cjs +8 -0
  21. package/dist/{PermissionManager-U5OMGR3L.js → PermissionManager-ATUV34LQ.js} +4 -3
  22. package/dist/PermissionManager-KMN53FJP.cjs +11 -0
  23. package/dist/ProjectProfiler-UMJJSOCE.js +194 -0
  24. package/dist/ProjectProfiler-ZDWR2ODG.cjs +194 -0
  25. package/dist/ProviderFactory-MR5B23QJ.js +9 -0
  26. package/dist/ProviderFactory-VFGCJJX6.cjs +9 -0
  27. package/dist/SessionManager-FEUAU3ZJ.cjs +10 -0
  28. package/dist/SessionManager-IKWAK2PI.js +10 -0
  29. package/dist/SkillsRegistry-KPQFTRIT.cjs +9 -0
  30. package/dist/SkillsRegistry-XJSKPDF2.js +9 -0
  31. package/dist/SubAgent-NYH6GWQ3.js +11 -0
  32. package/dist/SubAgent-PZKBDUBA.cjs +11 -0
  33. package/dist/{SyncApiClient-AYXYSOJM.js → SyncApiClient-LVIO4C2S.js} +1 -0
  34. package/dist/{SyncApiClient-ID3KXEMA.cjs → SyncApiClient-ZNYMT36M.cjs} +1 -0
  35. package/dist/about-HHTF2YFL.js +12 -0
  36. package/dist/about-JGRVNNQC.cjs +12 -0
  37. package/dist/actionExecutor-U6IBN2TU.cjs +19 -0
  38. package/dist/actionExecutor-XT5FW3W6.js +19 -0
  39. package/dist/add-dir-247K3XRY.js +10 -0
  40. package/dist/add-dir-GS4DXKKH.cjs +10 -0
  41. package/dist/agents/builtin/code-cleaner.md +14 -0
  42. package/dist/agents/builtin/docs-writer.md +14 -0
  43. package/dist/agents/builtin/researcher.md +14 -0
  44. package/dist/agents/builtin/reviewer.md +15 -0
  45. package/dist/agents/builtin/tester.md +15 -0
  46. package/dist/agents/builtin/todo-resolver.md +15 -0
  47. package/dist/agents-R6ZEFTVR.cjs +12 -0
  48. package/dist/agents-WJPQWQF2.js +12 -0
  49. package/dist/agents-new-HKVEIBDJ.js +14 -0
  50. package/dist/agents-new-X6GTHIO6.cjs +14 -0
  51. package/dist/assets/icon.png +0 -0
  52. package/dist/autoSkill-6TGBTEQD.js +20 -0
  53. package/dist/autoSkill-H4T6VVDA.cjs +20 -0
  54. package/dist/automode-BC6NVECO.js +10 -0
  55. package/dist/automode-WN2RSOGW.cjs +10 -0
  56. package/dist/{cc-UTTLESTY.js → cc-7LEIJ3KF.js} +1 -0
  57. package/dist/{cc-2W6M7J45.cjs → cc-Q5MM4AWC.cjs} +1 -0
  58. package/dist/{chunk-N4ZSG6JJ.cjs → chunk-22D2CNTP.cjs} +2 -2
  59. package/dist/chunk-245KJE5Y.cjs +55 -0
  60. package/dist/chunk-24QIWILL.js +51 -0
  61. package/dist/{chunk-MYNHJHDZ.js → chunk-2AA5MFES.js} +1 -1
  62. package/dist/{chunk-TSY7JHIV.cjs → chunk-33A755XB.cjs} +2 -2
  63. package/dist/chunk-33RSHBDH.js +131 -0
  64. package/dist/{chunk-QRGPAUST.js → chunk-34M3HWLR.js} +2 -2
  65. package/dist/{chunk-U7CZFKPL.cjs → chunk-3K2ESU53.cjs} +2 -2
  66. package/dist/{chunk-SIGWDEPS.cjs → chunk-3L53OA4E.cjs} +10 -10
  67. package/dist/chunk-3OEDGIFW.js +42 -0
  68. package/dist/chunk-3OTU3RS3.cjs +1607 -0
  69. package/dist/{chunk-MNSTWHK3.cjs → chunk-3PCTTUNW.cjs} +11 -11
  70. package/dist/{chunk-P5VDZ6PV.js → chunk-3PDTTAKJ.js} +1 -1
  71. package/dist/chunk-47CKWKEX.cjs +59 -0
  72. package/dist/{chunk-Z4J4W6YQ.cjs → chunk-4JNNTOGF.cjs} +2 -48
  73. package/dist/{chunk-GVZPIQWB.js → chunk-4PKF7WPD.js} +11 -5
  74. package/dist/{chunk-3S4DEIJP.cjs → chunk-5IXII4HX.cjs} +2 -2
  75. package/dist/{chunk-CRQKDBLD.js → chunk-5P2NXKP3.js} +98 -64
  76. package/dist/{chunk-DSKVMFRM.cjs → chunk-643VRA5S.cjs} +12 -4
  77. package/dist/{chunk-VVBBEYTH.cjs → chunk-6HYLHBQG.cjs} +10 -10
  78. package/dist/{chunk-L5ZFPWHY.js → chunk-6OYHF6MF.js} +12 -4
  79. package/dist/{chunk-BPTBKO7D.js → chunk-6RF7UKUS.js} +224 -37
  80. package/dist/{chunk-YHGTBPEC.js → chunk-6ZCULLCA.js} +1 -1
  81. package/dist/{chunk-VHBUKGRG.js → chunk-72FKPBT5.js} +4 -4
  82. package/dist/{chunk-2U5HFVRO.cjs → chunk-7BTSG4ME.cjs} +5165 -2194
  83. package/dist/chunk-7UOUW76C.js +603 -0
  84. package/dist/{chunk-FEVHH525.cjs → chunk-A4IJHHV7.cjs} +11 -5
  85. package/dist/{chunk-B6EBHCK2.cjs → chunk-AEJH23FO.cjs} +6 -6
  86. package/dist/{chunk-WLTVF77A.js → chunk-ALYU6VTM.js} +1 -1
  87. package/dist/{chunk-NMWEDN4Z.js → chunk-APIXPPMT.js} +5165 -2194
  88. package/dist/chunk-AS6RTLN7.cjs +203 -0
  89. package/dist/{chunk-BHV7CBNT.js → chunk-AYS2ASM7.js} +1 -1
  90. package/dist/{chunk-GRSVQ5YZ.js → chunk-AYSFIUFW.js} +44 -12
  91. package/dist/{chunk-NUHYCFHW.cjs → chunk-BVKXEQVG.cjs} +54 -65
  92. package/dist/chunk-BWN2CLLM.cjs +298 -0
  93. package/dist/{chunk-4HA7IHLJ.cjs → chunk-C5IJIM2V.cjs} +38 -16
  94. package/dist/{chunk-SRLY7K6J.js → chunk-CAMZTXV6.js} +2 -2
  95. package/dist/chunk-CDBPBM2K.cjs +29 -0
  96. package/dist/chunk-CNBKZEX5.cjs +109 -0
  97. package/dist/{chunk-WQUQ5JMM.js → chunk-CWMZKFTT.js} +4 -4
  98. package/dist/{chunk-CKN2BLHK.cjs → chunk-CZXGCVTR.cjs} +2 -2
  99. package/dist/{chunk-SZP4ULM5.cjs → chunk-DJDE4DTT.cjs} +17 -17
  100. package/dist/chunk-DN573ME7.cjs +1675 -0
  101. package/dist/chunk-DRE2RXBZ.js +4498 -0
  102. package/dist/chunk-DSPQEHDT.js +29 -0
  103. package/dist/{chunk-SFNT5DYE.cjs → chunk-DVUHHH3B.cjs} +4 -4
  104. package/dist/chunk-DVZOENQ7.cjs +58 -0
  105. package/dist/{chunk-PWLLLJHU.js → chunk-EGFT4PGW.js} +3 -1
  106. package/dist/chunk-EGMZDTSL.js +55 -0
  107. package/dist/chunk-EZMINVLU.js +123 -0
  108. package/dist/chunk-FHK7UDOJ.cjs +42 -0
  109. package/dist/{chunk-KWRUQRXR.js → chunk-FKSDEWDH.js} +44 -10
  110. package/dist/chunk-FMB3TSWP.cjs +218 -0
  111. package/dist/chunk-FW774QXH.js +1838 -0
  112. package/dist/{chunk-MY3TZER2.js → chunk-G27PQQFD.js} +1 -1
  113. package/dist/{chunk-Y2ZSH3YF.cjs → chunk-G3V4SFET.cjs} +57 -23
  114. package/dist/chunk-G4CAKI3V.js +58 -0
  115. package/dist/{chunk-FB6JWNJS.js → chunk-GBHDROGL.js} +54 -65
  116. package/dist/{chunk-DEAEO7RI.js → chunk-GJH7XMSK.js} +15 -1
  117. package/dist/chunk-GLBAF54O.js +218 -0
  118. package/dist/{chunk-S47TCZDL.js → chunk-H5SWOLG6.js} +7 -7
  119. package/dist/chunk-HBXAA3XB.js +83 -0
  120. package/dist/{chunk-63BXZQZW.js → chunk-HIVRCQS2.js} +26 -4
  121. package/dist/{chunk-WOGJXDBU.cjs → chunk-HLHTG5ZU.cjs} +18 -4
  122. package/dist/{chunk-FK2DVRPJ.js → chunk-HLQV64Y5.js} +170 -4
  123. package/dist/chunk-HOAHWIQ5.cjs +260 -0
  124. package/dist/{chunk-D2XFTCRP.js → chunk-HQ7YZKXE.js} +1 -1
  125. package/dist/{chunk-L42HTMMR.cjs → chunk-HTLINWX6.cjs} +2 -2
  126. package/dist/{chunk-PKOAXQKW.cjs → chunk-HVKOZ2VP.cjs} +11 -11
  127. package/dist/chunk-HXGBSJL5.cjs +27 -0
  128. package/dist/chunk-I5IW3T2Y.js +310 -0
  129. package/dist/chunk-IETRBBMP.cjs +603 -0
  130. package/dist/{chunk-MTALRU7R.cjs → chunk-IFFXSTOM.cjs} +3 -3
  131. package/dist/{chunk-V7YTCNMN.cjs → chunk-IKGWDOGU.cjs} +174 -8
  132. package/dist/chunk-IQ5RXU6O.js +1675 -0
  133. package/dist/{chunk-ZBIBLOZL.js → chunk-IVM5F2AE.js} +500 -317
  134. package/dist/chunk-J4Q7XR3G.js +260 -0
  135. package/dist/{chunk-XL77XYI2.cjs → chunk-J6QET7EF.cjs} +27 -7
  136. package/dist/{chunk-TQB222ZB.js → chunk-JCLYQ2JC.js} +2 -2
  137. package/dist/chunk-JSBRDJBE.js +30 -0
  138. package/dist/{chunk-XPOHYKR3.js → chunk-JX3DFKBI.js} +2 -2
  139. package/dist/chunk-JYTDYJVW.js +27 -0
  140. package/dist/{chunk-6SHHB2VD.js → chunk-KPELYZ6L.js} +2 -2
  141. package/dist/{chunk-ZLOTP56B.cjs → chunk-KWXVKLQ5.cjs} +5 -5
  142. package/dist/chunk-L3WAH3EM.cjs +131 -0
  143. package/dist/{chunk-ZXIQCYYV.cjs → chunk-LA7H35XM.cjs} +9 -9
  144. package/dist/chunk-LENHP55G.cjs +1838 -0
  145. package/dist/chunk-LJFUXC56.cjs +123 -0
  146. package/dist/{chunk-R5OO7MEB.cjs → chunk-LNMYK2F5.cjs} +22 -22
  147. package/dist/chunk-LQGVEP3E.js +109 -0
  148. package/dist/{chunk-KXAAEROY.js → chunk-LWUJFGOZ.js} +2 -2
  149. package/dist/chunk-MAKMSQMQ.cjs +504 -0
  150. package/dist/{chunk-BG4OQUKP.js → chunk-MBBY4ZIK.js} +1 -1
  151. package/dist/chunk-MSED7RH2.cjs +267 -0
  152. package/dist/{chunk-NMGF2KUN.js → chunk-MYISNQH4.js} +1 -1
  153. package/dist/chunk-N23UAW4I.js +59 -0
  154. package/dist/chunk-N254NRHT.cjs +30 -0
  155. package/dist/{chunk-TOTDRAWG.js → chunk-NDMIPTV4.js} +1 -1
  156. package/dist/{chunk-AIH6GUGB.cjs → chunk-NNPAM4HC.cjs} +5 -5
  157. package/dist/{chunk-HSPWX4Z2.cjs → chunk-O4IF4NJT.cjs} +231 -44
  158. package/dist/{chunk-DZHR34H6.cjs → chunk-OGV4WJ5L.cjs} +8 -8
  159. package/dist/chunk-OHUZKDGX.js +348 -0
  160. package/dist/{chunk-BRXIEKJ3.cjs → chunk-OLSBBZW6.cjs} +5 -5
  161. package/dist/{chunk-MILZEEUV.js → chunk-OOKY3HPZ.js} +9 -3
  162. package/dist/chunk-P47WPOXN.js +298 -0
  163. package/dist/{chunk-ULMPJUJW.cjs → chunk-PRRCJFU3.cjs} +23 -23
  164. package/dist/{chunk-SMHY3Q7B.cjs → chunk-Q7XSCYND.cjs} +54 -22
  165. package/dist/chunk-QCLYBIMM.cjs +51 -0
  166. package/dist/chunk-QMAKTSZB.cjs +48 -0
  167. package/dist/{chunk-DTFR3WD6.js → chunk-QNGEW5TC.js} +1 -1
  168. package/dist/chunk-QOXPOR5D.js +267 -0
  169. package/dist/chunk-R33VKSH5.cjs +348 -0
  170. package/dist/{chunk-RJP3SZ7Q.cjs → chunk-RD5XAJR2.cjs} +492 -309
  171. package/dist/chunk-RGR6ME5J.cjs +844 -0
  172. package/dist/{chunk-EOGKE5GD.cjs → chunk-RKJTGGMU.cjs} +221 -126
  173. package/dist/{chunk-GD4AFYJ3.js → chunk-RO6WYEWH.js} +24 -4
  174. package/dist/chunk-S52YW5ZQ.js +844 -0
  175. package/dist/{chunk-6DWXHBAY.js → chunk-SAHBLB3E.js} +222 -127
  176. package/dist/{chunk-JHOQABEF.js → chunk-SCXX4LW5.js} +5 -5
  177. package/dist/{chunk-GIZL57FE.cjs → chunk-SEKD5FH3.cjs} +3 -1
  178. package/dist/{chunk-JWPI6O5Z.js → chunk-SKV2F3NM.js} +31 -4
  179. package/dist/{chunk-FHUNAB2K.cjs → chunk-SKYG33B2.cjs} +33 -6
  180. package/dist/{chunk-BISFR6ZL.js → chunk-SLQAYV3W.js} +1 -1
  181. package/dist/{chunk-RFNCTE4V.cjs → chunk-SYVYLZZF.cjs} +2 -2
  182. package/dist/{chunk-3XJD56Z4.js → chunk-T73IDKDF.js} +10 -3
  183. package/dist/chunk-TBEGGJNC.cjs +310 -0
  184. package/dist/{chunk-RRZS5A53.js → chunk-TNZRZQ7Q.js} +1 -1
  185. package/dist/{chunk-CH4SPVFD.cjs → chunk-TXSDBGKX.cjs} +10 -3
  186. package/dist/chunk-U3WDY42C.cjs +42 -0
  187. package/dist/{chunk-425MT6Y5.cjs → chunk-U46VYPLR.cjs} +9 -9
  188. package/dist/{chunk-OLG7LZBD.js → chunk-VG34MG2U.js} +1 -1
  189. package/dist/{chunk-XDVG3NM4.js → chunk-W3X6PAC7.js} +2 -48
  190. package/dist/{chunk-LYMTYC67.js → chunk-WHE2SWHU.js} +2 -2
  191. package/dist/chunk-WM5PAOTQ.cjs +4498 -0
  192. package/dist/chunk-WNUVPKBW.js +42 -0
  193. package/dist/{chunk-EV53SLSB.cjs → chunk-WPVWQSL7.cjs} +4 -4
  194. package/dist/chunk-WQ3VJXZB.js +118 -0
  195. package/dist/{chunk-HMRDNRTH.js → chunk-X2MSVKDV.js} +2 -2
  196. package/dist/chunk-X3WS5LDG.js +504 -0
  197. package/dist/{chunk-43XS26AQ.cjs → chunk-X5VSP65C.cjs} +4 -4
  198. package/dist/{chunk-DSCQPWUB.cjs → chunk-X5YJ34FZ.cjs} +15 -15
  199. package/dist/chunk-XAV24VYN.js +48 -0
  200. package/dist/chunk-XDLH4EDL.cjs +118 -0
  201. package/dist/{chunk-X765A7J5.js → chunk-XRZEUWKF.js} +1 -1
  202. package/dist/{chunk-ZKZRFH37.cjs → chunk-XTB6VJVQ.cjs} +6 -6
  203. package/dist/{chunk-H3GBSPK5.js → chunk-XX2ZO7DS.js} +14 -6
  204. package/dist/{chunk-RUZB43HU.cjs → chunk-Y72HH2TF.cjs} +22 -14
  205. package/dist/chunk-YFXTE422.cjs +92 -0
  206. package/dist/{chunk-OSUWEUZE.js → chunk-YGN4CQIP.js} +1 -1
  207. package/dist/{chunk-KC5FPUOF.cjs → chunk-YRLYSQEQ.cjs} +2 -2
  208. package/dist/{chunk-3KBBARKO.js → chunk-YZXUDM5X.js} +85 -28
  209. package/dist/chunk-Z36XBUMX.cjs +83 -0
  210. package/dist/chunk-ZK6HOR62.js +92 -0
  211. package/dist/{chunk-PDKNHU5G.cjs → chunk-ZQE72E6W.cjs} +22 -16
  212. package/dist/chunk-ZVY2XD6T.js +1607 -0
  213. package/dist/{chunk-XBUMKEFN.cjs → chunk-ZYQMLKOK.cjs} +91 -34
  214. package/dist/clear-UO4MNWZW.cjs +12 -0
  215. package/dist/clear-ZJ5NYP6E.js +12 -0
  216. package/dist/communityInstaller-6KCFN7YZ.js +19 -0
  217. package/dist/communityInstaller-PVSOFDZD.cjs +19 -0
  218. package/dist/completion-MMF2PN2H.js +14 -0
  219. package/dist/completion-UI5WKHXI.cjs +14 -0
  220. package/dist/config-E7RINK4R.cjs +18 -0
  221. package/dist/config-ZN66VXPS.js +18 -0
  222. package/dist/constants-6CPCJ3DY.cjs +21 -0
  223. package/dist/{constants-V6J54N3X.js → constants-UFM5B232.js} +2 -1
  224. package/dist/{defaultHooks-WLMRQUXG.cjs → defaultHooks-RCXPHF4M.cjs} +3 -1
  225. package/dist/{defaultHooks-R56VYG7I.js → defaultHooks-RDRMER3Z.js} +2 -0
  226. package/dist/export-N4XIVDSL.cjs +12 -0
  227. package/dist/export-W22L4D5C.js +12 -0
  228. package/dist/extractSessionMemories-SDW2MVBQ.cjs +7 -0
  229. package/dist/extractSessionMemories-V7K42ZHW.js +7 -0
  230. package/dist/feedback-DR6ADSNE.cjs +15 -0
  231. package/dist/feedback-FEEAP4QW.js +15 -0
  232. package/dist/filesystem-3SGCW2BF.js +10 -0
  233. package/dist/filesystem-MCFXJQ6R.cjs +10 -0
  234. package/dist/formatters-6K7QVWQL.cjs +10 -0
  235. package/dist/formatters-DQHO5I36.js +10 -0
  236. package/dist/{help-LKKQU2TN.js → help-2BLR7L43.js} +3 -2
  237. package/dist/help-AQHGTS7P.cjs +12 -0
  238. package/dist/{history-AV4XBFRK.js → history-5FZ3M2AK.js} +3 -2
  239. package/dist/history-NIUDRMKA.cjs +14 -0
  240. package/dist/hooks-2EY4IPKV.js +13 -0
  241. package/dist/hooks-LJVORRIG.cjs +13 -0
  242. package/dist/i18n-ARDG2SMC.cjs +33 -0
  243. package/dist/{i18n-BSAPXM56.js → i18n-K7QOWIBH.js} +2 -1
  244. package/dist/ide-GFW6IJHD.js +12 -0
  245. package/dist/ide-N2ZNSSB3.cjs +12 -0
  246. package/dist/import-DFVN3KNZ.js +10 -0
  247. package/dist/import-QEME3E4T.cjs +170 -0
  248. package/dist/import-UXM3VK7B.js +170 -0
  249. package/dist/import-ZS6DPGU5.cjs +10 -0
  250. package/dist/index.cjs +11233 -11804
  251. package/dist/index.js +12594 -13165
  252. package/dist/init-PY75HA3S.cjs +10 -0
  253. package/dist/init-QNMWLAVY.js +10 -0
  254. package/dist/language-5UE4G2BT.cjs +18 -0
  255. package/dist/language-UXMHEZUJ.js +18 -0
  256. package/dist/learn-HJ3FLNZC.cjs +20 -0
  257. package/dist/learn-MVYS3RU5.js +20 -0
  258. package/dist/{lint-44UQJ673.cjs → lint-D5UOJWIK.cjs} +1 -0
  259. package/dist/{lint-TA2ZHVLM.js → lint-NJPZWVN2.js} +1 -0
  260. package/dist/{localProjectPermissions-WQYMGI42.js → localProjectPermissions-N77HA3XK.js} +3 -2
  261. package/dist/localProjectPermissions-UFSMNTBJ.cjs +18 -0
  262. package/dist/login-DSE7H63A.js +20 -0
  263. package/dist/login-V3MEWPKN.cjs +20 -0
  264. package/dist/logout-BMVCLKKW.js +18 -0
  265. package/dist/logout-XEG7FHOZ.cjs +18 -0
  266. package/dist/mcp-PYUR4PHO.js +18 -0
  267. package/dist/mcp-SG6JFLGC.cjs +18 -0
  268. package/dist/{mcp-install-2KVKRAMQ.cjs → mcp-install-G27HSS3Z.cjs} +26 -14
  269. package/dist/{mcp-install-77UXRN6R.js → mcp-install-VESN42PI.js} +21 -9
  270. package/dist/memory-4ZMMEZ2Z.js +10 -0
  271. package/dist/memory-QSGMVVGH.cjs +10 -0
  272. package/dist/message-JUBOK2VU.js +9 -0
  273. package/dist/message-ZJ5AYAMT.cjs +9 -0
  274. package/dist/model-NANLBZ4Z.cjs +10 -0
  275. package/dist/model-ZXNV4AF7.js +10 -0
  276. package/dist/new-5QJY5JP2.js +12 -0
  277. package/dist/new-PMMG55UX.cjs +12 -0
  278. package/dist/{patch-BAAQIYSW.js → patch-5F6VBIT3.js} +2 -0
  279. package/dist/{patch-J32X2QQP.cjs → patch-MOD7QC3D.cjs} +3 -1
  280. package/dist/permissions-LECTCJ4H.cjs +13 -0
  281. package/dist/permissions-VP5VGIBL.js +13 -0
  282. package/dist/{plan-JFGNRL2S.js → plan-G5CEKJI4.js} +1 -0
  283. package/dist/{plan-B3CW5DXJ.cjs → plan-QKOHE3LH.cjs} +1 -0
  284. package/dist/quit-BKOOPHU5.cjs +10 -0
  285. package/dist/quit-FVFNYACP.js +10 -0
  286. package/dist/registry-KWZGYJC2.js +2108 -0
  287. package/dist/registry-YN4FQPOO.cjs +2108 -0
  288. package/dist/resume-EXFQSQPH.js +13 -0
  289. package/dist/resume-PP2IQM5S.cjs +13 -0
  290. package/dist/search-C56FBN67.cjs +17 -0
  291. package/dist/search-XGZDYBF4.js +17 -0
  292. package/dist/{session-T3TAZ5ZU.cjs → session-BSU2L5UI.cjs} +1 -0
  293. package/dist/{session-H5QWKE5E.js → session-SZMRN5KG.js} +1 -0
  294. package/dist/sessions-54KI3F2Q.js +10 -0
  295. package/dist/sessions-DDTSPNVW.cjs +10 -0
  296. package/dist/settings-BDO37TTO.cjs +30 -0
  297. package/dist/settings-FHRDFPLK.js +30 -0
  298. package/dist/share-IERCTBGN.cjs +14 -0
  299. package/dist/share-TGROUE6R.js +14 -0
  300. package/dist/skills-6OL4OSGA.js +76 -0
  301. package/dist/skills-FYY6F2WV.cjs +76 -0
  302. package/dist/skills-OM4IGBAA.cjs +26 -0
  303. package/dist/skills-S3GRN323.js +26 -0
  304. package/dist/{skills-install-MQINL3EC.js → skills-install-6CSWC24P.js} +97 -26
  305. package/dist/{skills-install-IKJZN4G2.cjs → skills-install-O3LZ2ETC.cjs} +106 -35
  306. package/dist/skills-new-ALD2PTHN.js +15 -0
  307. package/dist/skills-new-PWLKK7GW.cjs +15 -0
  308. package/dist/slashCommands-L4ZD33LJ.js +75 -0
  309. package/dist/slashCommands-YY2VUUDF.cjs +75 -0
  310. package/dist/status-3PC5XWSS.cjs +11 -0
  311. package/dist/status-KCLVOYPD.js +11 -0
  312. package/dist/sync-6SDWG5RK.js +18 -0
  313. package/dist/sync-7JMZVEQD.cjs +40 -0
  314. package/dist/{sync-EXYX7HXW.js → sync-KWX67OUN.js} +3 -2
  315. package/dist/sync-WHURZL3U.cjs +18 -0
  316. package/dist/tasks-5FPBIFLC.js +9 -0
  317. package/dist/tasks-TXGKGNH6.cjs +9 -0
  318. package/dist/team-5YXP3JGR.js +9 -0
  319. package/dist/team-IIWEZKNR.cjs +9 -0
  320. package/dist/teammate-2KMKJXAM.cjs +139 -0
  321. package/dist/teammate-L6EZQ3I2.js +139 -0
  322. package/dist/theme-BE5A4FPN.cjs +18 -0
  323. package/dist/theme-YMFCQP7J.js +18 -0
  324. package/dist/ui/questionModal.cjs +7 -25
  325. package/dist/ui/questionModal.js +6 -24
  326. package/dist/undo-KZHUUZTD.cjs +10 -0
  327. package/dist/undo-NEIEHQVX.js +10 -0
  328. package/dist/update-TVAJMMBC.js +82 -0
  329. package/dist/update-Z6BIIQDC.cjs +82 -0
  330. package/package.json +10 -3
  331. package/dist/CommunitySkillsCache-ILWHWE5P.js +0 -7
  332. package/dist/CommunitySkillsCache-KHC6RUJW.cjs +0 -7
  333. package/dist/HookManager-X47HCM5G.cjs +0 -6
  334. package/dist/HookManager-ZXKHCD7U.js +0 -6
  335. package/dist/MemoryManager-6ZT7IDO5.cjs +0 -7
  336. package/dist/MemoryManager-AJGS5AKB.js +0 -7
  337. package/dist/PermissionManager-HG6W2DGU.cjs +0 -10
  338. package/dist/SessionManager-BJ2G6VV4.cjs +0 -9
  339. package/dist/SessionManager-ENPGYK5J.js +0 -9
  340. package/dist/SkillsRegistry-6ZFOCT25.cjs +0 -8
  341. package/dist/SkillsRegistry-C2SHOZ5D.js +0 -8
  342. package/dist/about-3BJTNSLK.js +0 -11
  343. package/dist/about-EABQNJGV.cjs +0 -11
  344. package/dist/add-dir-7FD4DMDA.cjs +0 -9
  345. package/dist/add-dir-LOYJ4YB5.js +0 -9
  346. package/dist/agents-2Y6ASV7C.js +0 -10
  347. package/dist/agents-UOSPKLQL.cjs +0 -10
  348. package/dist/agents-new-23NSGAM5.js +0 -13
  349. package/dist/agents-new-WI2EL7IJ.cjs +0 -13
  350. package/dist/automode-LGWTY3UX.js +0 -9
  351. package/dist/automode-WLBQ7MN7.cjs +0 -9
  352. package/dist/chunk-5UBW2BGC.js +0 -33
  353. package/dist/chunk-I6DBWNLN.cjs +0 -169
  354. package/dist/chunk-IZBCMJHJ.cjs +0 -33
  355. package/dist/completion-7WGMHKOR.cjs +0 -13
  356. package/dist/completion-KH33NSGP.js +0 -13
  357. package/dist/constants-RBQTR32A.cjs +0 -20
  358. package/dist/export-3QN3IH7A.js +0 -11
  359. package/dist/export-BI54X3MP.cjs +0 -11
  360. package/dist/feedback-CI4OIPOS.cjs +0 -14
  361. package/dist/feedback-GFPL5STE.js +0 -14
  362. package/dist/formatters-N5IJKYZY.cjs +0 -8
  363. package/dist/formatters-UG6VZJJ5.js +0 -8
  364. package/dist/help-CWMUGD3V.cjs +0 -11
  365. package/dist/history-73VBEMSI.cjs +0 -13
  366. package/dist/hooks-62UDQBGH.cjs +0 -12
  367. package/dist/hooks-XORDJD5X.js +0 -12
  368. package/dist/i18n-X2IU2EZD.cjs +0 -32
  369. package/dist/ide-RPKZALQV.js +0 -11
  370. package/dist/ide-YMNXJB6A.cjs +0 -11
  371. package/dist/init-J5HR4R7U.js +0 -9
  372. package/dist/init-JCC7RVMC.cjs +0 -9
  373. package/dist/language-AZISJCEZ.js +0 -16
  374. package/dist/language-F65RA6FZ.cjs +0 -16
  375. package/dist/localProjectPermissions-2EATUDZM.cjs +0 -17
  376. package/dist/login-5HLPMECE.js +0 -18
  377. package/dist/login-ISWYYBXP.cjs +0 -18
  378. package/dist/logout-3EKZM5J3.cjs +0 -16
  379. package/dist/logout-GE7TSZ24.js +0 -16
  380. package/dist/mcp-EW64QRFA.cjs +0 -15
  381. package/dist/mcp-VHS7AMF2.js +0 -15
  382. package/dist/memory-2I473RU3.js +0 -9
  383. package/dist/memory-JZ6NPSP3.cjs +0 -9
  384. package/dist/model-GXZLARPT.js +0 -9
  385. package/dist/model-Y274DBDO.cjs +0 -9
  386. package/dist/new-BG5VIGZ7.cjs +0 -9
  387. package/dist/new-YXFDQOA7.js +0 -9
  388. package/dist/permissions-QILEAGBP.cjs +0 -12
  389. package/dist/permissions-WVEOVMWO.js +0 -12
  390. package/dist/quit-NC32OEJG.cjs +0 -9
  391. package/dist/quit-WRRIGU33.js +0 -9
  392. package/dist/resume-GJIKIDPR.cjs +0 -12
  393. package/dist/resume-RMJNCAOK.js +0 -12
  394. package/dist/search-UIWIXB73.js +0 -14
  395. package/dist/search-WQNXDA2E.cjs +0 -14
  396. package/dist/sessions-HPFX2GDD.js +0 -9
  397. package/dist/sessions-SAQU6MFA.cjs +0 -9
  398. package/dist/share-2WH5ZVOO.cjs +0 -13
  399. package/dist/share-PSSWWVV5.js +0 -13
  400. package/dist/skills-LJZA6PVJ.js +0 -13
  401. package/dist/skills-YTYGART7.cjs +0 -13
  402. package/dist/skills-new-3WCU3CWB.js +0 -14
  403. package/dist/skills-new-O5LFVFZU.cjs +0 -14
  404. package/dist/slashCommands-7IRDOXOQ.cjs +0 -55
  405. package/dist/slashCommands-C6CAQA25.js +0 -55
  406. package/dist/status-4EDV2LSY.cjs +0 -10
  407. package/dist/status-NU7TJDCE.js +0 -10
  408. package/dist/sync-3GFSEIAZ.js +0 -16
  409. package/dist/sync-6M3WRKMH.cjs +0 -39
  410. package/dist/sync-CQNQDNTJ.cjs +0 -16
  411. package/dist/theme-EMJGULMI.cjs +0 -16
  412. package/dist/theme-FGDSXNU3.js +0 -16
  413. package/dist/undo-CTXQYE7C.cjs +0 -9
  414. package/dist/undo-HX2ZMECP.js +0 -9
@@ -0,0 +1,4498 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+ var _chunkJ6QET7EFcjs = require('./chunk-J6QET7EF.cjs');
4
+
5
+
6
+ var _chunk4JNNTOGFcjs = require('./chunk-4JNNTOGF.cjs');
7
+
8
+
9
+
10
+
11
+
12
+
13
+ var _chunkRKJTGGMUcjs = require('./chunk-RKJTGGMU.cjs');
14
+
15
+
16
+
17
+ var _chunkZYQMLKOKcjs = require('./chunk-ZYQMLKOK.cjs');
18
+
19
+
20
+
21
+
22
+ var _chunkPGRH5Q77cjs = require('./chunk-PGRH5Q77.cjs');
23
+
24
+
25
+ var _chunkSEKD5FH3cjs = require('./chunk-SEKD5FH3.cjs');
26
+
27
+
28
+ var _chunkULQ6MDSJcjs = require('./chunk-ULQ6MDSJ.cjs');
29
+
30
+
31
+ var _chunkLJFUXC56cjs = require('./chunk-LJFUXC56.cjs');
32
+
33
+ // src/core/actionExecutor.ts
34
+ var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk);
35
+ var _diff = require('diff');
36
+
37
+ // src/ui/syntaxHighlight.ts
38
+
39
+ var _path = require('path'); var _path2 = _interopRequireDefault(_path);
40
+ var EXTENSION_MAP = {
41
+ ".ts": "typescript",
42
+ ".tsx": "typescript",
43
+ ".js": "javascript",
44
+ ".jsx": "javascript",
45
+ ".mjs": "javascript",
46
+ ".cjs": "javascript",
47
+ ".py": "python",
48
+ ".rs": "rust",
49
+ ".go": "go",
50
+ ".rb": "ruby",
51
+ ".java": "java",
52
+ ".kt": "kotlin",
53
+ ".swift": "swift",
54
+ ".c": "c",
55
+ ".cpp": "cpp",
56
+ ".h": "c",
57
+ ".hpp": "cpp",
58
+ ".cs": "csharp",
59
+ ".php": "php",
60
+ ".sh": "bash",
61
+ ".bash": "bash",
62
+ ".zsh": "bash",
63
+ ".fish": "fish",
64
+ ".json": "json",
65
+ ".yaml": "yaml",
66
+ ".yml": "yaml",
67
+ ".toml": "toml",
68
+ ".xml": "xml",
69
+ ".html": "html",
70
+ ".htm": "html",
71
+ ".css": "css",
72
+ ".scss": "css",
73
+ ".less": "css",
74
+ ".sql": "sql",
75
+ ".md": "markdown",
76
+ ".dockerfile": "dockerfile",
77
+ ".prisma": "prisma",
78
+ ".graphql": "graphql",
79
+ ".gql": "graphql"
80
+ };
81
+ var KEYWORDS = {
82
+ typescript: [
83
+ "const",
84
+ "let",
85
+ "var",
86
+ "function",
87
+ "class",
88
+ "interface",
89
+ "type",
90
+ "enum",
91
+ "import",
92
+ "export",
93
+ "from",
94
+ "default",
95
+ "async",
96
+ "await",
97
+ "return",
98
+ "if",
99
+ "else",
100
+ "for",
101
+ "while",
102
+ "do",
103
+ "switch",
104
+ "case",
105
+ "break",
106
+ "continue",
107
+ "try",
108
+ "catch",
109
+ "finally",
110
+ "throw",
111
+ "new",
112
+ "this",
113
+ "super",
114
+ "extends",
115
+ "implements",
116
+ "static",
117
+ "public",
118
+ "private",
119
+ "protected",
120
+ "readonly",
121
+ "abstract",
122
+ "as",
123
+ "is",
124
+ "in",
125
+ "of",
126
+ "typeof",
127
+ "instanceof",
128
+ "keyof",
129
+ "never",
130
+ "unknown",
131
+ "any",
132
+ "void",
133
+ "null",
134
+ "undefined",
135
+ "true",
136
+ "false"
137
+ ],
138
+ javascript: [
139
+ "const",
140
+ "let",
141
+ "var",
142
+ "function",
143
+ "class",
144
+ "import",
145
+ "export",
146
+ "from",
147
+ "default",
148
+ "async",
149
+ "await",
150
+ "return",
151
+ "if",
152
+ "else",
153
+ "for",
154
+ "while",
155
+ "do",
156
+ "switch",
157
+ "case",
158
+ "break",
159
+ "continue",
160
+ "try",
161
+ "catch",
162
+ "finally",
163
+ "throw",
164
+ "new",
165
+ "this",
166
+ "super",
167
+ "extends",
168
+ "static",
169
+ "get",
170
+ "set",
171
+ "typeof",
172
+ "instanceof",
173
+ "in",
174
+ "of",
175
+ "true",
176
+ "false",
177
+ "null",
178
+ "undefined"
179
+ ],
180
+ python: [
181
+ "def",
182
+ "class",
183
+ "import",
184
+ "from",
185
+ "as",
186
+ "return",
187
+ "if",
188
+ "elif",
189
+ "else",
190
+ "for",
191
+ "while",
192
+ "break",
193
+ "continue",
194
+ "try",
195
+ "except",
196
+ "finally",
197
+ "raise",
198
+ "with",
199
+ "as",
200
+ "pass",
201
+ "lambda",
202
+ "yield",
203
+ "global",
204
+ "nonlocal",
205
+ "assert",
206
+ "async",
207
+ "await",
208
+ "True",
209
+ "False",
210
+ "None",
211
+ "and",
212
+ "or",
213
+ "not",
214
+ "in",
215
+ "is"
216
+ ],
217
+ rust: [
218
+ "fn",
219
+ "let",
220
+ "mut",
221
+ "const",
222
+ "static",
223
+ "struct",
224
+ "enum",
225
+ "impl",
226
+ "trait",
227
+ "type",
228
+ "where",
229
+ "for",
230
+ "loop",
231
+ "while",
232
+ "if",
233
+ "else",
234
+ "match",
235
+ "return",
236
+ "break",
237
+ "continue",
238
+ "pub",
239
+ "mod",
240
+ "use",
241
+ "crate",
242
+ "super",
243
+ "self",
244
+ "Self",
245
+ "async",
246
+ "await",
247
+ "move",
248
+ "ref",
249
+ "dyn",
250
+ "true",
251
+ "false",
252
+ "as",
253
+ "in",
254
+ "unsafe"
255
+ ],
256
+ go: [
257
+ "func",
258
+ "var",
259
+ "const",
260
+ "type",
261
+ "struct",
262
+ "interface",
263
+ "map",
264
+ "chan",
265
+ "package",
266
+ "import",
267
+ "return",
268
+ "if",
269
+ "else",
270
+ "for",
271
+ "range",
272
+ "switch",
273
+ "case",
274
+ "default",
275
+ "break",
276
+ "continue",
277
+ "go",
278
+ "defer",
279
+ "select",
280
+ "fallthrough",
281
+ "true",
282
+ "false",
283
+ "nil",
284
+ "make",
285
+ "new",
286
+ "append",
287
+ "len",
288
+ "cap"
289
+ ],
290
+ bash: [
291
+ "if",
292
+ "then",
293
+ "else",
294
+ "elif",
295
+ "fi",
296
+ "for",
297
+ "while",
298
+ "do",
299
+ "done",
300
+ "case",
301
+ "esac",
302
+ "function",
303
+ "return",
304
+ "exit",
305
+ "break",
306
+ "continue",
307
+ "export",
308
+ "local",
309
+ "readonly",
310
+ "declare",
311
+ "unset",
312
+ "source",
313
+ "alias",
314
+ "echo",
315
+ "printf"
316
+ ],
317
+ sql: [
318
+ "SELECT",
319
+ "FROM",
320
+ "WHERE",
321
+ "AND",
322
+ "OR",
323
+ "NOT",
324
+ "IN",
325
+ "LIKE",
326
+ "ORDER",
327
+ "BY",
328
+ "GROUP",
329
+ "HAVING",
330
+ "JOIN",
331
+ "LEFT",
332
+ "RIGHT",
333
+ "INNER",
334
+ "OUTER",
335
+ "ON",
336
+ "AS",
337
+ "INSERT",
338
+ "INTO",
339
+ "VALUES",
340
+ "UPDATE",
341
+ "SET",
342
+ "DELETE",
343
+ "CREATE",
344
+ "TABLE",
345
+ "DROP",
346
+ "ALTER",
347
+ "INDEX",
348
+ "PRIMARY",
349
+ "KEY",
350
+ "FOREIGN",
351
+ "REFERENCES",
352
+ "NULL",
353
+ "DEFAULT",
354
+ "DISTINCT",
355
+ "LIMIT",
356
+ "OFFSET",
357
+ "UNION",
358
+ "ALL"
359
+ ]
360
+ };
361
+ var BUILTIN_TYPES = {
362
+ typescript: [
363
+ "string",
364
+ "number",
365
+ "boolean",
366
+ "object",
367
+ "symbol",
368
+ "bigint",
369
+ "Array",
370
+ "Map",
371
+ "Set",
372
+ "Promise",
373
+ "Record",
374
+ "Partial",
375
+ "Required",
376
+ "Readonly",
377
+ "Pick",
378
+ "Omit",
379
+ "Exclude",
380
+ "Extract",
381
+ "NonNullable",
382
+ "ReturnType"
383
+ ],
384
+ rust: [
385
+ "i8",
386
+ "i16",
387
+ "i32",
388
+ "i64",
389
+ "i128",
390
+ "isize",
391
+ "u8",
392
+ "u16",
393
+ "u32",
394
+ "u64",
395
+ "u128",
396
+ "usize",
397
+ "f32",
398
+ "f64",
399
+ "bool",
400
+ "char",
401
+ "str",
402
+ "String",
403
+ "Vec",
404
+ "Option",
405
+ "Result",
406
+ "Box",
407
+ "Rc",
408
+ "Arc",
409
+ "Cell",
410
+ "RefCell",
411
+ "HashMap"
412
+ ],
413
+ go: [
414
+ "int",
415
+ "int8",
416
+ "int16",
417
+ "int32",
418
+ "int64",
419
+ "uint",
420
+ "uint8",
421
+ "uint16",
422
+ "uint32",
423
+ "uint64",
424
+ "uintptr",
425
+ "float32",
426
+ "float64",
427
+ "complex64",
428
+ "complex128",
429
+ "bool",
430
+ "byte",
431
+ "rune",
432
+ "string",
433
+ "error"
434
+ ]
435
+ };
436
+ function detectLanguage(filePath, content) {
437
+ if (filePath) {
438
+ const ext = _path2.default.extname(filePath).toLowerCase();
439
+ if (EXTENSION_MAP[ext]) {
440
+ return EXTENSION_MAP[ext];
441
+ }
442
+ const basename = _path2.default.basename(filePath).toLowerCase();
443
+ if (basename === "dockerfile") return "dockerfile";
444
+ if (basename === "makefile") return "makefile";
445
+ if (basename.endsWith(".d.ts")) return "typescript";
446
+ }
447
+ if (content) {
448
+ if (content.includes("#!/bin/bash") || content.includes("#!/usr/bin/env bash")) {
449
+ return "bash";
450
+ }
451
+ if (content.includes("#!/usr/bin/env python") || content.includes("#!/usr/bin/python")) {
452
+ return "python";
453
+ }
454
+ if (content.includes("#!/usr/bin/env node")) {
455
+ return "javascript";
456
+ }
457
+ }
458
+ return "text";
459
+ }
460
+ function tokenize(code, language) {
461
+ const tokens = [];
462
+ const keywords = KEYWORDS[language] || KEYWORDS.javascript || [];
463
+ const types = BUILTIN_TYPES[language] || [];
464
+ const patterns = [
465
+ // Comments (single line)
466
+ { type: "comment", regex: /^(\/\/.*|#.*|--.*)/m },
467
+ // Comments (multi-line for JS/TS/C-style)
468
+ { type: "comment", regex: /^\/\*[\s\S]*?\*\// },
469
+ // Strings (double quotes)
470
+ { type: "string", regex: /^"(?:[^"\\]|\\.)*"/ },
471
+ // Strings (single quotes)
472
+ { type: "string", regex: /^'(?:[^'\\]|\\.)*'/ },
473
+ // Template literals
474
+ { type: "string", regex: /^`(?:[^`\\]|\\.)*`/ },
475
+ // Numbers
476
+ { type: "number", regex: /^0x[0-9a-fA-F]+|^0b[01]+|^0o[0-7]+|^\d+\.?\d*(?:[eE][+-]?\d+)?/ },
477
+ // Operators
478
+ { type: "operator", regex: /^(?:=>|===|!==|==|!=|<=|>=|&&|\|\||[+\-*/%<>=!&|^~?:])+/ },
479
+ // Punctuation
480
+ { type: "punctuation", regex: /^[{}[\]();,.]/ },
481
+ // Words (identifiers, keywords, types)
482
+ { type: "text", regex: /^[a-zA-Z_$][a-zA-Z0-9_$]*/ },
483
+ // Whitespace and other
484
+ { type: "text", regex: /^\s+/ },
485
+ { type: "text", regex: /^./ }
486
+ ];
487
+ let remaining = code;
488
+ while (remaining.length > 0) {
489
+ let matched = false;
490
+ for (const { type, regex } of patterns) {
491
+ const match = remaining.match(regex);
492
+ if (match) {
493
+ let tokenType = type;
494
+ const value = match[0];
495
+ if (type === "text" && /^[a-zA-Z_$]/.test(value)) {
496
+ if (keywords.includes(value)) {
497
+ tokenType = "keyword";
498
+ } else if (types.includes(value)) {
499
+ tokenType = "type";
500
+ } else if (/^[A-Z]/.test(value)) {
501
+ tokenType = "type";
502
+ }
503
+ }
504
+ tokens.push({ type: tokenType, value });
505
+ remaining = remaining.slice(value.length);
506
+ matched = true;
507
+ break;
508
+ }
509
+ }
510
+ if (!matched) {
511
+ tokens.push({ type: "text", value: remaining[0] });
512
+ remaining = remaining.slice(1);
513
+ }
514
+ }
515
+ return tokens;
516
+ }
517
+ function colorToken(token) {
518
+ if (_chunkPGRH5Q77cjs.isThemeInitialized.call(void 0, )) {
519
+ const theme = _chunkPGRH5Q77cjs.getTheme.call(void 0, );
520
+ switch (token.type) {
521
+ case "keyword":
522
+ return theme.fg("syntaxKeyword", token.value);
523
+ case "string":
524
+ return theme.fg("syntaxString", token.value);
525
+ case "number":
526
+ return theme.fg("syntaxNumber", token.value);
527
+ case "comment":
528
+ return theme.fg("syntaxComment", token.value);
529
+ case "type":
530
+ return theme.fg("syntaxType", token.value);
531
+ case "function":
532
+ return theme.fg("syntaxFunction", token.value);
533
+ case "operator":
534
+ return theme.fg("syntaxOperator", token.value);
535
+ case "punctuation":
536
+ return theme.fg("syntaxPunctuation", token.value);
537
+ default:
538
+ return token.value;
539
+ }
540
+ }
541
+ switch (token.type) {
542
+ case "keyword":
543
+ return _chalk2.default.magenta(token.value);
544
+ case "string":
545
+ return _chalk2.default.green(token.value);
546
+ case "number":
547
+ return _chalk2.default.yellow(token.value);
548
+ case "comment":
549
+ return _chalk2.default.gray(token.value);
550
+ case "type":
551
+ return _chalk2.default.cyan(token.value);
552
+ case "function":
553
+ return _chalk2.default.blue(token.value);
554
+ case "operator":
555
+ return _chalk2.default.white(token.value);
556
+ case "punctuation":
557
+ return _chalk2.default.white(token.value);
558
+ default:
559
+ return token.value;
560
+ }
561
+ }
562
+ function highlightLine(line, language) {
563
+ const tokens = tokenize(line, language);
564
+ return tokens.map(colorToken).join("");
565
+ }
566
+
567
+ // src/actions/dependencies.ts
568
+ var _fsextra = require('fs-extra'); var _fsextra2 = _interopRequireDefault(_fsextra);
569
+
570
+ async function readPackageManifest(cwd) {
571
+ const manifestPath = _path2.default.join(cwd, "package.json");
572
+ if (!await _fsextra2.default.pathExists(manifestPath)) {
573
+ return null;
574
+ }
575
+ return _fsextra2.default.readJson(manifestPath);
576
+ }
577
+ async function addDependency(cwd, name, version, options = {}) {
578
+ const manifest = await _asyncNullishCoalesce(await readPackageManifest(cwd), async () => ( {}));
579
+ if (options.dev) {
580
+ manifest.devDependencies = _nullishCoalesce(manifest.devDependencies, () => ( {}));
581
+ manifest.devDependencies[name] = version;
582
+ } else {
583
+ manifest.dependencies = _nullishCoalesce(manifest.dependencies, () => ( {}));
584
+ manifest.dependencies[name] = version;
585
+ }
586
+ const manifestPath = _path2.default.join(cwd, "package.json");
587
+ await _fsextra2.default.writeJson(manifestPath, manifest, { spaces: 2 });
588
+ }
589
+ async function removeDependency(cwd, name, options = {}) {
590
+ const manifest = await _asyncNullishCoalesce(await readPackageManifest(cwd), async () => ( {}));
591
+ const targetKey = options.dev ? "devDependencies" : "dependencies";
592
+ if (manifest[targetKey] && manifest[targetKey][name]) {
593
+ delete manifest[targetKey][name];
594
+ const manifestPath = _path2.default.join(cwd, "package.json");
595
+ await _fsextra2.default.writeJson(manifestPath, manifest, { spaces: 2 });
596
+ }
597
+ }
598
+
599
+ // src/actions/command.ts
600
+ var _child_process = require('child_process');
601
+
602
+ function runCommand(cmd, args, cwd, options = {}) {
603
+ if (!cmd || typeof cmd !== "string") {
604
+ return Promise.reject(new Error("Command is required and must be a string"));
605
+ }
606
+ return new Promise((resolve, reject) => {
607
+ const workDir = options.directory ? _path.join.call(void 0, cwd, options.directory) : cwd;
608
+ const spawnOptions = {
609
+ cwd: workDir,
610
+ shell: _nullishCoalesce(options.shell, () => ( false)),
611
+ env: {
612
+ ...process.env,
613
+ AUTOHAND_CLI: "1",
614
+ ...options.env
615
+ }
616
+ };
617
+ if (options.background) {
618
+ spawnOptions.detached = true;
619
+ spawnOptions.stdio = ["ignore", "pipe", "pipe"];
620
+ }
621
+ let child;
622
+ try {
623
+ child = _child_process.spawn.call(void 0, cmd, args, spawnOptions);
624
+ } catch (error) {
625
+ const err = error;
626
+ if (err.code === "ENOENT") {
627
+ reject(new Error(`Command not found: ${cmd}`));
628
+ } else {
629
+ reject(error);
630
+ }
631
+ return;
632
+ }
633
+ if (options.background) {
634
+ child.unref();
635
+ resolve({
636
+ stdout: "",
637
+ stderr: "",
638
+ code: null,
639
+ backgroundPid: child.pid,
640
+ signal: null
641
+ });
642
+ return;
643
+ }
644
+ let stdout = "";
645
+ let stderr = "";
646
+ let timeoutId;
647
+ if (options.timeout && options.timeout > 0) {
648
+ timeoutId = setTimeout(() => {
649
+ child.kill("SIGTERM");
650
+ }, options.timeout);
651
+ }
652
+ _optionalChain([child, 'access', _ => _.stdout, 'optionalAccess', _2 => _2.on, 'call', _3 => _3("data", (chunk) => {
653
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
654
+ stdout += text;
655
+ _optionalChain([options, 'access', _4 => _4.onStdout, 'optionalCall', _5 => _5(text)]);
656
+ })]);
657
+ _optionalChain([child, 'access', _6 => _6.stderr, 'optionalAccess', _7 => _7.on, 'call', _8 => _8("data", (chunk) => {
658
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
659
+ stderr += text;
660
+ _optionalChain([options, 'access', _9 => _9.onStderr, 'optionalCall', _10 => _10(text)]);
661
+ })]);
662
+ child.once("error", (error) => {
663
+ if (timeoutId) clearTimeout(timeoutId);
664
+ if (error.code === "ENOENT") {
665
+ reject(new Error(`Command not found: ${cmd}`));
666
+ } else {
667
+ reject(error);
668
+ }
669
+ });
670
+ child.once("close", (code, signal) => {
671
+ if (timeoutId) clearTimeout(timeoutId);
672
+ resolve({ stdout, stderr, code, signal });
673
+ });
674
+ });
675
+ }
676
+
677
+ // src/actions/metadata.ts
678
+ var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto);
679
+
680
+
681
+ var ALWAYS_SKIP = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", "__pycache__", ".cache"]);
682
+ async function listDirectoryTree(root, options = {}) {
683
+ const depth = _nullishCoalesce(options.depth, () => ( 2));
684
+ const maxEntries = _nullishCoalesce(options.maxEntries, () => ( 200));
685
+ const workspaceRoot = _nullishCoalesce(options.workspaceRoot, () => ( root));
686
+ const result = [];
687
+ const resolvedRoot = _path2.default.resolve(root);
688
+ const resolvedWorkspace = _path2.default.resolve(workspaceRoot);
689
+ if (!resolvedRoot.startsWith(resolvedWorkspace)) {
690
+ throw new Error(`Path ${root} is outside the workspace root.`);
691
+ }
692
+ const ignoreFilter = new (0, _chunkLJFUXC56cjs.GitIgnoreParser)(workspaceRoot);
693
+ async function walk(current, prefix, currentDepth) {
694
+ if (result.length >= maxEntries) {
695
+ return;
696
+ }
697
+ let entries;
698
+ try {
699
+ entries = await _fsextra2.default.readdir(current);
700
+ } catch (e2) {
701
+ return;
702
+ }
703
+ const slice = entries.slice(0, maxEntries - result.length);
704
+ for (const entry of slice) {
705
+ if (entry.startsWith(".")) {
706
+ continue;
707
+ }
708
+ const full = _path2.default.join(current, entry);
709
+ const rel = _path2.default.relative(workspaceRoot, full);
710
+ if (ALWAYS_SKIP.has(entry) || ignoreFilter.isIgnored(rel)) {
711
+ continue;
712
+ }
713
+ try {
714
+ const stats = await _fsextra2.default.stat(full);
715
+ result.push(`${prefix}${entry}${stats.isDirectory() ? "/" : ""}`);
716
+ if (stats.isDirectory() && currentDepth < depth) {
717
+ await walk(full, `${prefix} `, currentDepth + 1);
718
+ }
719
+ } catch (e3) {
720
+ continue;
721
+ }
722
+ if (result.length >= maxEntries) {
723
+ break;
724
+ }
725
+ }
726
+ }
727
+ await walk(root, "", 0);
728
+ return result;
729
+ }
730
+ async function fileStats(root, relativePath) {
731
+ const fullPath = _path2.default.join(root, relativePath);
732
+ if (!await _fsextra2.default.pathExists(fullPath)) {
733
+ return null;
734
+ }
735
+ const stats = await _fsextra2.default.stat(fullPath);
736
+ return {
737
+ size: stats.size,
738
+ mtime: stats.mtime.toISOString(),
739
+ isDirectory: stats.isDirectory()
740
+ };
741
+ }
742
+ async function checksumFile(root, relativePath, algorithm = "sha256") {
743
+ const fullPath = _path2.default.join(root, relativePath);
744
+ const exists = await _fsextra2.default.pathExists(fullPath);
745
+ if (!exists) {
746
+ throw new Error(`${relativePath} does not exist.`);
747
+ }
748
+ const hash = _crypto2.default.createHash(algorithm);
749
+ const stream = _fsextra2.default.createReadStream(fullPath);
750
+ return await new Promise((resolve, reject) => {
751
+ stream.on("data", (chunk) => hash.update(chunk));
752
+ stream.on("error", reject);
753
+ stream.on("end", () => resolve(hash.digest("hex")));
754
+ });
755
+ }
756
+
757
+ // src/actions/git.ts
758
+
759
+ var GIT_SAFETY = {
760
+ /** Branches where force push is blocked */
761
+ PROTECTED_BRANCHES: ["main", "master", "develop", "production", "staging"],
762
+ /** Maximum commits to push at once (to prevent accidental mass pushes) */
763
+ MAX_COMMITS_PER_PUSH: 50
764
+ };
765
+ function getCurrentBranch(cwd) {
766
+ const result = _child_process.spawnSync.call(void 0, "git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, encoding: "utf8" });
767
+ return _optionalChain([result, 'access', _11 => _11.stdout, 'optionalAccess', _12 => _12.trim, 'call', _13 => _13()]) || "";
768
+ }
769
+ function getCommitsAhead(cwd, remote = "origin", branch) {
770
+ const currentBranch = branch || getCurrentBranch(cwd);
771
+ if (!currentBranch) return 0;
772
+ const result = _child_process.spawnSync.call(void 0, "git", ["rev-list", "--count", `${remote}/${currentBranch}..HEAD`], {
773
+ cwd,
774
+ encoding: "utf8"
775
+ });
776
+ return parseInt(_optionalChain([result, 'access', _14 => _14.stdout, 'optionalAccess', _15 => _15.trim, 'call', _16 => _16()]) || "0", 10) || 0;
777
+ }
778
+ function applyGitPatch(cwd, patch) {
779
+ const result = _child_process.spawnSync.call(void 0, "git", ["apply", "-"], {
780
+ cwd,
781
+ input: patch,
782
+ encoding: "utf8"
783
+ });
784
+ if (result.status !== 0) {
785
+ throw new Error(result.stderr || "git apply failed");
786
+ }
787
+ return _nullishCoalesce(result.stdout, () => ( ""));
788
+ }
789
+ function diffFile(cwd, file) {
790
+ const result = _child_process.spawnSync.call(void 0, "git", ["diff", "--", file], { cwd, encoding: "utf8" });
791
+ if (result.status !== 0) {
792
+ throw new Error(result.stderr || `git diff failed for ${file}`);
793
+ }
794
+ return result.stdout || "No diff";
795
+ }
796
+ function checkoutFile(cwd, file) {
797
+ const result = _child_process.spawnSync.call(void 0, "git", ["checkout", "--", file], { cwd, encoding: "utf8" });
798
+ if (result.status !== 0) {
799
+ throw new Error(result.stderr || `git checkout failed for ${file}`);
800
+ }
801
+ }
802
+ function gitStatus(cwd) {
803
+ const result = _child_process.spawnSync.call(void 0, "git", ["status", "-sb"], { cwd, encoding: "utf8" });
804
+ if (result.status !== 0) {
805
+ throw new Error(result.stderr || "git status failed");
806
+ }
807
+ return result.stdout || "clean";
808
+ }
809
+ function gitListUntracked(cwd) {
810
+ const result = _child_process.spawnSync.call(void 0, "git", ["ls-files", "--others", "--exclude-standard"], { cwd, encoding: "utf8" });
811
+ if (result.status !== 0) {
812
+ throw new Error(result.stderr || "git ls-files failed");
813
+ }
814
+ return result.stdout || "";
815
+ }
816
+ function gitDiffRange(cwd, options = {}) {
817
+ const args = ["diff"];
818
+ if (options.staged) {
819
+ args.push("--staged");
820
+ }
821
+ if (options.range) {
822
+ args.push(options.range);
823
+ }
824
+ if (_optionalChain([options, 'access', _17 => _17.paths, 'optionalAccess', _18 => _18.length])) {
825
+ args.push("--", ...options.paths);
826
+ }
827
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
828
+ if (result.status !== 0) {
829
+ throw new Error(result.stderr || "git diff failed");
830
+ }
831
+ return result.stdout || "No diff output.";
832
+ }
833
+ function gitListWorktrees(cwd) {
834
+ const result = _child_process.spawnSync.call(void 0, "git", ["worktree", "list", "--porcelain"], { cwd, encoding: "utf8" });
835
+ if (result.status !== 0) {
836
+ throw new Error(result.stderr || "git worktree list failed");
837
+ }
838
+ return result.stdout || "No worktrees.";
839
+ }
840
+ function gitAddWorktree(cwd, pathArg, ref) {
841
+ const args = ["worktree", "add", pathArg];
842
+ if (ref) {
843
+ args.push(ref);
844
+ }
845
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
846
+ if (result.status !== 0) {
847
+ throw new Error(result.stderr || "git worktree add failed");
848
+ }
849
+ return result.stdout || `Added worktree at ${pathArg}`;
850
+ }
851
+ function gitRemoveWorktree(cwd, pathArg, force = false) {
852
+ const args = ["worktree", "remove"];
853
+ if (force) {
854
+ args.push("--force");
855
+ }
856
+ args.push(pathArg);
857
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
858
+ if (result.status !== 0) {
859
+ throw new Error(result.stderr || "git worktree remove failed");
860
+ }
861
+ return result.stdout || `Removed worktree ${pathArg}`;
862
+ }
863
+ function gitStash(cwd, options = {}) {
864
+ const args = ["stash", "push"];
865
+ if (options.includeUntracked) {
866
+ args.push("--include-untracked");
867
+ }
868
+ if (options.keepIndex) {
869
+ args.push("--keep-index");
870
+ }
871
+ if (options.message) {
872
+ args.push("-m", options.message);
873
+ }
874
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
875
+ if (result.status !== 0) {
876
+ throw new Error(result.stderr || "git stash failed");
877
+ }
878
+ return result.stdout || result.stderr || "Stashed changes";
879
+ }
880
+ function gitStashList(cwd) {
881
+ const result = _child_process.spawnSync.call(void 0, "git", ["stash", "list"], { cwd, encoding: "utf8" });
882
+ if (result.status !== 0) {
883
+ throw new Error(result.stderr || "git stash list failed");
884
+ }
885
+ return result.stdout || "No stashes";
886
+ }
887
+ function gitStashPop(cwd, stashRef) {
888
+ const args = ["stash", "pop"];
889
+ if (stashRef) {
890
+ args.push(stashRef);
891
+ }
892
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
893
+ if (result.status !== 0) {
894
+ throw new Error(result.stderr || "git stash pop failed");
895
+ }
896
+ return result.stdout || "Applied and dropped stash";
897
+ }
898
+ function gitStashApply(cwd, stashRef) {
899
+ const args = ["stash", "apply"];
900
+ if (stashRef) {
901
+ args.push(stashRef);
902
+ }
903
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
904
+ if (result.status !== 0) {
905
+ throw new Error(result.stderr || "git stash apply failed");
906
+ }
907
+ return result.stdout || "Applied stash";
908
+ }
909
+ function gitStashDrop(cwd, stashRef) {
910
+ const args = ["stash", "drop"];
911
+ if (stashRef) {
912
+ args.push(stashRef);
913
+ }
914
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
915
+ if (result.status !== 0) {
916
+ throw new Error(result.stderr || "git stash drop failed");
917
+ }
918
+ return result.stdout || "Dropped stash";
919
+ }
920
+ function gitBranch(cwd, branchName, options = {}) {
921
+ const args = ["branch"];
922
+ if (options.delete) {
923
+ args.push(options.force ? "-D" : "-d");
924
+ }
925
+ if (branchName) {
926
+ args.push(branchName);
927
+ }
928
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
929
+ if (result.status !== 0) {
930
+ throw new Error(result.stderr || "git branch failed");
931
+ }
932
+ return result.stdout || "Branch operation completed";
933
+ }
934
+ function gitSwitch(cwd, branchName, options = {}) {
935
+ const args = ["switch"];
936
+ if (options.create) {
937
+ args.push("-c");
938
+ }
939
+ args.push(branchName);
940
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
941
+ if (result.status !== 0) {
942
+ throw new Error(result.stderr || "git switch failed");
943
+ }
944
+ return result.stdout || `Switched to ${branchName}`;
945
+ }
946
+ function gitCherryPick(cwd, commits, options = {}) {
947
+ const args = ["cherry-pick"];
948
+ if (options.noCommit) {
949
+ args.push("--no-commit");
950
+ }
951
+ if (options.mainline !== void 0) {
952
+ args.push("-m", String(options.mainline));
953
+ }
954
+ args.push(...commits);
955
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
956
+ if (result.status !== 0) {
957
+ throw new Error(result.stderr || "git cherry-pick failed");
958
+ }
959
+ return result.stdout || `Cherry-picked ${commits.join(", ")}`;
960
+ }
961
+ function gitCherryPickAbort(cwd) {
962
+ const result = _child_process.spawnSync.call(void 0, "git", ["cherry-pick", "--abort"], { cwd, encoding: "utf8" });
963
+ if (result.status !== 0) {
964
+ throw new Error(result.stderr || "git cherry-pick --abort failed");
965
+ }
966
+ return "Cherry-pick aborted";
967
+ }
968
+ function gitCherryPickContinue(cwd) {
969
+ const result = _child_process.spawnSync.call(void 0, "git", ["cherry-pick", "--continue"], { cwd, encoding: "utf8" });
970
+ if (result.status !== 0) {
971
+ throw new Error(result.stderr || "git cherry-pick --continue failed");
972
+ }
973
+ return "Cherry-pick continued";
974
+ }
975
+ function gitRebase(cwd, upstream, options = {}) {
976
+ const currentBranch = getCurrentBranch(cwd);
977
+ if (GIT_SAFETY.PROTECTED_BRANCHES.includes(currentBranch)) {
978
+ throw new Error(
979
+ `Rebasing protected branch "${currentBranch}" is blocked. Protected branches should not be rebased as it rewrites history. Use merge instead, or switch to a feature branch first.`
980
+ );
981
+ }
982
+ const args = ["rebase"];
983
+ if (options.onto) {
984
+ args.push("--onto", options.onto);
985
+ }
986
+ if (options.autosquash) {
987
+ args.push("--autosquash");
988
+ }
989
+ args.push(upstream);
990
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
991
+ if (result.status !== 0) {
992
+ throw new Error(result.stderr || "git rebase failed");
993
+ }
994
+ return result.stdout || `Rebased onto ${upstream}`;
995
+ }
996
+ function gitRebaseAbort(cwd) {
997
+ const result = _child_process.spawnSync.call(void 0, "git", ["rebase", "--abort"], { cwd, encoding: "utf8" });
998
+ if (result.status !== 0) {
999
+ throw new Error(result.stderr || "git rebase --abort failed");
1000
+ }
1001
+ return "Rebase aborted";
1002
+ }
1003
+ function gitRebaseContinue(cwd) {
1004
+ const result = _child_process.spawnSync.call(void 0, "git", ["rebase", "--continue"], { cwd, encoding: "utf8" });
1005
+ if (result.status !== 0) {
1006
+ throw new Error(result.stderr || "git rebase --continue failed");
1007
+ }
1008
+ return "Rebase continued";
1009
+ }
1010
+ function gitRebaseSkip(cwd) {
1011
+ const result = _child_process.spawnSync.call(void 0, "git", ["rebase", "--skip"], { cwd, encoding: "utf8" });
1012
+ if (result.status !== 0) {
1013
+ throw new Error(result.stderr || "git rebase --skip failed");
1014
+ }
1015
+ return "Skipped commit and continued rebase";
1016
+ }
1017
+ function gitMerge(cwd, branch, options = {}) {
1018
+ const localBranches = _child_process.spawnSync.call(void 0, "git", ["branch", "--list"], { cwd, encoding: "utf8" });
1019
+ const remoteBranches = _child_process.spawnSync.call(void 0, "git", ["branch", "-r", "--list"], { cwd, encoding: "utf8" });
1020
+ const allBranches = (localBranches.stdout || "") + (remoteBranches.stdout || "");
1021
+ const branchExists = allBranches.split("\n").some(
1022
+ (b) => b.trim().replace("* ", "") === branch || b.trim() === `origin/${branch}` || b.trim() === branch
1023
+ );
1024
+ if (!branchExists) {
1025
+ throw new Error(
1026
+ `Branch "${branch}" not found locally or in remotes. For security, only existing branches can be merged. Run 'git fetch' first if the branch exists remotely.`
1027
+ );
1028
+ }
1029
+ const args = ["merge"];
1030
+ if (options.noCommit) {
1031
+ args.push("--no-commit");
1032
+ }
1033
+ if (options.noFastForward) {
1034
+ args.push("--no-ff");
1035
+ }
1036
+ if (options.squash) {
1037
+ args.push("--squash");
1038
+ }
1039
+ if (options.message) {
1040
+ args.push("-m", options.message);
1041
+ }
1042
+ args.push(branch);
1043
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1044
+ if (result.status !== 0) {
1045
+ throw new Error(result.stderr || "git merge failed");
1046
+ }
1047
+ return result.stdout || `Merged ${branch}`;
1048
+ }
1049
+ function gitMergeAbort(cwd) {
1050
+ const result = _child_process.spawnSync.call(void 0, "git", ["merge", "--abort"], { cwd, encoding: "utf8" });
1051
+ if (result.status !== 0) {
1052
+ throw new Error(result.stderr || "git merge --abort failed");
1053
+ }
1054
+ return "Merge aborted";
1055
+ }
1056
+ function gitCommit(cwd, options) {
1057
+ const args = ["commit", "-m", options.message];
1058
+ if (options.amend) {
1059
+ args.push("--amend");
1060
+ }
1061
+ if (options.allowEmpty) {
1062
+ args.push("--allow-empty");
1063
+ }
1064
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1065
+ if (result.status !== 0) {
1066
+ throw new Error(result.stderr || "git commit failed");
1067
+ }
1068
+ return result.stdout || "Committed";
1069
+ }
1070
+ function gitAdd(cwd, paths) {
1071
+ const args = ["add", ...paths];
1072
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1073
+ if (result.status !== 0) {
1074
+ throw new Error(result.stderr || "git add failed");
1075
+ }
1076
+ return result.stdout || `Staged ${paths.join(", ")}`;
1077
+ }
1078
+ function gitReset(cwd, mode = "mixed", ref) {
1079
+ if (mode === "hard") {
1080
+ const currentBranch = getCurrentBranch(cwd);
1081
+ if (GIT_SAFETY.PROTECTED_BRANCHES.includes(currentBranch)) {
1082
+ throw new Error(
1083
+ `Hard reset on protected branch "${currentBranch}" is blocked for safety.
1084
+ Protected branches: ${GIT_SAFETY.PROTECTED_BRANCHES.join(", ")}
1085
+ Use soft or mixed reset instead, or switch to a feature branch.`
1086
+ );
1087
+ }
1088
+ }
1089
+ const args = ["reset", `--${mode}`];
1090
+ if (ref) {
1091
+ args.push(ref);
1092
+ }
1093
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1094
+ if (result.status !== 0) {
1095
+ throw new Error(result.stderr || "git reset failed");
1096
+ }
1097
+ return result.stdout || `Reset ${mode}${ref ? ` to ${ref}` : ""}`;
1098
+ }
1099
+ function isGitRepository(cwd) {
1100
+ const result = _child_process.spawnSync.call(void 0, "git", ["rev-parse", "--is-inside-work-tree"], { cwd, encoding: "utf8" });
1101
+ return result.status === 0;
1102
+ }
1103
+ function getAutoCommitInfo(cwd) {
1104
+ if (!isGitRepository(cwd)) {
1105
+ return {
1106
+ canCommit: false,
1107
+ error: "Not a git repository",
1108
+ filesChanged: [],
1109
+ suggestedMessage: "",
1110
+ diffSummary: ""
1111
+ };
1112
+ }
1113
+ const statusResult = _child_process.spawnSync.call(void 0, "git", ["status", "--porcelain"], { cwd, encoding: "utf8" });
1114
+ if (statusResult.status !== 0) {
1115
+ return {
1116
+ canCommit: false,
1117
+ error: "Failed to get git status",
1118
+ filesChanged: [],
1119
+ suggestedMessage: "",
1120
+ diffSummary: ""
1121
+ };
1122
+ }
1123
+ const changes = _optionalChain([statusResult, 'access', _19 => _19.stdout, 'optionalAccess', _20 => _20.trim, 'call', _21 => _21(), 'access', _22 => _22.split, 'call', _23 => _23("\n"), 'access', _24 => _24.filter, 'call', _25 => _25(Boolean)]) || [];
1124
+ if (changes.length === 0) {
1125
+ return {
1126
+ canCommit: false,
1127
+ error: "No changes to commit",
1128
+ filesChanged: [],
1129
+ suggestedMessage: "",
1130
+ diffSummary: ""
1131
+ };
1132
+ }
1133
+ const added = [];
1134
+ const modified = [];
1135
+ const deleted = [];
1136
+ const renamed = [];
1137
+ for (const change of changes) {
1138
+ const status = change.substring(0, 2);
1139
+ const file = change.substring(3).trim();
1140
+ if (status.includes("A") || status === "??") {
1141
+ added.push(file);
1142
+ } else if (status.includes("M")) {
1143
+ modified.push(file);
1144
+ } else if (status.includes("D")) {
1145
+ deleted.push(file);
1146
+ } else if (status.includes("R")) {
1147
+ renamed.push(file);
1148
+ }
1149
+ }
1150
+ const diffStatResult = _child_process.spawnSync.call(void 0, "git", ["diff", "--stat", "HEAD"], { cwd, encoding: "utf8" });
1151
+ const diffSummary = _optionalChain([diffStatResult, 'access', _26 => _26.stdout, 'optionalAccess', _27 => _27.trim, 'call', _28 => _28()]) || "";
1152
+ const suggestedMessage = generateCommitMessage(added, modified, deleted, renamed);
1153
+ return {
1154
+ canCommit: true,
1155
+ filesChanged: changes.map((c) => c.substring(3).trim()),
1156
+ suggestedMessage,
1157
+ diffSummary
1158
+ };
1159
+ }
1160
+ function generateCommitMessage(added, modified, deleted, renamed) {
1161
+ const parts = [];
1162
+ const totalChanges = added.length + modified.length + deleted.length + renamed.length;
1163
+ if (totalChanges === 1) {
1164
+ if (added.length === 1) {
1165
+ return `feat: Add ${added[0]}`;
1166
+ } else if (modified.length === 1) {
1167
+ return `update: Modify ${modified[0]}`;
1168
+ } else if (deleted.length === 1) {
1169
+ return `chore: Remove ${deleted[0]}`;
1170
+ } else if (renamed.length === 1) {
1171
+ return `refactor: Rename ${renamed[0]}`;
1172
+ }
1173
+ }
1174
+ if (added.length > 0) {
1175
+ parts.push(`add ${added.length} file${added.length > 1 ? "s" : ""}`);
1176
+ }
1177
+ if (modified.length > 0) {
1178
+ parts.push(`update ${modified.length} file${modified.length > 1 ? "s" : ""}`);
1179
+ }
1180
+ if (deleted.length > 0) {
1181
+ parts.push(`remove ${deleted.length} file${deleted.length > 1 ? "s" : ""}`);
1182
+ }
1183
+ if (renamed.length > 0) {
1184
+ parts.push(`rename ${renamed.length} file${renamed.length > 1 ? "s" : ""}`);
1185
+ }
1186
+ const allFiles = [...added, ...modified];
1187
+ const hasTests = allFiles.some((f) => f.includes("test") || f.includes("spec"));
1188
+ const hasDocs = allFiles.some((f) => f.includes(".md") || f.includes("doc"));
1189
+ const hasConfig = allFiles.some((f) => f.includes("config") || f.includes(".json") || f.includes(".yaml"));
1190
+ let prefix = "chore";
1191
+ if (added.length > modified.length && added.length > deleted.length) {
1192
+ prefix = "feat";
1193
+ } else if (hasTests) {
1194
+ prefix = "test";
1195
+ } else if (hasDocs) {
1196
+ prefix = "docs";
1197
+ } else if (hasConfig) {
1198
+ prefix = "chore";
1199
+ } else if (modified.length > 0) {
1200
+ prefix = "update";
1201
+ }
1202
+ return `${prefix}: ${parts.join(", ")}`;
1203
+ }
1204
+ function executeAutoCommit(cwd, message, stageAll = true) {
1205
+ const statusResult = _child_process.spawnSync.call(void 0, "git", ["status", "--porcelain"], { cwd, encoding: "utf8" });
1206
+ const changes = _optionalChain([statusResult, 'access', _29 => _29.stdout, 'optionalAccess', _30 => _30.trim, 'call', _31 => _31(), 'access', _32 => _32.split, 'call', _33 => _33("\n"), 'access', _34 => _34.filter, 'call', _35 => _35(Boolean)]) || [];
1207
+ if (stageAll) {
1208
+ const addResult = _child_process.spawnSync.call(void 0, "git", ["add", "-A"], { cwd, encoding: "utf8" });
1209
+ if (addResult.status !== 0) {
1210
+ return {
1211
+ success: false,
1212
+ message: `Failed to stage changes: ${addResult.stderr}`,
1213
+ filesChanged: 0
1214
+ };
1215
+ }
1216
+ }
1217
+ const commitResult = _child_process.spawnSync.call(void 0, "git", ["commit", "-m", message], { cwd, encoding: "utf8" });
1218
+ if (commitResult.status !== 0) {
1219
+ return {
1220
+ success: false,
1221
+ message: `Failed to commit: ${commitResult.stderr}`,
1222
+ filesChanged: changes.length
1223
+ };
1224
+ }
1225
+ const hashResult = _child_process.spawnSync.call(void 0, "git", ["rev-parse", "--short", "HEAD"], { cwd, encoding: "utf8" });
1226
+ const commitHash = _optionalChain([hashResult, 'access', _36 => _36.stdout, 'optionalAccess', _37 => _37.trim, 'call', _38 => _38()]);
1227
+ return {
1228
+ success: true,
1229
+ message: `Committed ${changes.length} file(s): ${commitHash}`,
1230
+ filesChanged: changes.length,
1231
+ commitHash
1232
+ };
1233
+ }
1234
+ function gitLog(cwd, options = {}) {
1235
+ const args = ["log"];
1236
+ if (options.maxCount) {
1237
+ args.push(`-n${options.maxCount}`);
1238
+ }
1239
+ if (options.oneline) {
1240
+ args.push("--oneline");
1241
+ }
1242
+ if (options.graph) {
1243
+ args.push("--graph");
1244
+ }
1245
+ if (options.all) {
1246
+ args.push("--all");
1247
+ }
1248
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1249
+ if (result.status !== 0) {
1250
+ throw new Error(result.stderr || "git log failed");
1251
+ }
1252
+ return result.stdout || "No commits";
1253
+ }
1254
+ function gitFetch(cwd, remote, branch) {
1255
+ const args = ["fetch"];
1256
+ if (remote) {
1257
+ args.push(remote);
1258
+ if (branch) {
1259
+ args.push(branch);
1260
+ }
1261
+ }
1262
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1263
+ if (result.status !== 0) {
1264
+ throw new Error(result.stderr || "git fetch failed");
1265
+ }
1266
+ return result.stdout || result.stderr || "Fetched";
1267
+ }
1268
+ function gitPull(cwd, remote, branch) {
1269
+ const args = ["pull"];
1270
+ if (remote) {
1271
+ args.push(remote);
1272
+ if (branch) {
1273
+ args.push(branch);
1274
+ }
1275
+ }
1276
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1277
+ if (result.status !== 0) {
1278
+ throw new Error(result.stderr || "git pull failed");
1279
+ }
1280
+ return result.stdout || "Pulled";
1281
+ }
1282
+ function gitPush(cwd, remote, branch, options = {}) {
1283
+ const targetRemote = remote || "origin";
1284
+ const targetBranch = branch || getCurrentBranch(cwd);
1285
+ if (options.force && GIT_SAFETY.PROTECTED_BRANCHES.includes(targetBranch)) {
1286
+ throw new Error(
1287
+ `Force push to protected branch "${targetBranch}" is blocked. Protected branches: ${GIT_SAFETY.PROTECTED_BRANCHES.join(", ")}`
1288
+ );
1289
+ }
1290
+ const commitsAhead = getCommitsAhead(cwd, targetRemote, targetBranch);
1291
+ if (commitsAhead > GIT_SAFETY.MAX_COMMITS_PER_PUSH) {
1292
+ throw new Error(
1293
+ `Too many commits to push (${commitsAhead}). Maximum allowed: ${GIT_SAFETY.MAX_COMMITS_PER_PUSH}. This limit exists to prevent accidental large pushes. Push manually if intentional.`
1294
+ );
1295
+ }
1296
+ const args = ["push"];
1297
+ if (options.force) {
1298
+ args.push("--force-with-lease");
1299
+ }
1300
+ if (options.setUpstream) {
1301
+ args.push("--set-upstream");
1302
+ }
1303
+ if (remote) {
1304
+ args.push(remote);
1305
+ if (branch) {
1306
+ args.push(branch);
1307
+ }
1308
+ }
1309
+ const result = _child_process.spawnSync.call(void 0, "git", args, { cwd, encoding: "utf8" });
1310
+ if (result.status !== 0) {
1311
+ throw new Error(result.stderr || "git push failed");
1312
+ }
1313
+ return result.stdout || result.stderr || "Pushed";
1314
+ }
1315
+
1316
+ // src/actions/worktree.ts
1317
+
1318
+
1319
+
1320
+ var _os = require('os'); var _os2 = _interopRequireDefault(_os);
1321
+ var DEFAULT_TEMPLATES = [
1322
+ {
1323
+ name: "feature",
1324
+ description: "Feature branch worktree",
1325
+ pathPattern: "../{repo}-feature-{branch}",
1326
+ setupCommands: ["npm install || yarn install || pnpm install || true"]
1327
+ },
1328
+ {
1329
+ name: "hotfix",
1330
+ description: "Hotfix branch from main/master",
1331
+ pathPattern: "../{repo}-hotfix-{branch}",
1332
+ setupCommands: ["npm install || yarn install || pnpm install || true"]
1333
+ },
1334
+ {
1335
+ name: "release",
1336
+ description: "Release branch worktree",
1337
+ pathPattern: "../{repo}-release-{branch}",
1338
+ setupCommands: ["npm install || yarn install || pnpm install || true"]
1339
+ },
1340
+ {
1341
+ name: "review",
1342
+ description: "PR review worktree",
1343
+ pathPattern: "../{repo}-review-{branch}",
1344
+ setupCommands: []
1345
+ },
1346
+ {
1347
+ name: "experiment",
1348
+ description: "Experimental detached worktree",
1349
+ pathPattern: "../{repo}-experiment-{timestamp}",
1350
+ setupCommands: []
1351
+ }
1352
+ ];
1353
+ var WorktreeManager = class {
1354
+ constructor(cwd) {
1355
+ this.repoRoot = this.findGitRoot(cwd);
1356
+ this.repoName = _path2.default.basename(this.repoRoot);
1357
+ this.templates = [...DEFAULT_TEMPLATES];
1358
+ }
1359
+ // ============ Core Operations ============
1360
+ /**
1361
+ * List all worktrees with detailed information
1362
+ */
1363
+ list() {
1364
+ const result = _child_process.spawnSync.call(void 0, "git", ["worktree", "list", "--porcelain"], {
1365
+ cwd: this.repoRoot,
1366
+ encoding: "utf8"
1367
+ });
1368
+ if (result.status !== 0) {
1369
+ throw new Error(result.stderr || "Failed to list worktrees");
1370
+ }
1371
+ return this.parseWorktreeList(result.stdout);
1372
+ }
1373
+ /**
1374
+ * Get comprehensive status of all worktrees
1375
+ */
1376
+ async statusAll() {
1377
+ const worktrees = this.list();
1378
+ const statuses = [];
1379
+ for (const wt of worktrees) {
1380
+ if (wt.bare) continue;
1381
+ try {
1382
+ const status = await this.getWorktreeStatus(wt);
1383
+ statuses.push(status);
1384
+ } catch (e4) {
1385
+ statuses.push({
1386
+ worktree: wt,
1387
+ gitStatus: { staged: 0, modified: 0, untracked: 0, conflicts: 0, ahead: 0, behind: 0 },
1388
+ isClean: false,
1389
+ lastCommit: null
1390
+ });
1391
+ }
1392
+ }
1393
+ return statuses;
1394
+ }
1395
+ /**
1396
+ * Smart worktree creation with templates
1397
+ */
1398
+ async create(options) {
1399
+ const branch = options.branch || `worktree-${Date.now()}`;
1400
+ const template = options.template ? this.getTemplate(options.template) : null;
1401
+ let worktreePath;
1402
+ if (template) {
1403
+ worktreePath = this.resolvePath(template.pathPattern, branch);
1404
+ } else {
1405
+ worktreePath = _path2.default.join(_path2.default.dirname(this.repoRoot), `${this.repoName}-${branch}`);
1406
+ }
1407
+ await _fsextra2.default.ensureDir(_path2.default.dirname(worktreePath));
1408
+ const args = ["worktree", "add"];
1409
+ if (options.newBranch) {
1410
+ args.push("-b", branch);
1411
+ if (options.baseBranch) {
1412
+ args.push(worktreePath, options.baseBranch);
1413
+ } else {
1414
+ args.push(worktreePath);
1415
+ }
1416
+ } else if (options.detach) {
1417
+ args.push("--detach", worktreePath);
1418
+ if (options.branch) {
1419
+ args.push(options.branch);
1420
+ }
1421
+ } else {
1422
+ args.push(worktreePath);
1423
+ if (options.branch) {
1424
+ args.push(options.branch);
1425
+ }
1426
+ }
1427
+ if (options.force) {
1428
+ args.splice(2, 0, "--force");
1429
+ }
1430
+ const result = _child_process.spawnSync.call(void 0, "git", args, {
1431
+ cwd: this.repoRoot,
1432
+ encoding: "utf8"
1433
+ });
1434
+ if (result.status !== 0) {
1435
+ throw new Error(result.stderr || "Failed to create worktree");
1436
+ }
1437
+ if (_optionalChain([template, 'optionalAccess', _39 => _39.setupCommands]) && options.runSetup !== false) {
1438
+ for (const cmd of template.setupCommands) {
1439
+ await this.runInWorktree(worktreePath, cmd);
1440
+ }
1441
+ }
1442
+ return { path: worktreePath, branch };
1443
+ }
1444
+ /**
1445
+ * Remove a worktree with cleanup
1446
+ */
1447
+ async remove(worktreePath, options = {}) {
1448
+ const absolutePath = _path2.default.isAbsolute(worktreePath) ? worktreePath : _path2.default.resolve(this.repoRoot, worktreePath);
1449
+ const worktrees = this.list();
1450
+ const wt = worktrees.find((w) => w.path === absolutePath);
1451
+ const branchToDelete = _optionalChain([wt, 'optionalAccess', _40 => _40.branch]);
1452
+ const args = ["worktree", "remove"];
1453
+ if (options.force) {
1454
+ args.push("--force");
1455
+ }
1456
+ args.push(absolutePath);
1457
+ const result = _child_process.spawnSync.call(void 0, "git", args, {
1458
+ cwd: this.repoRoot,
1459
+ encoding: "utf8"
1460
+ });
1461
+ if (result.status !== 0) {
1462
+ throw new Error(result.stderr || "Failed to remove worktree");
1463
+ }
1464
+ if (options.deleteBranch && branchToDelete) {
1465
+ const deleteResult = _child_process.spawnSync.call(void 0, "git", ["branch", "-d", branchToDelete], {
1466
+ cwd: this.repoRoot,
1467
+ encoding: "utf8"
1468
+ });
1469
+ if (deleteResult.status === 0) {
1470
+ return `Removed worktree and deleted branch ${branchToDelete}`;
1471
+ }
1472
+ }
1473
+ return `Removed worktree at ${absolutePath}`;
1474
+ }
1475
+ // ============ Advanced Operations ============
1476
+ /**
1477
+ * Find and clean up stale/merged worktrees
1478
+ */
1479
+ async cleanup(options = {}) {
1480
+ const worktrees = this.list();
1481
+ const mainBranch = this.getMainBranch();
1482
+ const toRemove = [];
1483
+ for (const wt of worktrees) {
1484
+ if (wt.bare || wt.path === this.repoRoot) continue;
1485
+ if (options.removeStale !== false && wt.prunable) {
1486
+ toRemove.push(wt);
1487
+ continue;
1488
+ }
1489
+ if (options.removeMerged && wt.branch) {
1490
+ const isMerged = this.isBranchMerged(wt.branch, mainBranch);
1491
+ if (isMerged) {
1492
+ toRemove.push(wt);
1493
+ }
1494
+ }
1495
+ }
1496
+ if (options.dryRun) {
1497
+ return { removed: [], wouldRemove: toRemove.map((w) => w.path) };
1498
+ }
1499
+ const removed = [];
1500
+ for (const wt of toRemove) {
1501
+ try {
1502
+ await this.remove(wt.path, { force: true, deleteBranch: options.removeMerged });
1503
+ removed.push(wt.path);
1504
+ } catch (e5) {
1505
+ }
1506
+ }
1507
+ _child_process.spawnSync.call(void 0, "git", ["worktree", "prune"], { cwd: this.repoRoot });
1508
+ return { removed, wouldRemove: [] };
1509
+ }
1510
+ /**
1511
+ * Run a command in parallel across all worktrees
1512
+ */
1513
+ async runParallel(command, options = {}) {
1514
+ const worktrees = this.list().filter((wt) => !wt.bare);
1515
+ const filtered = options.filter ? worktrees.filter(options.filter) : worktrees;
1516
+ const maxConcurrent = options.maxConcurrent || _os2.default.cpus().length;
1517
+ const timeout = options.timeout || 3e5;
1518
+ const results = [];
1519
+ const running = [];
1520
+ for (const wt of filtered) {
1521
+ const task = (async () => {
1522
+ const start = Date.now();
1523
+ try {
1524
+ const output = await this.runInWorktreeWithTimeout(wt.path, command, timeout);
1525
+ results.push({
1526
+ worktree: wt.path,
1527
+ branch: wt.branch,
1528
+ success: true,
1529
+ output,
1530
+ exitCode: 0,
1531
+ duration: Date.now() - start
1532
+ });
1533
+ } catch (error) {
1534
+ results.push({
1535
+ worktree: wt.path,
1536
+ branch: wt.branch,
1537
+ success: false,
1538
+ output: "",
1539
+ error: error.message,
1540
+ exitCode: error.exitCode || 1,
1541
+ duration: Date.now() - start
1542
+ });
1543
+ }
1544
+ })();
1545
+ running.push(task);
1546
+ if (running.length >= maxConcurrent) {
1547
+ await Promise.race(running);
1548
+ }
1549
+ }
1550
+ await Promise.all(running);
1551
+ return results;
1552
+ }
1553
+ /**
1554
+ * Sync changes from main branch to all worktrees
1555
+ */
1556
+ async syncAll(options = {}) {
1557
+ const mainBranch = options.mainBranch || this.getMainBranch();
1558
+ const strategy = options.strategy || "rebase";
1559
+ const worktrees = this.list().filter((wt) => !wt.bare && wt.branch && wt.branch !== mainBranch);
1560
+ _child_process.spawnSync.call(void 0, "git", ["fetch", "--all"], { cwd: this.repoRoot });
1561
+ const synced = [];
1562
+ const failed = [];
1563
+ const skipped = [];
1564
+ for (const wt of worktrees) {
1565
+ const status = await this.getWorktreeStatus(wt);
1566
+ if (!status.isClean) {
1567
+ skipped.push(`${wt.path} (has uncommitted changes)`);
1568
+ continue;
1569
+ }
1570
+ if (options.dryRun) {
1571
+ synced.push(wt.path);
1572
+ continue;
1573
+ }
1574
+ try {
1575
+ const cmd = strategy === "rebase" ? `git rebase origin/${mainBranch}` : `git merge origin/${mainBranch}`;
1576
+ await this.runInWorktree(wt.path, cmd);
1577
+ synced.push(wt.path);
1578
+ } catch (error) {
1579
+ try {
1580
+ await this.runInWorktree(wt.path, `git ${strategy} --abort`);
1581
+ } catch (e6) {
1582
+ }
1583
+ failed.push(`${wt.path}: ${error.message}`);
1584
+ }
1585
+ }
1586
+ return { synced, failed, skipped };
1587
+ }
1588
+ /**
1589
+ * Create a worktree for a PR review
1590
+ */
1591
+ async createForPR(prNumber, remote = "origin") {
1592
+ const branch = `pr-${prNumber}`;
1593
+ const fetchResult = _child_process.spawnSync.call(void 0, "git", ["fetch", remote, `pull/${prNumber}/head:${branch}`], {
1594
+ cwd: this.repoRoot,
1595
+ encoding: "utf8"
1596
+ });
1597
+ if (fetchResult.status !== 0) {
1598
+ throw new Error(`Failed to fetch PR #${prNumber}: ${fetchResult.stderr}`);
1599
+ }
1600
+ return this.create({
1601
+ branch,
1602
+ template: "review",
1603
+ runSetup: true
1604
+ });
1605
+ }
1606
+ /**
1607
+ * Switch to a worktree (opens in current terminal context)
1608
+ */
1609
+ getWorktreePath(branchOrPath) {
1610
+ const worktrees = this.list();
1611
+ const byPath = worktrees.find((wt) => wt.path === branchOrPath || wt.path.endsWith(branchOrPath));
1612
+ if (byPath) return byPath.path;
1613
+ const byBranch = worktrees.find((wt) => wt.branch === branchOrPath);
1614
+ if (byBranch) return byBranch.path;
1615
+ return null;
1616
+ }
1617
+ // ============ Template Management ============
1618
+ getTemplates() {
1619
+ return [...this.templates];
1620
+ }
1621
+ getTemplate(name) {
1622
+ return this.templates.find((t) => t.name === name) || null;
1623
+ }
1624
+ addTemplate(template) {
1625
+ const existing = this.templates.findIndex((t) => t.name === template.name);
1626
+ if (existing >= 0) {
1627
+ this.templates[existing] = template;
1628
+ } else {
1629
+ this.templates.push(template);
1630
+ }
1631
+ }
1632
+ // ============ Helper Methods ============
1633
+ findGitRoot(cwd) {
1634
+ const result = _child_process.spawnSync.call(void 0, "git", ["rev-parse", "--show-toplevel"], {
1635
+ cwd,
1636
+ encoding: "utf8"
1637
+ });
1638
+ if (result.status !== 0) {
1639
+ throw new Error("Not a git repository");
1640
+ }
1641
+ return result.stdout.trim();
1642
+ }
1643
+ parseWorktreeList(output) {
1644
+ const worktrees = [];
1645
+ const entries = output.trim().split("\n\n");
1646
+ for (const entry of entries) {
1647
+ if (!entry.trim()) continue;
1648
+ const lines = entry.split("\n");
1649
+ const info = {
1650
+ bare: false,
1651
+ detached: false,
1652
+ locked: false,
1653
+ prunable: false
1654
+ };
1655
+ for (const line of lines) {
1656
+ if (line.startsWith("worktree ")) {
1657
+ info.path = line.slice(9);
1658
+ } else if (line.startsWith("HEAD ")) {
1659
+ info.head = line.slice(5);
1660
+ } else if (line.startsWith("branch ")) {
1661
+ info.branch = line.slice(7).replace("refs/heads/", "");
1662
+ } else if (line === "bare") {
1663
+ info.bare = true;
1664
+ } else if (line === "detached") {
1665
+ info.detached = true;
1666
+ } else if (line.startsWith("locked")) {
1667
+ info.locked = true;
1668
+ } else if (line.startsWith("prunable")) {
1669
+ info.prunable = true;
1670
+ }
1671
+ }
1672
+ if (info.path && info.head) {
1673
+ worktrees.push(info);
1674
+ }
1675
+ }
1676
+ return worktrees;
1677
+ }
1678
+ async getWorktreeStatus(wt) {
1679
+ const statusResult = _child_process.spawnSync.call(void 0, "git", ["status", "--porcelain=v1", "-b"], {
1680
+ cwd: wt.path,
1681
+ encoding: "utf8"
1682
+ });
1683
+ const lines = statusResult.stdout.trim().split("\n");
1684
+ const branchLine = lines[0] || "";
1685
+ const fileLines = lines.slice(1);
1686
+ let ahead = 0;
1687
+ let behind = 0;
1688
+ const aheadBehindMatch = branchLine.match(/\[ahead (\d+)(?:, behind (\d+))?\]|\[behind (\d+)\]/);
1689
+ if (aheadBehindMatch) {
1690
+ ahead = parseInt(aheadBehindMatch[1] || "0", 10);
1691
+ behind = parseInt(aheadBehindMatch[2] || aheadBehindMatch[3] || "0", 10);
1692
+ }
1693
+ let staged = 0, modified = 0, untracked = 0, conflicts = 0;
1694
+ for (const line of fileLines) {
1695
+ if (!line) continue;
1696
+ const x = line[0];
1697
+ const y = line[1];
1698
+ if (x === "U" || y === "U" || x === "D" && y === "D" || x === "A" && y === "A") {
1699
+ conflicts++;
1700
+ } else {
1701
+ if (x !== " " && x !== "?") staged++;
1702
+ if (y === "M" || y === "D") modified++;
1703
+ if (x === "?") untracked++;
1704
+ }
1705
+ }
1706
+ const logResult = _child_process.spawnSync.call(void 0, "git", ["log", "-1", "--format=%H|%s|%an|%ai"], {
1707
+ cwd: wt.path,
1708
+ encoding: "utf8"
1709
+ });
1710
+ let lastCommit = null;
1711
+ if (logResult.status === 0 && logResult.stdout.trim()) {
1712
+ const [hash, message, author, date] = logResult.stdout.trim().split("|");
1713
+ lastCommit = { hash, message, author, date };
1714
+ }
1715
+ return {
1716
+ worktree: wt,
1717
+ gitStatus: { staged, modified, untracked, conflicts, ahead, behind },
1718
+ isClean: staged === 0 && modified === 0 && untracked === 0 && conflicts === 0,
1719
+ lastCommit
1720
+ };
1721
+ }
1722
+ getMainBranch() {
1723
+ const result = _child_process.spawnSync.call(void 0, "git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
1724
+ cwd: this.repoRoot,
1725
+ encoding: "utf8"
1726
+ });
1727
+ if (result.status === 0) {
1728
+ return result.stdout.trim().replace("refs/remotes/origin/", "");
1729
+ }
1730
+ const branches = _child_process.spawnSync.call(void 0, "git", ["branch", "-l", "main", "master"], {
1731
+ cwd: this.repoRoot,
1732
+ encoding: "utf8"
1733
+ });
1734
+ if (branches.stdout.includes("main")) return "main";
1735
+ if (branches.stdout.includes("master")) return "master";
1736
+ return "main";
1737
+ }
1738
+ isBranchMerged(branch, into) {
1739
+ const result = _child_process.spawnSync.call(void 0, "git", ["branch", "--merged", into], {
1740
+ cwd: this.repoRoot,
1741
+ encoding: "utf8"
1742
+ });
1743
+ if (result.status !== 0) return false;
1744
+ return result.stdout.split("\n").some(
1745
+ (line) => line.trim() === branch || line.trim() === `* ${branch}`
1746
+ );
1747
+ }
1748
+ resolvePath(pattern, branch) {
1749
+ const timestamp = Date.now().toString();
1750
+ const sanitizedBranch = branch.replace(/[^a-zA-Z0-9-_]/g, "-");
1751
+ return _path2.default.resolve(
1752
+ this.repoRoot,
1753
+ pattern.replace("{repo}", this.repoName).replace("{branch}", sanitizedBranch).replace("{timestamp}", timestamp)
1754
+ );
1755
+ }
1756
+ async runInWorktree(worktreePath, command) {
1757
+ return new Promise((resolve, reject) => {
1758
+ const child = _child_process.spawn.call(void 0, "sh", ["-c", command], {
1759
+ cwd: worktreePath,
1760
+ stdio: ["pipe", "pipe", "pipe"]
1761
+ });
1762
+ let stdout = "";
1763
+ let stderr = "";
1764
+ child.stdout.on("data", (data) => {
1765
+ stdout += data;
1766
+ });
1767
+ child.stderr.on("data", (data) => {
1768
+ stderr += data;
1769
+ });
1770
+ child.on("close", (code) => {
1771
+ if (code === 0) {
1772
+ resolve(stdout);
1773
+ } else {
1774
+ const error = new Error(stderr || `Command failed with code ${code}`);
1775
+ error.exitCode = code;
1776
+ reject(error);
1777
+ }
1778
+ });
1779
+ });
1780
+ }
1781
+ async runInWorktreeWithTimeout(worktreePath, command, timeout) {
1782
+ return new Promise((resolve, reject) => {
1783
+ const child = _child_process.spawn.call(void 0, "sh", ["-c", command], {
1784
+ cwd: worktreePath,
1785
+ stdio: ["pipe", "pipe", "pipe"]
1786
+ });
1787
+ let stdout = "";
1788
+ let stderr = "";
1789
+ let killed = false;
1790
+ const timer = setTimeout(() => {
1791
+ killed = true;
1792
+ child.kill("SIGTERM");
1793
+ reject(new Error(`Command timed out after ${timeout}ms`));
1794
+ }, timeout);
1795
+ child.stdout.on("data", (data) => {
1796
+ stdout += data;
1797
+ });
1798
+ child.stderr.on("data", (data) => {
1799
+ stderr += data;
1800
+ });
1801
+ child.on("close", (code) => {
1802
+ clearTimeout(timer);
1803
+ if (killed) return;
1804
+ if (code === 0) {
1805
+ resolve(stdout);
1806
+ } else {
1807
+ const error = new Error(stderr || `Command failed with code ${code}`);
1808
+ error.exitCode = code;
1809
+ reject(error);
1810
+ }
1811
+ });
1812
+ });
1813
+ }
1814
+ };
1815
+
1816
+ // src/core/customCommands.ts
1817
+
1818
+
1819
+ var COMMANDS_DIR = _chunkSEKD5FH3cjs.AUTOHAND_PATHS.commands;
1820
+ async function loadCustomCommand(name) {
1821
+ const filePath = _path2.default.join(COMMANDS_DIR, `${sanitizeName(name)}.json`);
1822
+ if (!await _fsextra2.default.pathExists(filePath)) {
1823
+ return null;
1824
+ }
1825
+ return _fsextra2.default.readJson(filePath);
1826
+ }
1827
+ async function saveCustomCommand(definition) {
1828
+ await _fsextra2.default.ensureDir(COMMANDS_DIR);
1829
+ const filePath = _path2.default.join(COMMANDS_DIR, `${sanitizeName(definition.name)}.json`);
1830
+ await _fsextra2.default.writeJson(filePath, definition, { spaces: 2 });
1831
+ }
1832
+ function sanitizeName(name) {
1833
+ return name.replace(/[^a-z0-9-_]/gi, "_");
1834
+ }
1835
+
1836
+ // src/actions/webRepo.ts
1837
+ var _https = require('https'); var https = _interopRequireWildcard(_https);
1838
+ function parseRepoUrl(input) {
1839
+ const shorthandMatch = input.match(/^(github|gitlab):(.+)$/);
1840
+ if (shorthandMatch) {
1841
+ const platform = shorthandMatch[1];
1842
+ const path8 = shorthandMatch[2];
1843
+ const lastSlash = path8.lastIndexOf("/");
1844
+ if (lastSlash === -1) {
1845
+ throw new Error("Could not parse repo URL. Use format: owner/repo (GitHub), github:owner/repo, gitlab:group/project, or full URL.");
1846
+ }
1847
+ return {
1848
+ platform,
1849
+ owner: path8.slice(0, lastSlash),
1850
+ repo: path8.slice(lastSlash + 1)
1851
+ };
1852
+ }
1853
+ if (!input.includes(":") && input.includes("/")) {
1854
+ const slashIndex = input.indexOf("/");
1855
+ const lastSlashIndex = input.lastIndexOf("/");
1856
+ if (slashIndex === lastSlashIndex && slashIndex > 0) {
1857
+ const owner = input.slice(0, slashIndex);
1858
+ const repo = input.slice(slashIndex + 1);
1859
+ if (owner && repo) {
1860
+ return {
1861
+ platform: "github",
1862
+ owner,
1863
+ repo
1864
+ };
1865
+ }
1866
+ }
1867
+ }
1868
+ try {
1869
+ const url = new URL(input);
1870
+ const hostname = url.hostname.toLowerCase();
1871
+ const pathParts = url.pathname.replace(/\/$/, "").split("/").filter(Boolean);
1872
+ if (pathParts.length < 2) {
1873
+ throw new Error("Could not parse repo URL. Use format: owner/repo (GitHub), github:owner/repo, gitlab:group/project, or full URL.");
1874
+ }
1875
+ if (hostname === "github.com") {
1876
+ return {
1877
+ platform: "github",
1878
+ owner: pathParts[0],
1879
+ repo: pathParts[1]
1880
+ };
1881
+ }
1882
+ if (hostname === "gitlab.com") {
1883
+ const repo = pathParts[pathParts.length - 1];
1884
+ const owner = pathParts.slice(0, -1).join("/");
1885
+ return {
1886
+ platform: "gitlab",
1887
+ owner,
1888
+ repo
1889
+ };
1890
+ }
1891
+ throw new Error("Could not parse repo URL. Use format: github:owner/repo, gitlab:group/project, or full URL.");
1892
+ } catch (e) {
1893
+ if (e instanceof Error && e.message.includes("Could not parse")) {
1894
+ throw e;
1895
+ }
1896
+ throw new Error("Could not parse repo URL. Use format: github:owner/repo, gitlab:group/project, or full URL.");
1897
+ }
1898
+ }
1899
+ async function fetchJson(url, headers = {}) {
1900
+ const TIMEOUT_MS = 15e3;
1901
+ return new Promise((resolve, reject) => {
1902
+ const req = https.get(url, {
1903
+ timeout: TIMEOUT_MS,
1904
+ headers: {
1905
+ "User-Agent": "Autohand-CLI/1.0",
1906
+ "Accept": "application/json",
1907
+ ...headers
1908
+ }
1909
+ }, (res) => {
1910
+ if (res.statusCode === 403) {
1911
+ reject(new Error("Rate limited. Hint: Set GITHUB_TOKEN or GITLAB_TOKEN in env or ~/.autohand/config.json to increase limits."));
1912
+ return;
1913
+ }
1914
+ if (res.statusCode === 404) {
1915
+ reject(new Error("Repository not found. Check the URL/shorthand is correct."));
1916
+ return;
1917
+ }
1918
+ if (res.statusCode && res.statusCode >= 400) {
1919
+ reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
1920
+ return;
1921
+ }
1922
+ let data = "";
1923
+ res.on("data", (chunk) => {
1924
+ data += chunk;
1925
+ });
1926
+ res.on("end", () => {
1927
+ try {
1928
+ const json = JSON.parse(data);
1929
+ resolve(json);
1930
+ } catch (parseError) {
1931
+ reject(new Error(`Failed to parse JSON response: ${parseError instanceof Error ? parseError.message : String(parseError)}`));
1932
+ }
1933
+ });
1934
+ res.on("error", reject);
1935
+ });
1936
+ req.on("error", reject);
1937
+ req.on("timeout", () => {
1938
+ req.destroy();
1939
+ reject(new Error("Request timed out"));
1940
+ });
1941
+ });
1942
+ }
1943
+ async function fetchGitHubInfo(parsed) {
1944
+ const url = `https://api.github.com/repos/${parsed.owner}/${parsed.repo}`;
1945
+ const token = process.env.GITHUB_TOKEN;
1946
+ const headers = {};
1947
+ if (token) {
1948
+ headers["Authorization"] = `Bearer ${token}`;
1949
+ }
1950
+ const data = await fetchJson(url, headers);
1951
+ return {
1952
+ platform: "github",
1953
+ name: data.name,
1954
+ fullName: data.full_name,
1955
+ description: data.description || "",
1956
+ stars: data.stargazers_count,
1957
+ language: data.language,
1958
+ defaultBranch: data.default_branch,
1959
+ license: _optionalChain([data, 'access', _41 => _41.license, 'optionalAccess', _42 => _42.spdx_id]) || null
1960
+ };
1961
+ }
1962
+ async function fetchGitLabInfo(parsed) {
1963
+ const projectPath = encodeURIComponent(`${parsed.owner}/${parsed.repo}`);
1964
+ const url = `https://gitlab.com/api/v4/projects/${projectPath}`;
1965
+ const token = process.env.GITLAB_TOKEN;
1966
+ const headers = {};
1967
+ if (token) {
1968
+ headers["PRIVATE-TOKEN"] = token;
1969
+ }
1970
+ const data = await fetchJson(url, headers);
1971
+ return {
1972
+ platform: "gitlab",
1973
+ name: data.name,
1974
+ fullName: data.path_with_namespace,
1975
+ description: data.description || "",
1976
+ stars: data.star_count,
1977
+ language: null,
1978
+ // Would require additional API call to /languages
1979
+ defaultBranch: data.default_branch,
1980
+ license: null
1981
+ // Would require additional API call
1982
+ };
1983
+ }
1984
+ async function fetchRepoInfo(parsed) {
1985
+ switch (parsed.platform) {
1986
+ case "github":
1987
+ return fetchGitHubInfo(parsed);
1988
+ case "gitlab":
1989
+ return fetchGitLabInfo(parsed);
1990
+ default:
1991
+ throw new Error(`Unsupported platform: ${parsed.platform}`);
1992
+ }
1993
+ }
1994
+ async function listGitHubDir(parsed, path8, branch) {
1995
+ const encodedPath = path8 ? encodeURIComponent(path8).replace(/%2F/g, "/") : "";
1996
+ let url = `https://api.github.com/repos/${parsed.owner}/${parsed.repo}/contents/${encodedPath}`;
1997
+ if (branch) {
1998
+ url += `?ref=${encodeURIComponent(branch)}`;
1999
+ }
2000
+ const token = process.env.GITHUB_TOKEN;
2001
+ const headers = {};
2002
+ if (token) {
2003
+ headers["Authorization"] = `Bearer ${token}`;
2004
+ }
2005
+ const data = await fetchJson(url, headers);
2006
+ return data.map((item) => ({
2007
+ name: item.name,
2008
+ type: item.type === "dir" ? "dir" : "file",
2009
+ path: item.path,
2010
+ size: item.type === "file" ? item.size : void 0
2011
+ }));
2012
+ }
2013
+ async function listGitLabDir(parsed, path8, branch) {
2014
+ const projectPath = encodeURIComponent(`${parsed.owner}/${parsed.repo}`);
2015
+ let url = `https://gitlab.com/api/v4/projects/${projectPath}/repository/tree?per_page=100`;
2016
+ if (path8) {
2017
+ url += `&path=${encodeURIComponent(path8)}`;
2018
+ }
2019
+ if (branch) {
2020
+ url += `&ref=${encodeURIComponent(branch)}`;
2021
+ }
2022
+ const token = process.env.GITLAB_TOKEN;
2023
+ const headers = {};
2024
+ if (token) {
2025
+ headers["PRIVATE-TOKEN"] = token;
2026
+ }
2027
+ const data = await fetchJson(url, headers);
2028
+ return data.map((item) => ({
2029
+ name: item.name,
2030
+ type: item.type === "tree" ? "dir" : "file",
2031
+ path: item.path
2032
+ // GitLab tree API does not return file sizes
2033
+ }));
2034
+ }
2035
+ async function listRepoDir(parsed, path8, branch) {
2036
+ switch (parsed.platform) {
2037
+ case "github":
2038
+ return listGitHubDir(parsed, path8, branch);
2039
+ case "gitlab":
2040
+ return listGitLabDir(parsed, path8, branch);
2041
+ default:
2042
+ throw new Error(`Unsupported platform: ${parsed.platform}`);
2043
+ }
2044
+ }
2045
+ async function fetchText(url, headers = {}, maxRedirects = 5) {
2046
+ const TIMEOUT_MS = 15e3;
2047
+ return new Promise((resolve, reject) => {
2048
+ const req = https.get(url, {
2049
+ timeout: TIMEOUT_MS,
2050
+ headers: {
2051
+ "User-Agent": "Autohand-CLI/1.0",
2052
+ ...headers
2053
+ }
2054
+ }, (res) => {
2055
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
2056
+ if (maxRedirects <= 0) {
2057
+ reject(new Error("Too many redirects"));
2058
+ return;
2059
+ }
2060
+ const redirectUrl = new URL(res.headers.location, url).toString();
2061
+ fetchText(redirectUrl, headers, maxRedirects - 1).then(resolve).catch(reject);
2062
+ return;
2063
+ }
2064
+ if (res.statusCode === 403) {
2065
+ reject(new Error("Rate limited. Hint: Set GITHUB_TOKEN or GITLAB_TOKEN in env or ~/.autohand/config.json to increase limits."));
2066
+ return;
2067
+ }
2068
+ if (res.statusCode === 404) {
2069
+ reject(new Error("File not found. Use operation 'list' to see available files."));
2070
+ return;
2071
+ }
2072
+ if (res.statusCode && res.statusCode >= 400) {
2073
+ reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
2074
+ return;
2075
+ }
2076
+ let data = "";
2077
+ res.on("data", (chunk) => {
2078
+ data += chunk;
2079
+ });
2080
+ res.on("end", () => {
2081
+ resolve(data);
2082
+ });
2083
+ res.on("error", reject);
2084
+ });
2085
+ req.on("error", reject);
2086
+ req.on("timeout", () => {
2087
+ req.destroy();
2088
+ reject(new Error("Request timed out"));
2089
+ });
2090
+ });
2091
+ }
2092
+ async function fetchGitHubFile(parsed, path8, branch = "HEAD") {
2093
+ const url = `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/${branch}/${path8}`;
2094
+ const token = process.env.GITHUB_TOKEN;
2095
+ const headers = {};
2096
+ if (token) {
2097
+ headers["Authorization"] = `Bearer ${token}`;
2098
+ }
2099
+ return fetchText(url, headers);
2100
+ }
2101
+ async function fetchGitLabFile(parsed, path8, branch = "HEAD") {
2102
+ const projectPath = encodeURIComponent(`${parsed.owner}/${parsed.repo}`);
2103
+ const encodedFilePath = encodeURIComponent(path8);
2104
+ const url = `https://gitlab.com/api/v4/projects/${projectPath}/repository/files/${encodedFilePath}/raw?ref=${encodeURIComponent(branch)}`;
2105
+ const token = process.env.GITLAB_TOKEN;
2106
+ const headers = {};
2107
+ if (token) {
2108
+ headers["PRIVATE-TOKEN"] = token;
2109
+ }
2110
+ return fetchText(url, headers);
2111
+ }
2112
+ async function fetchRepoFile(parsed, path8, branch) {
2113
+ switch (parsed.platform) {
2114
+ case "github":
2115
+ return fetchGitHubFile(parsed, path8, branch);
2116
+ case "gitlab":
2117
+ return fetchGitLabFile(parsed, path8, branch);
2118
+ default:
2119
+ throw new Error(`Unsupported platform: ${parsed.platform}`);
2120
+ }
2121
+ }
2122
+ function formatBytes(bytes) {
2123
+ if (bytes < 1024) {
2124
+ return `${bytes} B`;
2125
+ }
2126
+ if (bytes < 1024 * 1024) {
2127
+ return `${(bytes / 1024).toFixed(1)} KB`;
2128
+ }
2129
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2130
+ }
2131
+ function formatRepoInfo(info) {
2132
+ const lines = [];
2133
+ lines.push(`**${info.fullName}** (${info.platform})`);
2134
+ lines.push("");
2135
+ if (info.description) {
2136
+ lines.push(info.description);
2137
+ lines.push("");
2138
+ }
2139
+ lines.push(`Stars: ${info.stars}`);
2140
+ lines.push(`Default branch: ${info.defaultBranch}`);
2141
+ if (info.language) {
2142
+ lines.push(`Language: ${info.language}`);
2143
+ }
2144
+ if (info.license) {
2145
+ lines.push(`License: ${info.license}`);
2146
+ }
2147
+ return lines.join("\n");
2148
+ }
2149
+ function formatRepoDir(files, path8) {
2150
+ const lines = [];
2151
+ if (path8 === "") {
2152
+ lines.push("Repository root:");
2153
+ } else {
2154
+ lines.push(`Contents of ${path8}/`);
2155
+ }
2156
+ lines.push("");
2157
+ const dirs = files.filter((f) => f.type === "dir").sort((a, b) => a.name.localeCompare(b.name));
2158
+ const fileItems = files.filter((f) => f.type === "file").sort((a, b) => a.name.localeCompare(b.name));
2159
+ for (const dir of dirs) {
2160
+ lines.push(`\u{1F4C1} ${dir.name}/`);
2161
+ }
2162
+ for (const file of fileItems) {
2163
+ if (file.size !== void 0) {
2164
+ lines.push(`\u{1F4C4} ${file.name} (${formatBytes(file.size)})`);
2165
+ } else {
2166
+ lines.push(`\u{1F4C4} ${file.name}`);
2167
+ }
2168
+ }
2169
+ return lines.join("\n");
2170
+ }
2171
+ async function webRepo(options) {
2172
+ const parsed = parseRepoUrl(options.repo);
2173
+ switch (options.operation) {
2174
+ case "info": {
2175
+ const data = await fetchRepoInfo(parsed);
2176
+ return { type: "info", data };
2177
+ }
2178
+ case "list": {
2179
+ const path8 = _nullishCoalesce(options.path, () => ( ""));
2180
+ const data = await listRepoDir(parsed, path8, options.branch);
2181
+ return { type: "list", data, path: path8 };
2182
+ }
2183
+ case "fetch": {
2184
+ const path8 = _nullishCoalesce(options.path, () => ( "README.md"));
2185
+ const data = await fetchRepoFile(parsed, path8, options.branch);
2186
+ return { type: "fetch", data, path: path8 };
2187
+ }
2188
+ default:
2189
+ throw new Error(`Invalid operation: ${options.operation}. Valid operations are: info, list, fetch`);
2190
+ }
2191
+ }
2192
+
2193
+ // src/core/toolsRegistry.ts
2194
+
2195
+
2196
+ var ToolsRegistry = class {
2197
+ constructor(toolsDir = _chunkSEKD5FH3cjs.AUTOHAND_PATHS.tools) {
2198
+ this.toolsDir = toolsDir;
2199
+ this.metaToolCache = /* @__PURE__ */ new Map();
2200
+ }
2201
+ async initialize() {
2202
+ await _fsextra2.default.ensureDir(this.toolsDir);
2203
+ await this.loadMetaToolDefinitions();
2204
+ }
2205
+ async listTools(builtIns) {
2206
+ const seen = /* @__PURE__ */ new Set();
2207
+ const entries = [];
2208
+ for (const def of builtIns) {
2209
+ if (seen.has(def.name)) {
2210
+ continue;
2211
+ }
2212
+ entries.push({
2213
+ name: def.name,
2214
+ description: def.description,
2215
+ requiresApproval: def.requiresApproval,
2216
+ approvalMessage: def.approvalMessage,
2217
+ source: "builtin"
2218
+ });
2219
+ seen.add(def.name);
2220
+ }
2221
+ for (const [name, tool] of this.metaToolCache) {
2222
+ if (seen.has(name)) {
2223
+ continue;
2224
+ }
2225
+ entries.push({
2226
+ name: tool.name,
2227
+ description: tool.description,
2228
+ source: "meta"
2229
+ });
2230
+ seen.add(name);
2231
+ }
2232
+ return entries;
2233
+ }
2234
+ async saveMetaTool(definition) {
2235
+ const fullDef = {
2236
+ ...definition,
2237
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2238
+ };
2239
+ const filePath = _path2.default.join(this.toolsDir, `${definition.name}.json`);
2240
+ await _fsextra2.default.writeJson(filePath, fullDef, { spaces: 2 });
2241
+ this.metaToolCache.set(definition.name, fullDef);
2242
+ return fullDef;
2243
+ }
2244
+ getMetaTool(name) {
2245
+ return this.metaToolCache.get(name);
2246
+ }
2247
+ hasMetaTool(name) {
2248
+ return this.metaToolCache.has(name);
2249
+ }
2250
+ getAllMetaTools() {
2251
+ return Array.from(this.metaToolCache.values());
2252
+ }
2253
+ toToolDefinitions() {
2254
+ return this.getAllMetaTools().map((tool) => {
2255
+ const params = tool.parameters;
2256
+ return {
2257
+ name: tool.name,
2258
+ description: tool.description,
2259
+ parameters: params.properties ? {
2260
+ type: "object",
2261
+ properties: params.properties,
2262
+ required: _nullishCoalesce(params.required, () => ( []))
2263
+ } : void 0
2264
+ };
2265
+ });
2266
+ }
2267
+ async loadMetaToolDefinitions() {
2268
+ try {
2269
+ const exists = await _fsextra2.default.pathExists(this.toolsDir);
2270
+ if (!exists) {
2271
+ return;
2272
+ }
2273
+ const files = await _fsextra2.default.readdir(this.toolsDir);
2274
+ for (const file of files) {
2275
+ if (!file.endsWith(".json")) {
2276
+ continue;
2277
+ }
2278
+ const fullPath = _path2.default.join(this.toolsDir, file);
2279
+ try {
2280
+ const data = await _fsextra2.default.readJson(fullPath);
2281
+ if (this.isValidMetaTool(data)) {
2282
+ this.metaToolCache.set(data.name, data);
2283
+ }
2284
+ } catch (e7) {
2285
+ }
2286
+ }
2287
+ } catch (e8) {
2288
+ }
2289
+ }
2290
+ isValidMetaTool(candidate) {
2291
+ if (!candidate || typeof candidate !== "object") {
2292
+ return false;
2293
+ }
2294
+ const value = candidate;
2295
+ return typeof value.name === "string" && typeof value.description === "string" && typeof value.handler === "string" && typeof value.parameters === "object";
2296
+ }
2297
+ };
2298
+
2299
+ // src/core/SecurityScanner.ts
2300
+ var SecurityScanner = class {
2301
+ constructor() {
2302
+ /**
2303
+ * Built-in secret detection patterns
2304
+ */
2305
+ this.patterns = [
2306
+ // AWS
2307
+ {
2308
+ name: "AWS Access Key",
2309
+ regex: /AKIA[0-9A-Z]{16}/,
2310
+ severity: "high",
2311
+ description: "AWS Access Key ID"
2312
+ },
2313
+ // GitHub
2314
+ {
2315
+ name: "GitHub Token",
2316
+ regex: /ghp_[a-zA-Z0-9]{36}/,
2317
+ severity: "high",
2318
+ description: "GitHub Personal Access Token"
2319
+ },
2320
+ {
2321
+ name: "GitHub OAuth",
2322
+ regex: /gho_[a-zA-Z0-9]{36}/,
2323
+ severity: "high",
2324
+ description: "GitHub OAuth Token"
2325
+ },
2326
+ {
2327
+ name: "GitHub App Token",
2328
+ regex: /ghu_[a-zA-Z0-9]{36}/,
2329
+ severity: "high",
2330
+ description: "GitHub App User Token"
2331
+ },
2332
+ // OpenAI / Anthropic
2333
+ {
2334
+ name: "OpenAI Key",
2335
+ regex: /sk-proj-[a-zA-Z0-9]{32,}/,
2336
+ severity: "high",
2337
+ description: "OpenAI Project API Key"
2338
+ },
2339
+ {
2340
+ name: "Anthropic Key",
2341
+ regex: /sk-ant-api[a-zA-Z0-9-]{32,}/,
2342
+ severity: "high",
2343
+ description: "Anthropic API Key"
2344
+ },
2345
+ // Google
2346
+ {
2347
+ name: "Google API Key",
2348
+ regex: /AIzaSy[0-9A-Za-z-_]{33}/,
2349
+ severity: "high",
2350
+ description: "Google API Key"
2351
+ },
2352
+ // Stripe
2353
+ {
2354
+ name: "Stripe Live Key",
2355
+ regex: /sk_live_[0-9a-zA-Z]{24,}/,
2356
+ severity: "high",
2357
+ description: "Stripe Live Secret Key"
2358
+ },
2359
+ {
2360
+ name: "Stripe Test Key",
2361
+ regex: /sk_test_[0-9a-zA-Z]{24,}/,
2362
+ severity: "low",
2363
+ description: "Stripe Test Secret Key"
2364
+ },
2365
+ // Private Keys
2366
+ {
2367
+ name: "Private Key",
2368
+ regex: /-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,
2369
+ severity: "high",
2370
+ description: "Private Key File"
2371
+ },
2372
+ // Database URLs with credentials
2373
+ {
2374
+ name: "Database URL",
2375
+ regex: /(postgres|postgresql|mysql|mongodb|redis):\/\/[^:]+:[^@]+@/,
2376
+ severity: "high",
2377
+ description: "Database URL with credentials"
2378
+ },
2379
+ // JWT Tokens
2380
+ {
2381
+ name: "JWT Token",
2382
+ regex: /eyJ[a-zA-Z0-9]{10,}\.eyJ[a-zA-Z0-9]{10,}\.[a-zA-Z0-9_-]{10,}/,
2383
+ severity: "medium",
2384
+ description: "JSON Web Token"
2385
+ },
2386
+ // Generic patterns (lower priority)
2387
+ {
2388
+ name: "Generic API Key",
2389
+ regex: /[aA][pP][iI][-_]?[kK][eE][yY]\s*[:=]\s*['"][a-zA-Z0-9]{16,}['"]/,
2390
+ severity: "medium",
2391
+ description: "Generic API Key Assignment"
2392
+ },
2393
+ {
2394
+ name: "Generic Secret",
2395
+ regex: /[sS][eE][cC][rR][eE][tT]\s*[:=]\s*['"][^'"]{8,}['"]/,
2396
+ severity: "medium",
2397
+ description: "Generic Secret Assignment"
2398
+ },
2399
+ {
2400
+ name: "Password Assignment",
2401
+ regex: /[pP][aA][sS][sS][wW][oO][rR][dD]\s*[:=]\s*['"][^'"]{4,}['"]/,
2402
+ severity: "medium",
2403
+ description: "Password Assignment"
2404
+ }
2405
+ ];
2406
+ /**
2407
+ * Placeholder patterns to ignore (false positives)
2408
+ * These must be exact matches or specific patterns, not substrings
2409
+ */
2410
+ this.placeholderPatterns = [
2411
+ /your[-_]?api[-_]?key/i,
2412
+ /your[-_]?secret/i,
2413
+ /\*\*\*/,
2414
+ /\.\.\.$/,
2415
+ /-example/i,
2416
+ /placeholder/i,
2417
+ /sk-xxx$/i,
2418
+ /sk-your/i,
2419
+ /<your[-_]?key[-_]?here>/i,
2420
+ /\$\{[A-Z_]+\}/,
2421
+ // Environment variable placeholders
2422
+ /process\.env\./
2423
+ ];
2424
+ }
2425
+ /**
2426
+ * Scan git diff for secrets
2427
+ * @param diff - Git diff output
2428
+ * @returns Security scan result
2429
+ */
2430
+ scanDiff(diff) {
2431
+ const findings = [];
2432
+ const lines = diff.split("\n");
2433
+ let currentFile;
2434
+ let lineNumber = 0;
2435
+ for (const line of lines) {
2436
+ if (line.startsWith("+++ b/")) {
2437
+ currentFile = line.slice(6);
2438
+ continue;
2439
+ }
2440
+ if (line.startsWith("diff --git")) {
2441
+ const match = line.match(/diff --git a\/.+ b\/(.+)/);
2442
+ if (match) {
2443
+ currentFile = match[1];
2444
+ }
2445
+ continue;
2446
+ }
2447
+ if (line.startsWith("@@")) {
2448
+ const match = line.match(/@@ -\d+(?:,\d+)? \+(\d+)/);
2449
+ if (match) {
2450
+ lineNumber = parseInt(match[1], 10) - 1;
2451
+ }
2452
+ continue;
2453
+ }
2454
+ if (line.startsWith("-") && !line.startsWith("---")) {
2455
+ continue;
2456
+ }
2457
+ if (line.startsWith(" ")) {
2458
+ lineNumber++;
2459
+ continue;
2460
+ }
2461
+ if (!line.startsWith("+") || line.startsWith("+++")) {
2462
+ continue;
2463
+ }
2464
+ lineNumber++;
2465
+ const content = line.slice(1);
2466
+ if (this.isLikelyFalsePositive(content)) {
2467
+ continue;
2468
+ }
2469
+ this.scanLine(content, currentFile, lineNumber, findings);
2470
+ }
2471
+ return this.buildResult(findings);
2472
+ }
2473
+ /**
2474
+ * Scan file content directly
2475
+ * @param content - File content
2476
+ * @param filename - Optional filename for reporting
2477
+ * @returns Security scan result
2478
+ */
2479
+ scanFile(content, filename) {
2480
+ const findings = [];
2481
+ const lines = content.split("\n");
2482
+ for (let i = 0; i < lines.length; i++) {
2483
+ const line = lines[i];
2484
+ if (this.isLikelyFalsePositive(line)) {
2485
+ continue;
2486
+ }
2487
+ this.scanLine(line, filename, i + 1, findings);
2488
+ }
2489
+ return this.buildResult(findings);
2490
+ }
2491
+ /**
2492
+ * Scan a single line for secrets
2493
+ */
2494
+ scanLine(line, file, lineNumber, findings) {
2495
+ for (const pattern of this.patterns) {
2496
+ const match = line.match(pattern.regex);
2497
+ if (match) {
2498
+ findings.push({
2499
+ type: pattern.name,
2500
+ severity: pattern.severity,
2501
+ line,
2502
+ lineNumber,
2503
+ file,
2504
+ match: match[0]
2505
+ });
2506
+ }
2507
+ }
2508
+ }
2509
+ /**
2510
+ * Build scan result from findings
2511
+ */
2512
+ buildResult(findings) {
2513
+ const blockedCount = findings.filter((f) => f.severity === "high").length;
2514
+ const warningCount = findings.filter((f) => f.severity !== "high").length;
2515
+ return {
2516
+ clean: blockedCount === 0,
2517
+ findings,
2518
+ blockedCount,
2519
+ warningCount
2520
+ };
2521
+ }
2522
+ /**
2523
+ * Check if commit should be blocked based on scan result
2524
+ * @param result - Security scan result
2525
+ * @returns true if commit should be blocked
2526
+ */
2527
+ shouldBlockCommit(result) {
2528
+ return result.blockedCount > 0;
2529
+ }
2530
+ /**
2531
+ * Check if a line is likely a false positive
2532
+ */
2533
+ isLikelyFalsePositive(line) {
2534
+ if (/^\s*(\/\/|#|\/\*|\*|<!--)/.test(line)) {
2535
+ return true;
2536
+ }
2537
+ for (const pattern of this.placeholderPatterns) {
2538
+ if (pattern.test(line)) {
2539
+ return true;
2540
+ }
2541
+ }
2542
+ return false;
2543
+ }
2544
+ /**
2545
+ * Add a custom secret pattern
2546
+ * @param pattern - Pattern to add
2547
+ */
2548
+ addPattern(pattern) {
2549
+ this.patterns.push(pattern);
2550
+ }
2551
+ /**
2552
+ * Get all configured patterns (returns a copy)
2553
+ * @returns Array of secret patterns
2554
+ */
2555
+ getPatterns() {
2556
+ return [...this.patterns];
2557
+ }
2558
+ /**
2559
+ * Format scan result for display
2560
+ * @param result - Security scan result
2561
+ * @returns Formatted string for terminal display
2562
+ */
2563
+ formatDisplay(result) {
2564
+ const lines = ["[SECURITY] Scanning staged changes..."];
2565
+ if (result.findings.length === 0) {
2566
+ lines.push("");
2567
+ lines.push("[OK] No secrets detected");
2568
+ return lines.join("\n");
2569
+ }
2570
+ lines.push("");
2571
+ for (const finding of result.findings) {
2572
+ const severity = finding.severity === "high" ? "[HIGH]" : finding.severity === "medium" ? "[WARN]" : "[LOW]";
2573
+ lines.push(` ${severity} ${finding.type} detected`);
2574
+ if (finding.file && finding.lineNumber) {
2575
+ lines.push(` File: ${finding.file}:${finding.lineNumber}`);
2576
+ } else if (finding.file) {
2577
+ lines.push(` File: ${finding.file}`);
2578
+ }
2579
+ const redactedLine = this.redactSecret(finding.line, finding.match);
2580
+ lines.push(` Line: ${redactedLine}`);
2581
+ lines.push("");
2582
+ }
2583
+ if (result.blockedCount > 0) {
2584
+ lines.push(`[BLOCKED] ${result.blockedCount} high-severity secrets found`);
2585
+ lines.push(" Remove secrets before committing.");
2586
+ lines.push(" Consider using environment variables instead.");
2587
+ } else if (result.warningCount > 0) {
2588
+ lines.push(`[WARN] ${result.warningCount} potential secrets found`);
2589
+ lines.push(" Review before committing.");
2590
+ }
2591
+ return lines.join("\n");
2592
+ }
2593
+ /**
2594
+ * Redact a secret in a line for display
2595
+ */
2596
+ redactSecret(line, secret) {
2597
+ if (secret.length <= 8) {
2598
+ return line.replace(secret, "*".repeat(secret.length));
2599
+ }
2600
+ const redacted = secret.slice(0, 4) + "*".repeat(secret.length - 8) + secret.slice(-4);
2601
+ return line.replace(secret, redacted);
2602
+ }
2603
+ };
2604
+
2605
+ // src/core/actionExecutor.ts
2606
+
2607
+
2608
+ // src/modes/planMode/PlanFileStorage.ts
2609
+
2610
+
2611
+ var PlanFileStorage = class {
2612
+ constructor() {
2613
+ this.plansDir = _chunkSEKD5FH3cjs.AUTOHAND_PATHS.plans;
2614
+ }
2615
+ /**
2616
+ * Get the plans directory path
2617
+ */
2618
+ getPlansDirectory() {
2619
+ return this.plansDir;
2620
+ }
2621
+ /**
2622
+ * Save a plan to a markdown file
2623
+ * Returns the file path
2624
+ */
2625
+ async savePlan(plan) {
2626
+ await _fsextra2.default.ensureDir(this.plansDir);
2627
+ const filePath = _path2.default.join(this.plansDir, `${plan.id}.md`);
2628
+ const content = this.formatPlanAsMarkdown(plan);
2629
+ await _fsextra2.default.writeFile(filePath, content, "utf8");
2630
+ return filePath;
2631
+ }
2632
+ /**
2633
+ * Load a plan from file by ID
2634
+ * Returns null if not found
2635
+ */
2636
+ async loadPlan(planId) {
2637
+ const filePath = _path2.default.join(this.plansDir, `${planId}.md`);
2638
+ if (!await _fsextra2.default.pathExists(filePath)) {
2639
+ return null;
2640
+ }
2641
+ const content = await _fsextra2.default.readFile(filePath, "utf8");
2642
+ return this.parsePlanFromMarkdown(content, planId);
2643
+ }
2644
+ /**
2645
+ * List all plan IDs in the plans directory
2646
+ */
2647
+ async listPlans() {
2648
+ if (!await _fsextra2.default.pathExists(this.plansDir)) {
2649
+ return [];
2650
+ }
2651
+ const files = await _fsextra2.default.readdir(this.plansDir);
2652
+ return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, ""));
2653
+ }
2654
+ /**
2655
+ * Delete a plan file by ID
2656
+ * Returns true if deleted, false if not found
2657
+ */
2658
+ async deletePlan(planId) {
2659
+ const filePath = _path2.default.join(this.plansDir, `${planId}.md`);
2660
+ if (!await _fsextra2.default.pathExists(filePath)) {
2661
+ return false;
2662
+ }
2663
+ await _fsextra2.default.remove(filePath);
2664
+ return true;
2665
+ }
2666
+ /**
2667
+ * Format a plan as markdown content
2668
+ */
2669
+ formatPlanAsMarkdown(plan) {
2670
+ const createdDate = new Date(plan.createdAt).toISOString();
2671
+ const lines = [
2672
+ `# Plan: ${plan.id}`,
2673
+ "",
2674
+ `Created: ${createdDate}`,
2675
+ "",
2676
+ "## Steps",
2677
+ ""
2678
+ ];
2679
+ for (const step of plan.steps) {
2680
+ const checkbox = this.getCheckboxForStatus(step.status);
2681
+ lines.push(`- ${checkbox} ${step.number}. ${step.description}`);
2682
+ }
2683
+ lines.push("");
2684
+ return lines.join("\n");
2685
+ }
2686
+ /**
2687
+ * Get markdown checkbox for step status
2688
+ */
2689
+ getCheckboxForStatus(status) {
2690
+ switch (status) {
2691
+ case "completed":
2692
+ return "[x]";
2693
+ case "in_progress":
2694
+ return "[>]";
2695
+ case "skipped":
2696
+ return "[-]";
2697
+ default:
2698
+ return "[ ]";
2699
+ }
2700
+ }
2701
+ /**
2702
+ * Parse markdown content back to a Plan object
2703
+ */
2704
+ parsePlanFromMarkdown(content, planId) {
2705
+ const steps = [];
2706
+ const stepPattern = /^-\s+\[([ x>\-])\]\s+(\d+)\.\s+(.+)$/gm;
2707
+ let match;
2708
+ while ((match = stepPattern.exec(content)) !== null) {
2709
+ const checkboxChar = match[1];
2710
+ const number = parseInt(match[2], 10);
2711
+ const description = match[3].trim();
2712
+ steps.push({
2713
+ number,
2714
+ description,
2715
+ status: this.parseStatusFromCheckbox(checkboxChar)
2716
+ });
2717
+ }
2718
+ const dateMatch = content.match(/Created:\s*(.+)/);
2719
+ const createdAt = dateMatch ? new Date(dateMatch[1]).getTime() : Date.now();
2720
+ return {
2721
+ id: planId,
2722
+ steps,
2723
+ rawText: steps.map((s) => `${s.number}. ${s.description}`).join("\n"),
2724
+ createdAt
2725
+ };
2726
+ }
2727
+ /**
2728
+ * Parse step status from checkbox character
2729
+ */
2730
+ parseStatusFromCheckbox(char) {
2731
+ switch (char) {
2732
+ case "x":
2733
+ return "completed";
2734
+ case ">":
2735
+ return "in_progress";
2736
+ case "-":
2737
+ return "skipped";
2738
+ default:
2739
+ return "pending";
2740
+ }
2741
+ }
2742
+ };
2743
+
2744
+ // src/core/actionExecutor.ts
2745
+
2746
+ var ActionExecutor = class _ActionExecutor {
2747
+ constructor(deps) {
2748
+ this.deps = deps;
2749
+ this.searchCache = /* @__PURE__ */ new Map();
2750
+ this.runtime = deps.runtime;
2751
+ this.files = deps.files;
2752
+ this.resolveWorkspacePath = deps.resolveWorkspacePath;
2753
+ this.confirmDangerousAction = deps.confirmDangerousAction;
2754
+ this.projectManager = deps.projectManager;
2755
+ this.sessionId = deps.sessionId;
2756
+ this.logExploration = deps.onExploration;
2757
+ this.toolsRegistry = _nullishCoalesce(deps.toolsRegistry, () => ( new ToolsRegistry()));
2758
+ this.getRegisteredTools = _nullishCoalesce(deps.getRegisteredTools, () => ( (() => [])));
2759
+ this.permissionManager = _nullishCoalesce(deps.permissionManager, () => ( new (0, _chunkJ6QET7EFcjs.PermissionManager)(deps.runtime.config.permissions)));
2760
+ this.memoryManager = deps.memoryManager;
2761
+ this.onToolOutput = deps.onToolOutput;
2762
+ this.onFileModified = deps.onFileModified;
2763
+ this.onAskFollowup = deps.onAskFollowup;
2764
+ this.onPlanCreated = deps.onPlanCreated;
2765
+ this.onPermissionRequest = deps.onPermissionRequest;
2766
+ this.securityScanner = new SecurityScanner();
2767
+ }
2768
+ /**
2769
+ * Check permission hooks before prompting user.
2770
+ * Returns true if allowed, false if denied/blocked, undefined if should ask user.
2771
+ */
2772
+ async checkPermissionHook(context) {
2773
+ if (!this.onPermissionRequest) {
2774
+ return {};
2775
+ }
2776
+ const hookResponse = await this.onPermissionRequest(context);
2777
+ if (!_optionalChain([hookResponse, 'optionalAccess', _43 => _43.decision])) {
2778
+ return {};
2779
+ }
2780
+ switch (hookResponse.decision) {
2781
+ case "allow":
2782
+ return { allowed: true, updatedInput: hookResponse.updatedInput };
2783
+ case "deny":
2784
+ return { allowed: false, reason: _nullishCoalesce(hookResponse.reason, () => ( "Denied by hook")) };
2785
+ case "block":
2786
+ return { blocked: true, reason: _nullishCoalesce(hookResponse.reason, () => ( "Blocked by hook")) };
2787
+ case "ask":
2788
+ default:
2789
+ return {};
2790
+ }
2791
+ }
2792
+ async execute(action, context) {
2793
+ if (this.runtime.options.dryRun && action.type !== "search" && action.type !== "plan") {
2794
+ return "Dry-run mode: skipped mutation";
2795
+ }
2796
+ switch (action.type) {
2797
+ case "plan": {
2798
+ const notes = _nullishCoalesce(action.notes, () => ( ""));
2799
+ if (!notes) {
2800
+ return "No plan notes provided";
2801
+ }
2802
+ const storage = new PlanFileStorage();
2803
+ const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
2804
+ const now = Date.now();
2805
+ const existingPlanIds = await storage.listPlans();
2806
+ let cleanedCount = 0;
2807
+ for (const planId of existingPlanIds) {
2808
+ const existingPlan = await storage.loadPlan(planId);
2809
+ if (existingPlan && now - existingPlan.createdAt > THIRTY_DAYS_MS) {
2810
+ await storage.deletePlan(planId);
2811
+ cleanedCount++;
2812
+ }
2813
+ }
2814
+ if (cleanedCount > 0) {
2815
+ console.log(_chalk2.default.gray(`
2816
+ \u{1F9F9} Cleaned up ${cleanedCount} plan(s) older than 30 days`));
2817
+ }
2818
+ const planModeManager = _chunkULQ6MDSJcjs.getPlanModeManager.call(void 0, );
2819
+ if (planModeManager.isEnabled() && this.onAskFollowup) {
2820
+ const refreshedPlanIds = await storage.listPlans();
2821
+ const incompletePlans = [];
2822
+ for (const planId of refreshedPlanIds) {
2823
+ const existingPlan = await storage.loadPlan(planId);
2824
+ if (existingPlan) {
2825
+ const pendingCount = existingPlan.steps.filter((s) => s.status === "pending").length;
2826
+ const inProgressCount = existingPlan.steps.filter((s) => s.status === "in_progress").length;
2827
+ if (pendingCount > 0 || inProgressCount > 0) {
2828
+ incompletePlans.push({ plan: existingPlan, pendingCount, inProgressCount });
2829
+ }
2830
+ }
2831
+ }
2832
+ if (incompletePlans.length > 0) {
2833
+ console.log(_chalk2.default.yellow(`
2834
+ \u{1F4CB} Found ${incompletePlans.length} incomplete plan(s):`));
2835
+ for (const { plan: plan2, pendingCount, inProgressCount } of incompletePlans) {
2836
+ const age = Math.floor((now - plan2.createdAt) / (1e3 * 60 * 60 * 24));
2837
+ const ageStr = age === 0 ? "today" : age === 1 ? "1 day ago" : `${age} days ago`;
2838
+ const statusStr = inProgressCount > 0 ? `${inProgressCount} in progress, ${pendingCount} pending` : `${pendingCount} pending`;
2839
+ console.log(_chalk2.default.gray(` \u2022 ${plan2.id} (${ageStr}) - ${plan2.steps.length} steps, ${statusStr}`));
2840
+ }
2841
+ console.log();
2842
+ const suggestedAnswers = [
2843
+ "Create new plan",
2844
+ ...incompletePlans.slice(0, 3).map(({ plan: plan2 }) => `Resume: ${plan2.id}`)
2845
+ ];
2846
+ const answer = await this.onAskFollowup(
2847
+ "Would you like to resume an incomplete plan or create a new one?",
2848
+ suggestedAnswers
2849
+ );
2850
+ const answerText = answer.replace(/<\/?answer>/g, "").trim();
2851
+ if (answerText.toLowerCase().includes("resume:") || answerText.toLowerCase().startsWith("resume")) {
2852
+ const resumeMatch = answerText.match(/resume[:\s]+(\S+)/i);
2853
+ if (resumeMatch) {
2854
+ const planIdToResume = resumeMatch[1];
2855
+ const planToResume = incompletePlans.find((p) => p.plan.id === planIdToResume);
2856
+ if (planToResume) {
2857
+ const filePath2 = `${storage.getPlansDirectory()}/${planToResume.plan.id}.md`;
2858
+ console.log(_chalk2.default.cyan(`
2859
+ \u{1F4CB} Resuming plan: ${planToResume.plan.id}`));
2860
+ console.log(_chalk2.default.gray(` File: ${filePath2}
2861
+ `));
2862
+ if (this.onPlanCreated) {
2863
+ return this.onPlanCreated(planToResume.plan, filePath2);
2864
+ }
2865
+ return `Resumed plan ${planToResume.plan.id}
2866
+
2867
+ Steps:
2868
+ ${planToResume.plan.steps.map((s) => {
2869
+ const status = s.status === "completed" ? "\u2713" : s.status === "in_progress" ? ">" : "\u25CB";
2870
+ return `${status} ${s.number}. ${s.description}`;
2871
+ }).join("\n")}`;
2872
+ }
2873
+ }
2874
+ }
2875
+ console.log(_chalk2.default.cyan("\n\u{1F4CB} Creating new plan..."));
2876
+ }
2877
+ }
2878
+ const lines = notes.split("\n");
2879
+ const steps = [];
2880
+ let stepNumber = 0;
2881
+ for (const line of lines) {
2882
+ const trimmed = line.trim();
2883
+ const numberedMatch = trimmed.match(/^(\d+)[.)]\s*(.+)$/);
2884
+ const bulletMatch = trimmed.match(/^[-*]\s+(.+)$/);
2885
+ if (numberedMatch) {
2886
+ stepNumber = parseInt(numberedMatch[1], 10);
2887
+ steps.push({
2888
+ number: stepNumber,
2889
+ description: numberedMatch[2].trim(),
2890
+ status: "pending"
2891
+ });
2892
+ } else if (bulletMatch) {
2893
+ stepNumber++;
2894
+ steps.push({
2895
+ number: stepNumber,
2896
+ description: bulletMatch[1].trim(),
2897
+ status: "pending"
2898
+ });
2899
+ }
2900
+ }
2901
+ if (steps.length === 0) {
2902
+ steps.push({
2903
+ number: 1,
2904
+ description: notes.substring(0, 200),
2905
+ status: "pending"
2906
+ });
2907
+ }
2908
+ const plan = {
2909
+ id: `plan-${_crypto.randomUUID.call(void 0, ).split("-")[0]}`,
2910
+ steps,
2911
+ rawText: notes,
2912
+ createdAt: Date.now()
2913
+ };
2914
+ const filePath = await storage.savePlan(plan);
2915
+ console.log(_chalk2.default.cyan(`
2916
+ \u{1F4CB} Plan created with ${steps.length} step(s)`));
2917
+ console.log(_chalk2.default.gray(` Saved to: ${filePath}
2918
+ `));
2919
+ if (this.onPlanCreated) {
2920
+ return this.onPlanCreated(plan, filePath);
2921
+ }
2922
+ return `Plan saved to ${filePath}
2923
+
2924
+ Steps:
2925
+ ${steps.map((s) => `${s.number}. ${s.description}`).join("\n")}`;
2926
+ }
2927
+ case "read_file": {
2928
+ if (!action.path) {
2929
+ throw new Error('read_file requires a "path" argument.');
2930
+ }
2931
+ const offset = typeof action.offset === "number" ? action.offset : 0;
2932
+ const limit = typeof action.limit === "number" ? action.limit : 0;
2933
+ const fullContents = await this.files.readFile(action.path);
2934
+ this.recordExploration("read", action.path);
2935
+ const allLines = fullContents.split("\n");
2936
+ const totalLines = allLines.length;
2937
+ const fileSize = Buffer.byteLength(fullContents, "utf8");
2938
+ const fileSizeKB = (fileSize / 1024).toFixed(2);
2939
+ const MAX_LINES = 2e3;
2940
+ const MAX_SIZE_BYTES = 80 * 1024;
2941
+ const CHUNK_SIZE = 500;
2942
+ if (offset > 0 || limit > 0) {
2943
+ const effectiveLimit = limit > 0 ? limit : CHUNK_SIZE;
2944
+ const startLine = Math.min(offset, totalLines);
2945
+ const endLine = Math.min(startLine + effectiveLimit, totalLines);
2946
+ const chunk = allLines.slice(startLine, endLine).join("\n");
2947
+ console.log(_chalk2.default.cyan(`
2948
+ \u{1F4C4} ${action.path}`));
2949
+ console.log(_chalk2.default.gray(` Lines ${startLine + 1}-${endLine} of ${totalLines} (${fileSizeKB} KB total)`));
2950
+ if (endLine < totalLines) {
2951
+ console.log(_chalk2.default.yellow(` ${totalLines - endLine} more lines remaining`));
2952
+ }
2953
+ return chunk;
2954
+ }
2955
+ if (totalLines > MAX_LINES || fileSize > MAX_SIZE_BYTES) {
2956
+ console.log(_chalk2.default.cyan(`
2957
+ \u{1F4C4} ${action.path}`));
2958
+ console.log(_chalk2.default.yellow(` \u26A0 Large file: ${totalLines} lines \u2022 ${fileSizeKB} KB`));
2959
+ console.log(_chalk2.default.gray(` Smart chunking: outline + first ${CHUNK_SIZE} lines`));
2960
+ const outline = this.extractFileOutline(allLines, action.path);
2961
+ const firstChunk = allLines.slice(0, CHUNK_SIZE).join("\n");
2962
+ const response = [
2963
+ `=== FILE OUTLINE (${action.path}) ===`,
2964
+ `Total: ${totalLines} lines \u2022 ${fileSizeKB} KB`,
2965
+ "",
2966
+ outline,
2967
+ "",
2968
+ `=== CONTENT (lines 1-${CHUNK_SIZE}) ===`,
2969
+ firstChunk,
2970
+ "",
2971
+ `=== NAVIGATION ===`,
2972
+ `Showing lines 1-${CHUNK_SIZE} of ${totalLines}`,
2973
+ `To read more sections, use: read_file with offset=<line> limit=${CHUNK_SIZE}`,
2974
+ `Example: read_file path="${action.path}" offset=${CHUNK_SIZE} limit=${CHUNK_SIZE}`
2975
+ ].join("\n");
2976
+ return response;
2977
+ }
2978
+ console.log(_chalk2.default.cyan(`
2979
+ \u{1F4C4} ${action.path}`));
2980
+ console.log(_chalk2.default.gray(` ${totalLines} lines \u2022 ${fileSizeKB} KB`));
2981
+ return fullContents;
2982
+ }
2983
+ case "write_file": {
2984
+ if (!action.path) {
2985
+ const receivedKeys = Object.keys(action).filter((k) => k !== "type").join(", ") || "none";
2986
+ throw new Error(`write_file requires a "path" argument. Received arguments: [${receivedKeys}]`);
2987
+ }
2988
+ const filePath = this.resolveWorkspacePath(action.path);
2989
+ const fs7 = await Promise.resolve().then(() => _interopRequireWildcard(require("fs-extra")));
2990
+ const exists = this.files.root && await fs7.pathExists(filePath);
2991
+ const oldContent = exists ? await this.files.readFile(action.path) : "";
2992
+ const newContent = _nullishCoalesce(this.pickText(action.contents, action.content), () => ( ""));
2993
+ if (!exists) {
2994
+ const permContext = {
2995
+ tool: "write_file",
2996
+ path: action.path
2997
+ };
2998
+ const decision = this.permissionManager.checkPermission(permContext);
2999
+ if (decision.reason === "blacklisted" || decision.reason === "mode_restricted") {
3000
+ return `Blocked: Cannot create ${action.path} (${decision.reason})`;
3001
+ }
3002
+ if (decision.allowed) {
3003
+ console.log(_chalk2.default.cyan(`
3004
+ \u2728 Creating: ${action.path}`));
3005
+ } else {
3006
+ const hookResult = await this.checkPermissionHook({
3007
+ tool: "write_file",
3008
+ path: action.path,
3009
+ args: { content: newContent }
3010
+ });
3011
+ if (hookResult.blocked) {
3012
+ return `Blocked: ${hookResult.reason}`;
3013
+ }
3014
+ if (hookResult.allowed !== void 0) {
3015
+ if (hookResult.allowed) {
3016
+ console.log(_chalk2.default.cyan(`
3017
+ \u2728 Creating: ${action.path}`));
3018
+ await this.permissionManager.recordDecision(permContext, true);
3019
+ } else {
3020
+ await this.permissionManager.recordDecision(permContext, false);
3021
+ return `Denied: ${hookResult.reason}`;
3022
+ }
3023
+ } else {
3024
+ console.log(_chalk2.default.cyan(`
3025
+ \u2728 Creating new file: ${action.path}`));
3026
+ const preview = newContent.length > 500 ? newContent.substring(0, 500) + "\n... (truncated)" : newContent;
3027
+ console.log(_chalk2.default.gray(preview));
3028
+ const confirmed = await this.confirmDangerousAction(
3029
+ `Create new file ${action.path}?`,
3030
+ { tool: "write_file", path: action.path }
3031
+ );
3032
+ await this.permissionManager.recordDecision(permContext, confirmed);
3033
+ if (!confirmed) {
3034
+ return `Skipped creating ${action.path}`;
3035
+ }
3036
+ }
3037
+ }
3038
+ } else if (oldContent === newContent) {
3039
+ return `No changes needed for ${action.path} (content identical)`;
3040
+ } else {
3041
+ console.log(_chalk2.default.cyan(`
3042
+ \u{1F4DD} ${action.path}:`));
3043
+ this.showDiff(oldContent, newContent, action.path);
3044
+ }
3045
+ await this.files.writeFile(action.path, newContent);
3046
+ _optionalChain([this, 'access', _44 => _44.onFileModified, 'optionalCall', _45 => _45(action.path)]);
3047
+ return exists ? `Updated ${action.path}` : `Created ${action.path}`;
3048
+ }
3049
+ case "append_file": {
3050
+ if (!action.path) {
3051
+ throw new Error('append_file requires a "path" argument.');
3052
+ }
3053
+ const addition = _nullishCoalesce(this.pickText(action.contents, action.content), () => ( ""));
3054
+ const oldContent = await this.files.readFile(action.path).catch(() => "");
3055
+ const newContent = oldContent + addition;
3056
+ console.log(_chalk2.default.cyan(`
3057
+ \u{1F4DD} ${action.path}:`));
3058
+ this.showDiff(oldContent, newContent, action.path);
3059
+ await this.files.appendFile(action.path, addition);
3060
+ _optionalChain([this, 'access', _46 => _46.onFileModified, 'optionalCall', _47 => _47(action.path)]);
3061
+ return `Appended to ${action.path}`;
3062
+ }
3063
+ case "apply_patch": {
3064
+ if (!action.path) {
3065
+ throw new Error('apply_patch requires a "path" argument.');
3066
+ }
3067
+ const oldContent = await this.files.readFile(action.path).catch(() => "");
3068
+ const patch = this.pickText(action.patch, action.diff);
3069
+ if (!patch) {
3070
+ throw new Error("apply_patch requires patch or diff content.");
3071
+ }
3072
+ console.log(_chalk2.default.cyan(`
3073
+ \u{1F527} ${action.path}:`));
3074
+ console.log(_chalk2.default.gray("Applying patch..."));
3075
+ await this.files.applyPatch(action.path, patch);
3076
+ const newContent = await this.files.readFile(action.path);
3077
+ this.showDiff(oldContent, newContent, action.path);
3078
+ _optionalChain([this, 'access', _48 => _48.onFileModified, 'optionalCall', _49 => _49(action.path)]);
3079
+ return `Patched ${action.path}`;
3080
+ }
3081
+ case "tools_registry": {
3082
+ const tools = await this.toolsRegistry.listTools(this.getRegisteredTools());
3083
+ return JSON.stringify(tools, null, 2);
3084
+ }
3085
+ case "search": {
3086
+ const cacheKey = `search:${action.query}:${action.path || ""}`;
3087
+ if (this.searchCache.has(cacheKey)) {
3088
+ return `[Cached] ${this.searchCache.get(cacheKey)}`;
3089
+ }
3090
+ const hits = this.files.search(action.query, action.path);
3091
+ this.recordExploration("search", action.query);
3092
+ const result = hits.slice(0, 10).map((hit) => `${hit.file}:${hit.line}: ${hit.text}`).join("\n");
3093
+ this.searchCache.set(cacheKey, result);
3094
+ return result;
3095
+ }
3096
+ case "search_with_context": {
3097
+ const cacheKey = `search_ctx:${action.query}:${action.path || ""}:${action.limit || ""}:${action.context || ""}`;
3098
+ if (this.searchCache.has(cacheKey)) {
3099
+ return `[Cached] ${this.searchCache.get(cacheKey)}`;
3100
+ }
3101
+ this.recordExploration("search", action.query);
3102
+ const result = this.files.searchWithContext(action.query, {
3103
+ limit: action.limit,
3104
+ context: action.context,
3105
+ relativePath: action.path
3106
+ });
3107
+ this.searchCache.set(cacheKey, result);
3108
+ return result;
3109
+ }
3110
+ case "semantic_search": {
3111
+ const cacheKey = `semantic:${action.query}:${action.path || ""}:${action.limit || ""}:${action.window || ""}`;
3112
+ if (this.searchCache.has(cacheKey)) {
3113
+ return `[Cached] ${this.searchCache.get(cacheKey)}`;
3114
+ }
3115
+ const results = this.files.semanticSearch(action.query, {
3116
+ limit: action.limit,
3117
+ window: action.window,
3118
+ relativePath: action.path
3119
+ });
3120
+ if (!results.length) {
3121
+ this.searchCache.set(cacheKey, "No matches found.");
3122
+ return "No matches found.";
3123
+ }
3124
+ const result = results.map((hit) => `${_chalk2.default.cyan(hit.file)}
3125
+ ${hit.snippet}`).join("\n\n");
3126
+ this.searchCache.set(cacheKey, result);
3127
+ return result;
3128
+ }
3129
+ case "create_directory": {
3130
+ await this.files.createDirectory(action.path);
3131
+ return `Created directory ${action.path}`;
3132
+ }
3133
+ case "delete_path": {
3134
+ if (!action.path) {
3135
+ throw new Error('delete_path requires a "path" argument.');
3136
+ }
3137
+ const confirmed = await this.confirmDangerousAction(
3138
+ `Delete ${action.path}?`,
3139
+ { tool: "delete_path", path: action.path }
3140
+ );
3141
+ if (!confirmed) {
3142
+ return `Skipped deleting ${action.path}`;
3143
+ }
3144
+ await this.files.deletePath(action.path);
3145
+ return `Deleted ${action.path}`;
3146
+ }
3147
+ case "rename_path": {
3148
+ if (!action.from || !action.to) {
3149
+ throw new Error('rename_path requires "from" and "to" arguments.');
3150
+ }
3151
+ await this.files.renamePath(action.from, action.to);
3152
+ return `Renamed ${action.from} -> ${action.to}`;
3153
+ }
3154
+ case "copy_path": {
3155
+ if (!action.from || !action.to) {
3156
+ throw new Error('copy_path requires "from" and "to" arguments.');
3157
+ }
3158
+ await this.files.copyPath(action.from, action.to);
3159
+ return `Copied ${action.from} -> ${action.to}`;
3160
+ }
3161
+ case "search_replace": {
3162
+ const content = await this.files.readFile(action.path);
3163
+ const result = this.applySearchReplaceBlocks(content, action.blocks);
3164
+ if (content !== result) {
3165
+ console.log(_chalk2.default.cyan(`
3166
+ \u{1F504} ${action.path}:`));
3167
+ this.showDiff(content, result, action.path);
3168
+ await this.files.writeFile(action.path, result);
3169
+ _optionalChain([this, 'access', _50 => _50.onFileModified, 'optionalCall', _51 => _51(action.path)]);
3170
+ }
3171
+ return `Updated ${action.path}`;
3172
+ }
3173
+ case "format_file": {
3174
+ if (!action.path) {
3175
+ throw new Error('format_file requires a "path" argument.');
3176
+ }
3177
+ await this.files.formatFile(action.path, (contents, file) => _chunk4JNNTOGFcjs.applyFormatter.call(void 0, action.formatter, contents, file));
3178
+ return `Formatted ${action.path} (${action.formatter})`;
3179
+ }
3180
+ case "run_command": {
3181
+ if (!action.command || typeof action.command !== "string") {
3182
+ return 'Error: run_command requires a "command" argument (string)';
3183
+ }
3184
+ const shouldStreamOutput = Boolean(
3185
+ this.onToolOutput && _optionalChain([context, 'optionalAccess', _52 => _52.toolCallId]) && !action.background && process.env.AUTOHAND_STREAM_TOOL_OUTPUT === "1"
3186
+ );
3187
+ const emitOutput = (stream, data) => {
3188
+ if (!shouldStreamOutput) {
3189
+ return;
3190
+ }
3191
+ _optionalChain([this, 'access', _53 => _53.onToolOutput, 'optionalCall', _54 => _54({
3192
+ tool: action.type,
3193
+ toolCallId: _optionalChain([context, 'optionalAccess', _55 => _55.toolCallId]),
3194
+ stream,
3195
+ data
3196
+ })]);
3197
+ };
3198
+ const result = await runCommand(
3199
+ action.command,
3200
+ _nullishCoalesce(action.args, () => ( [])),
3201
+ this.runtime.workspaceRoot,
3202
+ {
3203
+ directory: action.directory,
3204
+ background: action.background,
3205
+ onStdout: (chunk) => emitOutput("stdout", chunk),
3206
+ onStderr: (chunk) => emitOutput("stderr", chunk)
3207
+ }
3208
+ );
3209
+ const cmdStr = `${action.command} ${(_nullishCoalesce(action.args, () => ( []))).join(" ")}`.trim();
3210
+ const header = action.description ? `$ ${action.description}
3211
+ > ${cmdStr}` : `$ ${cmdStr}`;
3212
+ const dirInfo = action.directory ? `[dir: ${action.directory}]` : "";
3213
+ const parts = [
3214
+ dirInfo ? `${header} ${dirInfo}` : header,
3215
+ result.stdout,
3216
+ result.stderr
3217
+ ].filter(Boolean);
3218
+ if (result.backgroundPid) {
3219
+ parts.push(`[Background PID: ${result.backgroundPid}]`);
3220
+ }
3221
+ return parts.join("\n");
3222
+ }
3223
+ case "add_dependency": {
3224
+ await addDependency(this.runtime.workspaceRoot, action.name, action.version, { dev: action.dev });
3225
+ return `Added dependency ${action.name}@${action.version}${action.dev ? " (dev)" : ""}`;
3226
+ }
3227
+ case "remove_dependency": {
3228
+ await removeDependency(this.runtime.workspaceRoot, action.name, { dev: action.dev });
3229
+ return `Removed dependency ${action.name}${action.dev ? " (dev)" : ""}`;
3230
+ }
3231
+ case "list_tree": {
3232
+ const treeRoot = this.resolveWorkspacePath(_nullishCoalesce(action.path, () => ( ".")));
3233
+ const lines = await listDirectoryTree(treeRoot, {
3234
+ depth: action.depth,
3235
+ workspaceRoot: this.runtime.workspaceRoot
3236
+ });
3237
+ this.recordExploration("list", _nullishCoalesce(action.path, () => ( ".")));
3238
+ return lines.join("\n");
3239
+ }
3240
+ case "file_stats": {
3241
+ if (!action.path) {
3242
+ throw new Error('file_stats requires a "path" argument.');
3243
+ }
3244
+ this.resolveWorkspacePath(action.path);
3245
+ const stats = await fileStats(this.runtime.workspaceRoot, action.path);
3246
+ return stats ? JSON.stringify(stats, null, 2) : `No stats for ${action.path}`;
3247
+ }
3248
+ case "checksum": {
3249
+ if (!action.path) {
3250
+ throw new Error('checksum requires a "path" argument.');
3251
+ }
3252
+ this.resolveWorkspacePath(action.path);
3253
+ const sum = await checksumFile(this.runtime.workspaceRoot, action.path, action.algorithm);
3254
+ return `${_nullishCoalesce(action.algorithm, () => ( "sha256"))} ${action.path}: ${sum}`;
3255
+ }
3256
+ case "git_diff": {
3257
+ if (!action.path) {
3258
+ throw new Error('git_diff requires a "path" argument.');
3259
+ }
3260
+ this.resolveWorkspacePath(action.path);
3261
+ const rawDiff = diffFile(this.runtime.workspaceRoot, action.path);
3262
+ return this.colorizeGitDiff(rawDiff);
3263
+ }
3264
+ case "git_checkout": {
3265
+ if (!action.path) {
3266
+ throw new Error('git_checkout requires a "path" argument.');
3267
+ }
3268
+ this.resolveWorkspacePath(action.path);
3269
+ checkoutFile(this.runtime.workspaceRoot, action.path);
3270
+ return `Restored ${action.path} from git.`;
3271
+ }
3272
+ case "git_status":
3273
+ return gitStatus(this.runtime.workspaceRoot);
3274
+ case "git_list_untracked":
3275
+ return gitListUntracked(this.runtime.workspaceRoot) || "No untracked files.";
3276
+ case "git_diff_range": {
3277
+ const rawDiff = gitDiffRange(this.runtime.workspaceRoot, {
3278
+ range: action.range,
3279
+ staged: action.staged,
3280
+ paths: action.paths
3281
+ });
3282
+ return this.colorizeGitDiff(rawDiff);
3283
+ }
3284
+ case "git_apply_patch": {
3285
+ const patch = this.pickText(action.patch, action.diff);
3286
+ if (!patch) {
3287
+ throw new Error("git_apply_patch requires patch or diff content.");
3288
+ }
3289
+ applyGitPatch(this.runtime.workspaceRoot, patch);
3290
+ return "Applied git patch.";
3291
+ }
3292
+ case "git_worktree_list":
3293
+ return gitListWorktrees(this.runtime.workspaceRoot);
3294
+ case "git_worktree_add": {
3295
+ const worktreePath = this.resolveWorkspacePath(action.path);
3296
+ return gitAddWorktree(this.runtime.workspaceRoot, worktreePath, action.ref);
3297
+ }
3298
+ case "git_worktree_remove": {
3299
+ const worktreePath = this.resolveWorkspacePath(action.path);
3300
+ return gitRemoveWorktree(this.runtime.workspaceRoot, worktreePath, action.force);
3301
+ }
3302
+ // Advanced Worktree Operations
3303
+ case "git_worktree_status_all": {
3304
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3305
+ const statuses = await manager.statusAll();
3306
+ if (statuses.length === 0) {
3307
+ return "No worktrees found.";
3308
+ }
3309
+ const lines = [_chalk2.default.cyan("\u{1F4CA} Worktree Status Summary:"), ""];
3310
+ for (const status of statuses) {
3311
+ const branchName = status.worktree.branch || "(detached)";
3312
+ const cleanIcon = status.isClean ? _chalk2.default.green("\u2713") : _chalk2.default.yellow("!");
3313
+ const syncInfo = status.gitStatus.ahead > 0 || status.gitStatus.behind > 0 ? _chalk2.default.gray(` [\u2191${status.gitStatus.ahead} \u2193${status.gitStatus.behind}]`) : "";
3314
+ lines.push(`${cleanIcon} ${_chalk2.default.bold(branchName)}${syncInfo}`);
3315
+ lines.push(_chalk2.default.gray(` ${status.worktree.path}`));
3316
+ if (!status.isClean) {
3317
+ const changes = [];
3318
+ if (status.gitStatus.staged > 0) changes.push(`${status.gitStatus.staged} staged`);
3319
+ if (status.gitStatus.modified > 0) changes.push(`${status.gitStatus.modified} modified`);
3320
+ if (status.gitStatus.untracked > 0) changes.push(`${status.gitStatus.untracked} untracked`);
3321
+ if (status.gitStatus.conflicts > 0) changes.push(_chalk2.default.red(`${status.gitStatus.conflicts} conflicts`));
3322
+ lines.push(_chalk2.default.yellow(` ${changes.join(", ")}`));
3323
+ }
3324
+ if (status.lastCommit) {
3325
+ lines.push(_chalk2.default.gray(` Last commit: ${status.lastCommit.message.substring(0, 50)}`));
3326
+ }
3327
+ lines.push("");
3328
+ }
3329
+ return lines.join("\n");
3330
+ }
3331
+ case "git_worktree_cleanup": {
3332
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3333
+ const result = await manager.cleanup({
3334
+ dryRun: action.dry_run,
3335
+ removeMerged: action.remove_merged,
3336
+ removeStale: action.remove_stale
3337
+ });
3338
+ if (action.dry_run) {
3339
+ if (result.wouldRemove.length === 0) {
3340
+ return "No worktrees to clean up.";
3341
+ }
3342
+ return `Would remove ${result.wouldRemove.length} worktree(s):
3343
+ ${result.wouldRemove.map((p) => ` - ${p}`).join("\n")}`;
3344
+ }
3345
+ if (result.removed.length === 0) {
3346
+ return "No worktrees were cleaned up.";
3347
+ }
3348
+ return `Cleaned up ${result.removed.length} worktree(s):
3349
+ ${result.removed.map((p) => ` - ${p}`).join("\n")}`;
3350
+ }
3351
+ case "git_worktree_run_parallel": {
3352
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3353
+ console.log(_chalk2.default.cyan(`
3354
+ \u{1F504} Running "${action.command}" across all worktrees...
3355
+ `));
3356
+ const results = await manager.runParallel(action.command, {
3357
+ timeout: action.timeout,
3358
+ maxConcurrent: action.max_concurrent
3359
+ });
3360
+ const lines = [];
3361
+ let successCount = 0;
3362
+ let failCount = 0;
3363
+ for (const result of results) {
3364
+ const branchName = result.branch || "(detached)";
3365
+ const statusIcon = result.success ? _chalk2.default.green("\u2713") : _chalk2.default.red("\u2717");
3366
+ const duration = `${(result.duration / 1e3).toFixed(1)}s`;
3367
+ lines.push(`${statusIcon} ${_chalk2.default.bold(branchName)} (${duration})`);
3368
+ if (result.success) {
3369
+ successCount++;
3370
+ if (result.output.trim()) {
3371
+ lines.push(_chalk2.default.gray(result.output.trim().split("\n").map((l) => ` ${l}`).join("\n")));
3372
+ }
3373
+ } else {
3374
+ failCount++;
3375
+ lines.push(_chalk2.default.red(` Error: ${result.error}`));
3376
+ }
3377
+ lines.push("");
3378
+ }
3379
+ lines.unshift(
3380
+ _chalk2.default.cyan(`\u{1F4CA} Results: ${successCount} succeeded, ${failCount} failed`),
3381
+ ""
3382
+ );
3383
+ return lines.join("\n");
3384
+ }
3385
+ case "git_worktree_sync": {
3386
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3387
+ const result = await manager.syncAll({
3388
+ strategy: action.strategy,
3389
+ mainBranch: action.main_branch,
3390
+ dryRun: action.dry_run
3391
+ });
3392
+ const lines = [_chalk2.default.cyan("\u{1F504} Worktree Sync Results:"), ""];
3393
+ if (result.synced.length > 0) {
3394
+ lines.push(_chalk2.default.green(`Synced (${result.synced.length}):`));
3395
+ for (const path8 of result.synced) {
3396
+ lines.push(` \u2713 ${path8}`);
3397
+ }
3398
+ lines.push("");
3399
+ }
3400
+ if (result.skipped.length > 0) {
3401
+ lines.push(_chalk2.default.yellow(`Skipped (${result.skipped.length}):`));
3402
+ for (const info of result.skipped) {
3403
+ lines.push(` \u2298 ${info}`);
3404
+ }
3405
+ lines.push("");
3406
+ }
3407
+ if (result.failed.length > 0) {
3408
+ lines.push(_chalk2.default.red(`Failed (${result.failed.length}):`));
3409
+ for (const info of result.failed) {
3410
+ lines.push(` \u2717 ${info}`);
3411
+ }
3412
+ }
3413
+ return lines.join("\n");
3414
+ }
3415
+ case "git_worktree_create_for_pr": {
3416
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3417
+ const result = await manager.createForPR(action.pr_number, action.remote);
3418
+ return `Created worktree for PR #${action.pr_number}:
3419
+ Path: ${result.path}
3420
+ Branch: ${result.branch}`;
3421
+ }
3422
+ case "git_worktree_create_from_template": {
3423
+ const manager = new WorktreeManager(this.runtime.workspaceRoot);
3424
+ const templates = manager.getTemplates();
3425
+ const template = templates.find((t) => t.name === action.template);
3426
+ if (!template) {
3427
+ const available = templates.map((t) => t.name).join(", ");
3428
+ throw new Error(`Unknown template "${action.template}". Available: ${available}`);
3429
+ }
3430
+ console.log(_chalk2.default.cyan(`
3431
+ \u{1F4C1} Creating worktree from template "${action.template}"...`));
3432
+ console.log(_chalk2.default.gray(` Template: ${template.description}`));
3433
+ const result = await manager.create({
3434
+ branch: action.branch,
3435
+ newBranch: true,
3436
+ baseBranch: action.base_branch,
3437
+ template: action.template,
3438
+ runSetup: action.run_setup
3439
+ });
3440
+ return `Created worktree from template "${action.template}":
3441
+ Path: ${result.path}
3442
+ Branch: ${result.branch}`;
3443
+ }
3444
+ // Git Stash Operations
3445
+ case "git_stash":
3446
+ return gitStash(this.runtime.workspaceRoot, {
3447
+ message: action.message,
3448
+ includeUntracked: action.include_untracked,
3449
+ keepIndex: action.keep_index
3450
+ });
3451
+ case "git_stash_list":
3452
+ return gitStashList(this.runtime.workspaceRoot);
3453
+ case "git_stash_pop":
3454
+ return gitStashPop(this.runtime.workspaceRoot, action.stash_ref);
3455
+ case "git_stash_apply":
3456
+ return gitStashApply(this.runtime.workspaceRoot, action.stash_ref);
3457
+ case "git_stash_drop":
3458
+ return gitStashDrop(this.runtime.workspaceRoot, action.stash_ref);
3459
+ // Git Branch Operations
3460
+ case "git_branch":
3461
+ return gitBranch(this.runtime.workspaceRoot, action.branch_name, {
3462
+ delete: action.delete,
3463
+ force: action.force
3464
+ });
3465
+ case "git_switch":
3466
+ return gitSwitch(this.runtime.workspaceRoot, action.branch_name, {
3467
+ create: action.create
3468
+ });
3469
+ // Git Cherry-pick Operations
3470
+ case "git_cherry_pick":
3471
+ return gitCherryPick(this.runtime.workspaceRoot, action.commits, {
3472
+ noCommit: action.no_commit,
3473
+ mainline: action.mainline
3474
+ });
3475
+ case "git_cherry_pick_abort":
3476
+ return gitCherryPickAbort(this.runtime.workspaceRoot);
3477
+ case "git_cherry_pick_continue":
3478
+ return gitCherryPickContinue(this.runtime.workspaceRoot);
3479
+ // Git Rebase Operations
3480
+ case "git_rebase":
3481
+ return gitRebase(this.runtime.workspaceRoot, action.upstream, {
3482
+ onto: action.onto,
3483
+ autosquash: action.autosquash
3484
+ });
3485
+ case "git_rebase_abort":
3486
+ return gitRebaseAbort(this.runtime.workspaceRoot);
3487
+ case "git_rebase_continue":
3488
+ return gitRebaseContinue(this.runtime.workspaceRoot);
3489
+ case "git_rebase_skip":
3490
+ return gitRebaseSkip(this.runtime.workspaceRoot);
3491
+ // Git Merge Operations
3492
+ case "git_merge":
3493
+ return gitMerge(this.runtime.workspaceRoot, action.branch, {
3494
+ noCommit: action.no_commit,
3495
+ noFastForward: action.no_ff,
3496
+ squash: action.squash,
3497
+ message: action.message
3498
+ });
3499
+ case "git_merge_abort":
3500
+ return gitMergeAbort(this.runtime.workspaceRoot);
3501
+ // Git Commit Operations
3502
+ case "git_commit": {
3503
+ const scanResult = await this.scanBeforeCommit();
3504
+ if (scanResult) {
3505
+ return scanResult;
3506
+ }
3507
+ return gitCommit(this.runtime.workspaceRoot, {
3508
+ message: action.message,
3509
+ amend: action.amend,
3510
+ allowEmpty: action.allow_empty
3511
+ });
3512
+ }
3513
+ case "git_add":
3514
+ return gitAdd(this.runtime.workspaceRoot, action.paths);
3515
+ case "git_reset":
3516
+ return gitReset(this.runtime.workspaceRoot, action.mode, action.ref);
3517
+ case "auto_commit": {
3518
+ const autoCommitScanResult = await this.scanBeforeCommit();
3519
+ if (autoCommitScanResult) {
3520
+ return autoCommitScanResult;
3521
+ }
3522
+ const info = getAutoCommitInfo(this.runtime.workspaceRoot);
3523
+ if (!info.canCommit) {
3524
+ console.log(_chalk2.default.yellow(`
3525
+ \u26A0 ${info.error}`));
3526
+ return info.error || "Cannot commit";
3527
+ }
3528
+ let commitMessage = action.message || info.suggestedMessage;
3529
+ console.log(_chalk2.default.cyan("\n\u{1F4DD} Changes to commit:"));
3530
+ info.filesChanged.slice(0, 10).forEach((file) => {
3531
+ console.log(_chalk2.default.gray(` ${file}`));
3532
+ });
3533
+ if (info.filesChanged.length > 10) {
3534
+ console.log(_chalk2.default.gray(` ... and ${info.filesChanged.length - 10} more files`));
3535
+ }
3536
+ console.log();
3537
+ console.log(_chalk2.default.cyan("Suggested commit message:"));
3538
+ console.log(_chalk2.default.white(` ${commitMessage}`));
3539
+ console.log();
3540
+ const autoApproveCommit = Boolean(
3541
+ this.runtime.options.yes || process.env.CI === "1" || process.env.AUTOHAND_NON_INTERACTIVE === "1"
3542
+ );
3543
+ if (autoApproveCommit) {
3544
+ console.log(_chalk2.default.gray("Auto-commit approval enabled; committing without prompt."));
3545
+ const result2 = executeAutoCommit(this.runtime.workspaceRoot, commitMessage, action.stage_all !== false);
3546
+ if (result2.success) {
3547
+ console.log(_chalk2.default.green(`
3548
+ \u2713 ${result2.message}`));
3549
+ return result2.message;
3550
+ }
3551
+ console.log(_chalk2.default.red(`
3552
+ \u2717 ${result2.message}`));
3553
+ return result2.message;
3554
+ }
3555
+ const options = [
3556
+ { label: "Yes - commit with this message", value: "y" },
3557
+ { label: "Edit - modify the message", value: "e" },
3558
+ { label: "No - cancel commit", value: "n" }
3559
+ ];
3560
+ const modalResult = await _chunkZYQMLKOKcjs.showModal.call(void 0, {
3561
+ title: "Commit with this message?",
3562
+ options
3563
+ });
3564
+ if (!modalResult || modalResult.value === "n") {
3565
+ console.log(_chalk2.default.yellow("Commit cancelled."));
3566
+ return "Commit cancelled by user";
3567
+ }
3568
+ if (modalResult.value === "e") {
3569
+ const editedMessage = await _chunkZYQMLKOKcjs.showInput.call(void 0, {
3570
+ title: "Enter commit message:",
3571
+ defaultValue: commitMessage
3572
+ });
3573
+ if (editedMessage) {
3574
+ commitMessage = editedMessage;
3575
+ }
3576
+ }
3577
+ const result = executeAutoCommit(this.runtime.workspaceRoot, commitMessage, action.stage_all !== false);
3578
+ if (result.success) {
3579
+ console.log(_chalk2.default.green(`
3580
+ \u2713 ${result.message}`));
3581
+ return result.message;
3582
+ } else {
3583
+ console.log(_chalk2.default.red(`
3584
+ \u2717 ${result.message}`));
3585
+ return result.message;
3586
+ }
3587
+ }
3588
+ // Git Log Operations
3589
+ case "git_log":
3590
+ return gitLog(this.runtime.workspaceRoot, {
3591
+ maxCount: action.max_count,
3592
+ oneline: action.oneline,
3593
+ graph: action.graph,
3594
+ all: action.all
3595
+ });
3596
+ // Git Remote Operations
3597
+ case "git_fetch":
3598
+ return gitFetch(this.runtime.workspaceRoot, action.remote, action.branch);
3599
+ case "git_pull":
3600
+ return gitPull(this.runtime.workspaceRoot, action.remote, action.branch);
3601
+ case "git_push":
3602
+ return gitPush(this.runtime.workspaceRoot, action.remote, action.branch, {
3603
+ force: action.force,
3604
+ setUpstream: action.set_upstream
3605
+ });
3606
+ case "custom_command":
3607
+ return this.executeCustomCommand(action);
3608
+ case "multi_file_edit": {
3609
+ const oldContent = await this.files.readFile(action.file_path);
3610
+ let newContent = oldContent;
3611
+ console.log(_chalk2.default.cyan(`
3612
+ \u270F\uFE0F ${action.file_path}:`));
3613
+ console.log(_chalk2.default.gray(`Applying ${action.edits.length} edit(s)...`));
3614
+ for (let i = 0; i < action.edits.length; i++) {
3615
+ const edit = action.edits[i];
3616
+ if (edit.replace_all) {
3617
+ const count = (newContent.match(new RegExp(this.escapeRegex(edit.old_string), "g")) || []).length;
3618
+ if (count === 0) {
3619
+ console.log(_chalk2.default.yellow(` \u26A0 Edit ${i + 1}: No occurrences found to replace`));
3620
+ console.log(_chalk2.default.gray(` Looking for: "${edit.old_string.substring(0, 60)}${edit.old_string.length > 60 ? "..." : ""}"`));
3621
+ const similar = this.findSimilarText(newContent, edit.old_string);
3622
+ if (similar) {
3623
+ console.log(_chalk2.default.gray(` Similar text found: "${similar.substring(0, 60)}${similar.length > 60 ? "..." : ""}"`));
3624
+ }
3625
+ continue;
3626
+ }
3627
+ newContent = newContent.replaceAll(edit.old_string, edit.new_string);
3628
+ console.log(_chalk2.default.green(` \u2713 Edit ${i + 1}: Replaced ${count} occurrence(s)`));
3629
+ } else {
3630
+ let firstIndex = newContent.indexOf(edit.old_string);
3631
+ if (firstIndex === -1) {
3632
+ const normalizedOld = this.normalizeText(edit.old_string);
3633
+ const normalizedContent = this.normalizeText(newContent);
3634
+ const normalizedIndex = normalizedContent.indexOf(normalizedOld);
3635
+ if (normalizedIndex !== -1) {
3636
+ console.log(_chalk2.default.yellow(` \u26A0 Edit ${i + 1}: Found match with normalized text (unicode chars differ)`));
3637
+ const actualOldString = this.extractMatchingText(newContent, normalizedContent, normalizedOld, normalizedIndex);
3638
+ if (actualOldString) {
3639
+ firstIndex = newContent.indexOf(actualOldString);
3640
+ if (firstIndex !== -1) {
3641
+ newContent = newContent.substring(0, firstIndex) + edit.new_string + newContent.substring(firstIndex + actualOldString.length);
3642
+ console.log(_chalk2.default.green(` \u2713 Edit ${i + 1}: Applied with normalized match`));
3643
+ continue;
3644
+ }
3645
+ }
3646
+ }
3647
+ }
3648
+ if (firstIndex === -1) {
3649
+ console.log(_chalk2.default.red(` \u2717 Edit ${i + 1}: Could not find text to replace`));
3650
+ console.log(_chalk2.default.gray(` Looking for (${edit.old_string.length} chars):`));
3651
+ console.log(_chalk2.default.gray(` "${edit.old_string.substring(0, 80)}${edit.old_string.length > 80 ? "..." : ""}"`));
3652
+ const similar = this.findSimilarText(newContent, edit.old_string);
3653
+ if (similar) {
3654
+ console.log(_chalk2.default.yellow(` Did you mean:`));
3655
+ console.log(_chalk2.default.yellow(` "${similar.substring(0, 80)}${similar.length > 80 ? "..." : ""}"`));
3656
+ }
3657
+ if (edit.old_string.length < 100) {
3658
+ const nonAscii = edit.old_string.match(/[^\x20-\x7E\n\r\t]/g);
3659
+ if (nonAscii && nonAscii.length > 0) {
3660
+ console.log(_chalk2.default.gray(` Non-ASCII chars: ${nonAscii.map((c) => `'${c}' (U+${c.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")})`).join(", ")}`));
3661
+ }
3662
+ }
3663
+ throw new Error(`Could not find text to replace in edit ${i + 1}. See details above.`);
3664
+ }
3665
+ newContent = newContent.substring(0, firstIndex) + edit.new_string + newContent.substring(firstIndex + edit.old_string.length);
3666
+ console.log(_chalk2.default.green(` \u2713 Edit ${i + 1}: Applied successfully`));
3667
+ }
3668
+ }
3669
+ if (oldContent !== newContent) {
3670
+ this.showDiff(oldContent, newContent, action.file_path);
3671
+ await this.files.writeFile(action.file_path, newContent);
3672
+ _optionalChain([this, 'access', _56 => _56.onFileModified, 'optionalCall', _57 => _57(action.file_path)]);
3673
+ }
3674
+ return `Applied ${action.edits.length} edit(s) to ${action.file_path}`;
3675
+ }
3676
+ case "todo_write": {
3677
+ const todoPath = ".autohand/agents/tasks/todos.json";
3678
+ if (!Array.isArray(action.tasks)) {
3679
+ console.log(_chalk2.default.yellow("\u26A0\uFE0F todo_write received invalid tasks (not an array), skipping"));
3680
+ return "todo_write skipped: tasks must be an array";
3681
+ }
3682
+ const validTasks = action.tasks.filter((task) => {
3683
+ if (!task) return false;
3684
+ const hasId = !!task.id;
3685
+ const hasContent = !!(task.content || task.title);
3686
+ return hasId && hasContent;
3687
+ });
3688
+ const normalizedTasks = validTasks.map((task) => {
3689
+ const content = task.content || task.title || "";
3690
+ const title = content;
3691
+ return {
3692
+ ...task,
3693
+ // Preserve extra properties like priority, tags, etc.
3694
+ id: task.id,
3695
+ title,
3696
+ content,
3697
+ // Keep original content field
3698
+ status: task.status || "pending",
3699
+ activeForm: task.activeForm || title,
3700
+ description: task.description
3701
+ };
3702
+ });
3703
+ const allTodos = normalizedTasks;
3704
+ await this.files.writeFile(todoPath, JSON.stringify(allTodos, null, 2));
3705
+ console.log(_chalk2.default.cyan("\n\u{1F4CB} Task Progress:"));
3706
+ const total = allTodos.length;
3707
+ const completed = allTodos.filter((t) => t.status === "completed").length;
3708
+ const inProgress = allTodos.filter((t) => t.status === "in_progress");
3709
+ const pending = allTodos.filter((t) => t.status === "pending").length;
3710
+ const percent = total > 0 ? Math.round(completed / total * 100) : 0;
3711
+ const barWidth = 20;
3712
+ const filled = Math.round(barWidth * percent / 100);
3713
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
3714
+ console.log(` ${_chalk2.default.green(bar)} ${percent}%`);
3715
+ console.log(_chalk2.default.gray(` ${completed} done \xB7 ${inProgress.length} in progress \xB7 ${pending} pending`));
3716
+ if (inProgress.length > 0) {
3717
+ console.log(_chalk2.default.yellow("\n \u{1F504} Active Tasks:"));
3718
+ for (const task of inProgress) {
3719
+ console.log(` \u2022 ${task.title || task.content}`);
3720
+ }
3721
+ }
3722
+ console.log();
3723
+ return `Updated task list: ${percent}% complete (${completed}/${total})`;
3724
+ }
3725
+ case "save_memory": {
3726
+ if (!this.memoryManager) {
3727
+ return "Memory manager not available";
3728
+ }
3729
+ const level = _nullishCoalesce(action.level, () => ( "user"));
3730
+ await this.memoryManager.store(action.fact, level);
3731
+ console.log(_chalk2.default.green(`
3732
+ \u{1F4BE} Memory saved (${level} level): "${action.fact.slice(0, 60)}${action.fact.length > 60 ? "..." : ""}"`));
3733
+ return `Saved to ${level} memory: ${action.fact}`;
3734
+ }
3735
+ case "recall_memory": {
3736
+ if (!this.memoryManager) {
3737
+ return "Memory manager not available";
3738
+ }
3739
+ const memories = await this.memoryManager.recall(action.query, action.level);
3740
+ if (memories.length === 0) {
3741
+ return action.query ? `No memories found matching "${action.query}"` : "No memories stored yet";
3742
+ }
3743
+ const formatted = memories.map((m) => `- [${m.level}] ${m.content}`).join("\n");
3744
+ console.log(_chalk2.default.cyan(`
3745
+ \u{1F9E0} Recalled ${memories.length} memor${memories.length === 1 ? "y" : "ies"}:`));
3746
+ console.log(_chalk2.default.gray(formatted));
3747
+ return formatted;
3748
+ }
3749
+ case "create_meta_tool": {
3750
+ if (!action.name || !action.description || !action.handler) {
3751
+ throw new Error("create_meta_tool requires name, description, and handler");
3752
+ }
3753
+ const builtInNames = this.getRegisteredTools().map((t) => t.name);
3754
+ if (builtInNames.includes(action.name)) {
3755
+ throw new Error(`Cannot create meta-tool "${action.name}": conflicts with built-in tool`);
3756
+ }
3757
+ const dangerousPatterns = [
3758
+ // Destructive file operations
3759
+ { pattern: /rm\s+(-[rf]+\s+)*\/(?!\w)/i, description: "rm with root path" },
3760
+ { pattern: /rm\s+.*--no-preserve-root/i, description: "rm --no-preserve-root" },
3761
+ { pattern: /dd\s+.*(?:of|if)=\/dev\/[sh]d/i, description: "dd to disk device" },
3762
+ { pattern: /mkfs\./i, description: "filesystem format" },
3763
+ { pattern: /wipefs/i, description: "disk wipe" },
3764
+ // Privilege escalation
3765
+ { pattern: /\bsudo\s/i, description: "sudo command" },
3766
+ { pattern: /\bsu\s+-?\s*\w/i, description: "su command" },
3767
+ { pattern: /chmod\s+[0-7]*7[0-7]*/i, description: "world-writable chmod" },
3768
+ { pattern: /chown\s+root/i, description: "chown to root" },
3769
+ // Remote code execution
3770
+ { pattern: /curl\s+.*\|\s*(ba)?sh/i, description: "curl | bash" },
3771
+ { pattern: /wget\s+.*\|\s*(ba)?sh/i, description: "wget | sh" },
3772
+ { pattern: /\beval\s+[`$]/i, description: "eval with expansion" },
3773
+ // Fork bomb and resource exhaustion
3774
+ { pattern: /:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;/i, description: "fork bomb" },
3775
+ { pattern: /while\s+true.*do.*done/i, description: "infinite loop" },
3776
+ // Reverse shell indicators
3777
+ { pattern: /nc\s+.*-e\s*\/bin/i, description: "netcat reverse shell" },
3778
+ { pattern: /ncat\s+.*-e\s*\/bin/i, description: "ncat reverse shell" },
3779
+ { pattern: /bash\s+-i\s+>&?\s*\/dev\/tcp/i, description: "bash reverse shell" },
3780
+ // Dangerous network operations
3781
+ { pattern: /iptables\s+-F/i, description: "flush firewall rules" },
3782
+ // Crypto operations that could lock out user
3783
+ { pattern: /gpg\s+.*--encrypt.*-r\s+\S+\s+\//i, description: "gpg encrypt root" }
3784
+ ];
3785
+ for (const { pattern, description } of dangerousPatterns) {
3786
+ if (pattern.test(action.handler)) {
3787
+ throw new Error(`Handler contains dangerous pattern: ${description}`);
3788
+ }
3789
+ }
3790
+ await this.toolsRegistry.saveMetaTool({
3791
+ name: action.name,
3792
+ description: action.description,
3793
+ parameters: _nullishCoalesce(action.parameters, () => ( { type: "object", properties: {} })),
3794
+ handler: action.handler,
3795
+ source: "agent"
3796
+ });
3797
+ console.log(_chalk2.default.green(`
3798
+ \u{1F527} Created meta-tool: ${action.name}`));
3799
+ console.log(_chalk2.default.gray(` ${action.description}`));
3800
+ console.log(_chalk2.default.gray(` Handler: ${action.handler}`));
3801
+ return `Created meta-tool "${action.name}" - available in this and future sessions`;
3802
+ }
3803
+ // Web Search Operations
3804
+ case "web_search": {
3805
+ if (!action.query) {
3806
+ throw new Error('web_search requires a "query" argument.');
3807
+ }
3808
+ console.log(_chalk2.default.cyan(`
3809
+ \u{1F50D} Searching web: "${action.query}"...`));
3810
+ const results = await _chunkRKJTGGMUcjs.webSearch.call(void 0, action.query, {
3811
+ maxResults: action.max_results,
3812
+ searchType: action.search_type
3813
+ });
3814
+ const formatted = _chunkRKJTGGMUcjs.formatSearchResults.call(void 0, results);
3815
+ console.log(_chalk2.default.gray(formatted.split("\n").slice(0, 10).join("\n")));
3816
+ if (results.length > 3) {
3817
+ console.log(_chalk2.default.gray(" ..."));
3818
+ }
3819
+ return formatted;
3820
+ }
3821
+ case "fetch_url": {
3822
+ if (!action.url) {
3823
+ throw new Error('fetch_url requires a "url" argument.');
3824
+ }
3825
+ console.log(_chalk2.default.cyan(`
3826
+ \u{1F310} Fetching: ${action.url}...`));
3827
+ const content = await _chunkRKJTGGMUcjs.fetchUrl.call(void 0, action.url, {
3828
+ maxLength: action.max_length
3829
+ });
3830
+ const preview = content.slice(0, 500);
3831
+ console.log(_chalk2.default.gray(preview + (content.length > 500 ? "\n ... (truncated)" : "")));
3832
+ return content;
3833
+ }
3834
+ case "package_info": {
3835
+ if (!action.package_name) {
3836
+ throw new Error('package_info requires a "package_name" argument.');
3837
+ }
3838
+ const registryLabel = action.registry ? ` (${action.registry})` : "";
3839
+ console.log(_chalk2.default.cyan(`
3840
+ \u{1F4E6} Getting package info: ${action.package_name}${action.version ? `@${action.version}` : ""}${registryLabel}...`));
3841
+ const info = await _chunkRKJTGGMUcjs.getPackageInfo.call(void 0, action.package_name, {
3842
+ registry: action.registry,
3843
+ version: action.version
3844
+ });
3845
+ const formatted = _chunkRKJTGGMUcjs.formatPackageInfo.call(void 0, info);
3846
+ console.log(_chalk2.default.gray(formatted));
3847
+ return formatted;
3848
+ }
3849
+ case "web_repo": {
3850
+ if (!action.repo) {
3851
+ throw new Error('web_repo requires a "repo" argument.');
3852
+ }
3853
+ if (!action.operation) {
3854
+ throw new Error('web_repo requires an "operation" argument (info, list, or fetch).');
3855
+ }
3856
+ console.log(_chalk2.default.cyan(`
3857
+ \u{1F517} ${action.operation}: ${action.repo}${action.path ? ` \u2192 ${action.path}` : ""}...`));
3858
+ const result = await webRepo({
3859
+ repo: action.repo,
3860
+ operation: action.operation,
3861
+ path: action.path,
3862
+ branch: action.branch
3863
+ });
3864
+ let formattedResult;
3865
+ switch (result.type) {
3866
+ case "info":
3867
+ formattedResult = formatRepoInfo(result.data);
3868
+ break;
3869
+ case "list":
3870
+ formattedResult = formatRepoDir(result.data, result.path);
3871
+ break;
3872
+ case "fetch":
3873
+ formattedResult = result.data;
3874
+ break;
3875
+ }
3876
+ const previewResult = formattedResult.slice(0, 500);
3877
+ console.log(_chalk2.default.gray(previewResult + (formattedResult.length > 500 ? "\n ... (truncated)" : "")));
3878
+ return formattedResult;
3879
+ }
3880
+ // Skills Discovery
3881
+ case "find_agent_skills": {
3882
+ const query = _nullishCoalesce(action.query, () => ( ""));
3883
+ console.log(_chalk2.default.cyan(`
3884
+ Searching skills: "${query}"${action.category ? ` [${action.category}]` : ""}...`));
3885
+ const { searchCommunitySkills } = await Promise.resolve().then(() => _interopRequireWildcard(require("./skills-FYY6F2WV.cjs")));
3886
+ const result = await searchCommunitySkills(query, {
3887
+ category: action.category,
3888
+ limit: action.limit
3889
+ });
3890
+ console.log(_chalk2.default.gray(result.split("\n").slice(0, 15).join("\n")));
3891
+ return result;
3892
+ }
3893
+ // User interaction
3894
+ case "ask_followup_question": {
3895
+ if (!action.question) {
3896
+ throw new Error('ask_followup_question requires a "question" parameter.');
3897
+ }
3898
+ if (this.onAskFollowup) {
3899
+ return this.onAskFollowup(action.question, action.suggested_answers);
3900
+ }
3901
+ console.log(_chalk2.default.cyan("\n\u2753 " + action.question + "\n"));
3902
+ if (Array.isArray(action.suggested_answers) && action.suggested_answers.length > 0) {
3903
+ const options = action.suggested_answers.map((answer, i) => ({
3904
+ label: `${i + 1}. ${answer}`,
3905
+ value: answer
3906
+ }));
3907
+ options.push({
3908
+ label: `${options.length + 1}. Other (type your own answer)`,
3909
+ value: "__other__"
3910
+ });
3911
+ const result = await _chunkZYQMLKOKcjs.showModal.call(void 0, {
3912
+ title: "Select an answer:",
3913
+ options
3914
+ });
3915
+ const selected = _optionalChain([result, 'optionalAccess', _58 => _58.value]);
3916
+ if (!selected) {
3917
+ console.log(_chalk2.default.yellow("\nAnswer cancelled.\n"));
3918
+ return "<answer>No answer provided</answer>";
3919
+ }
3920
+ if (selected === "__other__") {
3921
+ const answer = await _chunkZYQMLKOKcjs.showInput.call(void 0, {
3922
+ title: "Your answer:"
3923
+ });
3924
+ if (!answer) {
3925
+ console.log(_chalk2.default.yellow("\nAnswer cancelled.\n"));
3926
+ return "<answer>No answer provided</answer>";
3927
+ }
3928
+ console.log(_chalk2.default.green(`
3929
+ \u2713 Answer: ${answer}
3930
+ `));
3931
+ return `<answer>${answer}</answer>`;
3932
+ }
3933
+ console.log(_chalk2.default.green(`
3934
+ \u2713 Answer: ${selected}
3935
+ `));
3936
+ return `<answer>${selected}</answer>`;
3937
+ } else {
3938
+ const answer = await _chunkZYQMLKOKcjs.showInput.call(void 0, {
3939
+ title: "Your answer:"
3940
+ });
3941
+ const finalAnswer = answer || "No answer provided";
3942
+ console.log(_chalk2.default.green(`
3943
+ \u2713 Answer: ${finalAnswer}
3944
+ `));
3945
+ return `<answer>${finalAnswer}</answer>`;
3946
+ }
3947
+ }
3948
+ default: {
3949
+ const actionType = action.type;
3950
+ const metaTool = this.toolsRegistry.getMetaTool(actionType);
3951
+ if (metaTool) {
3952
+ return this.executeMetaTool(metaTool, action);
3953
+ }
3954
+ throw new Error(`Unsupported action type ${actionType}`);
3955
+ }
3956
+ }
3957
+ }
3958
+ pickText(...values) {
3959
+ for (const value of values) {
3960
+ if (typeof value === "string") {
3961
+ return value;
3962
+ }
3963
+ }
3964
+ return void 0;
3965
+ }
3966
+ /**
3967
+ * Extract file outline/structure for smart chunking of large files.
3968
+ * Identifies imports, classes, functions, and key sections with line numbers.
3969
+ */
3970
+ extractFileOutline(lines, filePath) {
3971
+ const ext = _optionalChain([filePath, 'access', _59 => _59.split, 'call', _60 => _60("."), 'access', _61 => _61.pop, 'call', _62 => _62(), 'optionalAccess', _63 => _63.toLowerCase, 'call', _64 => _64()]) || "";
3972
+ const outline = [];
3973
+ const patterns = {
3974
+ ts: [
3975
+ /^(import|export)\s+/,
3976
+ /^(export\s+)?(async\s+)?function\s+(\w+)/,
3977
+ /^(export\s+)?(abstract\s+)?class\s+(\w+)/,
3978
+ /^(export\s+)?interface\s+(\w+)/,
3979
+ /^(export\s+)?type\s+(\w+)/,
3980
+ /^(export\s+)?enum\s+(\w+)/,
3981
+ /^(export\s+)?const\s+(\w+)\s*[=:]/
3982
+ ],
3983
+ js: [
3984
+ /^(import|export)\s+/,
3985
+ /^(export\s+)?(async\s+)?function\s+(\w+)/,
3986
+ /^(export\s+)?class\s+(\w+)/,
3987
+ /^(export\s+)?const\s+(\w+)\s*=/,
3988
+ /^module\.exports/
3989
+ ],
3990
+ py: [
3991
+ /^(from|import)\s+/,
3992
+ /^(async\s+)?def\s+(\w+)/,
3993
+ /^class\s+(\w+)/,
3994
+ /^(\w+)\s*=\s*(lambda|def)/
3995
+ ],
3996
+ rs: [
3997
+ /^(use|mod)\s+/,
3998
+ /^(pub\s+)?(async\s+)?fn\s+(\w+)/,
3999
+ /^(pub\s+)?struct\s+(\w+)/,
4000
+ /^(pub\s+)?enum\s+(\w+)/,
4001
+ /^(pub\s+)?trait\s+(\w+)/,
4002
+ /^impl\s+/
4003
+ ],
4004
+ go: [
4005
+ /^import\s+/,
4006
+ /^func\s+(\w+|\(\w+\s+\*?\w+\)\s+\w+)/,
4007
+ /^type\s+(\w+)\s+(struct|interface)/,
4008
+ /^var\s+(\w+)/,
4009
+ /^const\s+/
4010
+ ]
4011
+ };
4012
+ const langPatterns = patterns[ext] || patterns["ts"] || [];
4013
+ if (["tsx", "jsx", "mts", "cts"].includes(ext)) {
4014
+ langPatterns.push(...patterns["ts"] || []);
4015
+ }
4016
+ let importStart = -1;
4017
+ let importEnd = -1;
4018
+ lines.forEach((line, idx) => {
4019
+ const trimmed = line.trim();
4020
+ if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*")) {
4021
+ return;
4022
+ }
4023
+ const lineNum = idx + 1;
4024
+ if (/^(import|from|use|require)\s+/.test(trimmed)) {
4025
+ if (importStart === -1) {
4026
+ importStart = lineNum;
4027
+ }
4028
+ importEnd = lineNum;
4029
+ return;
4030
+ }
4031
+ for (const pattern of langPatterns) {
4032
+ if (pattern.test(trimmed) && !/^(import|from|use)\s+/.test(trimmed)) {
4033
+ let identifier = trimmed.slice(0, 60);
4034
+ if (identifier.length < trimmed.length) identifier += "...";
4035
+ outline.push(` ${String(lineNum).padStart(4)}: ${identifier}`);
4036
+ break;
4037
+ }
4038
+ }
4039
+ });
4040
+ const result = [];
4041
+ if (importStart !== -1) {
4042
+ result.push(`Imports: lines ${importStart}-${importEnd}`);
4043
+ }
4044
+ if (outline.length > 0) {
4045
+ result.push("");
4046
+ result.push("Definitions:");
4047
+ result.push(...outline.slice(0, 50));
4048
+ if (outline.length > 50) {
4049
+ result.push(` ... and ${outline.length - 50} more`);
4050
+ }
4051
+ }
4052
+ return result.length > 0 ? result.join("\n") : "No structure detected";
4053
+ }
4054
+ recordExploration(kind, target) {
4055
+ if (!target) {
4056
+ return;
4057
+ }
4058
+ _optionalChain([this, 'access', _65 => _65.logExploration, 'optionalCall', _66 => _66({ kind, target })]);
4059
+ }
4060
+ async executeCustomCommand(action) {
4061
+ const existing = await loadCustomCommand(action.name);
4062
+ const definition = _nullishCoalesce(existing, () => ( {
4063
+ name: action.name,
4064
+ command: action.command,
4065
+ args: action.args,
4066
+ description: action.description,
4067
+ dangerous: action.dangerous
4068
+ }));
4069
+ if (!definition.command || typeof definition.command !== "string") {
4070
+ return `Error: custom_command "${action.name}" requires a "command" argument (string)`;
4071
+ }
4072
+ if (!existing) {
4073
+ console.log(_chalk2.default.cyan(`Custom command: ${definition.name}`));
4074
+ console.log(_chalk2.default.gray(_nullishCoalesce(definition.description, () => ( "No description provided."))));
4075
+ console.log(_chalk2.default.gray(`Command: ${definition.command} ${(_nullishCoalesce(definition.args, () => ( []))).join(" ")}`));
4076
+ if (this.isDestructiveCommand(definition.command)) {
4077
+ console.log(_chalk2.default.red("Warning: command may be destructive."));
4078
+ }
4079
+ const answer = await this.confirmDangerousAction(
4080
+ "Add and run this custom command?",
4081
+ { tool: "run_command", command: definition.command }
4082
+ );
4083
+ if (!answer) {
4084
+ return "Custom command rejected by user.";
4085
+ }
4086
+ await saveCustomCommand(definition);
4087
+ }
4088
+ const result = await runCommand(definition.command, _nullishCoalesce(definition.args, () => ( [])), this.runtime.workspaceRoot);
4089
+ return [`$ ${definition.command} ${(_nullishCoalesce(definition.args, () => ( []))).join(" ")}`, result.stdout, result.stderr].filter(Boolean).join("\n");
4090
+ }
4091
+ isDestructiveCommand(command) {
4092
+ const lowered = command.toLowerCase();
4093
+ return lowered.includes("rm ") || lowered.includes("sudo ") || lowered.includes("dd ");
4094
+ }
4095
+ static {
4096
+ /**
4097
+ * Shell metacharacters that could enable command injection
4098
+ */
4099
+ this.SHELL_METACHARACTERS = /[|;&$`><(){}[\]!#*?~'"\\]/;
4100
+ }
4101
+ /**
4102
+ * Safely escape a value for shell interpolation
4103
+ * Uses single quotes which prevent all shell expansion except for single quotes themselves
4104
+ */
4105
+ shellEscape(value) {
4106
+ return "'" + value.replace(/'/g, `'"'"'`) + "'";
4107
+ }
4108
+ /**
4109
+ * Execute a dynamic meta-tool by substituting {{param}} placeholders
4110
+ */
4111
+ async executeMetaTool(metaTool, args) {
4112
+ let command = metaTool.handler;
4113
+ const placeholderRegex = /\{\{(\w+)\}\}/g;
4114
+ let match;
4115
+ while ((match = placeholderRegex.exec(metaTool.handler)) !== null) {
4116
+ const paramName = match[1];
4117
+ const value = args[paramName];
4118
+ if (value === void 0 || value === null) {
4119
+ throw new Error(`Missing required parameter "${paramName}" for meta-tool "${metaTool.name}"`);
4120
+ }
4121
+ const stringValue = String(value);
4122
+ let safeValue;
4123
+ if (_ActionExecutor.SHELL_METACHARACTERS.test(stringValue)) {
4124
+ safeValue = this.shellEscape(stringValue);
4125
+ console.log(_chalk2.default.yellow(` \u26A0 Parameter "${paramName}" contains shell metacharacters, escaped for safety`));
4126
+ } else {
4127
+ safeValue = stringValue;
4128
+ }
4129
+ command = command.replace(new RegExp(`\\{\\{${paramName}\\}\\}`, "g"), safeValue);
4130
+ }
4131
+ console.log(_chalk2.default.cyan(`
4132
+ \u{1F527} Running meta-tool: ${metaTool.name}`));
4133
+ console.log(_chalk2.default.gray(` $ ${command}`));
4134
+ const result = await runCommand(command, [], this.runtime.workspaceRoot, { shell: true });
4135
+ return [`$ ${command}`, result.stdout, result.stderr].filter(Boolean).join("\n");
4136
+ }
4137
+ applySearchReplaceBlocks(content, blocks) {
4138
+ let result = content;
4139
+ if (blocks.includes("SEARCH:") && blocks.includes("REPLACE:") && !blocks.includes("<<<<<<< SEARCH")) {
4140
+ const searchIdx = blocks.indexOf("SEARCH:");
4141
+ const replaceIdx = blocks.indexOf("REPLACE:");
4142
+ if (searchIdx !== -1 && replaceIdx !== -1 && replaceIdx > searchIdx) {
4143
+ const searchText = blocks.slice(searchIdx + 7, replaceIdx).trim();
4144
+ const replaceText = blocks.slice(replaceIdx + 8).trim();
4145
+ const idx = result.indexOf(searchText);
4146
+ if (idx === -1) {
4147
+ throw new Error(`SEARCH text not found: "${searchText.slice(0, 50)}..."`);
4148
+ }
4149
+ result = result.slice(0, idx) + replaceText + result.slice(idx + searchText.length);
4150
+ return result;
4151
+ }
4152
+ }
4153
+ const MARKERS = { search: "<<<<<<< SEARCH", div: "=======", replace: ">>>>>>> REPLACE" };
4154
+ let remaining = blocks;
4155
+ while (remaining.includes(MARKERS.search)) {
4156
+ const searchStart = remaining.indexOf(MARKERS.search);
4157
+ const divPos = remaining.indexOf(MARKERS.div, searchStart);
4158
+ const replaceEnd = remaining.indexOf(MARKERS.replace, divPos);
4159
+ if (divPos === -1 || replaceEnd === -1) {
4160
+ throw new Error("Malformed SEARCH/REPLACE block");
4161
+ }
4162
+ const searchText = remaining.slice(searchStart + MARKERS.search.length, divPos).replace(/^\n/, "").replace(/\n$/, "");
4163
+ const replaceText = remaining.slice(divPos + MARKERS.div.length, replaceEnd).replace(/^\n/, "").replace(/\n$/, "");
4164
+ const idx = result.indexOf(searchText);
4165
+ if (idx === -1) {
4166
+ throw new Error(`SEARCH text not found: "${searchText.slice(0, 50)}..."`);
4167
+ }
4168
+ result = result.slice(0, idx) + replaceText + result.slice(idx + searchText.length);
4169
+ remaining = remaining.slice(replaceEnd + MARKERS.replace.length);
4170
+ }
4171
+ return result;
4172
+ }
4173
+ /**
4174
+ * Escape special regex characters in a string
4175
+ */
4176
+ escapeRegex(str) {
4177
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4178
+ }
4179
+ /**
4180
+ * Normalize text by converting common unicode variants to ASCII equivalents
4181
+ */
4182
+ normalizeText(text) {
4183
+ return text.replace(/[\u2014\u2013]/g, "-").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"').replace(/\u2026/g, "...").replace(/\u00A0/g, " ").replace(/[\u200B\u200C\u200D\uFEFF]/g, "");
4184
+ }
4185
+ /**
4186
+ * Extract the actual text from original content that matches a normalized position
4187
+ */
4188
+ extractMatchingText(originalContent, normalizedContent, normalizedSearch, normalizedIndex) {
4189
+ let origIdx = 0;
4190
+ let normIdx = 0;
4191
+ while (normIdx < normalizedIndex && origIdx < originalContent.length) {
4192
+ const origChar = originalContent[origIdx];
4193
+ const normChar = this.normalizeText(origChar);
4194
+ origIdx++;
4195
+ normIdx += normChar.length;
4196
+ }
4197
+ const startIdx = origIdx;
4198
+ const targetNormEnd = normalizedIndex + normalizedSearch.length;
4199
+ while (normIdx < targetNormEnd && origIdx < originalContent.length) {
4200
+ const origChar = originalContent[origIdx];
4201
+ const normChar = this.normalizeText(origChar);
4202
+ origIdx++;
4203
+ normIdx += normChar.length;
4204
+ }
4205
+ return originalContent.substring(startIdx, origIdx);
4206
+ }
4207
+ /**
4208
+ * Find text similar to the search string in the content
4209
+ * Uses a simple approach: look for lines that share significant words
4210
+ */
4211
+ findSimilarText(content, search) {
4212
+ const commonWords = /* @__PURE__ */ new Set(["the", "and", "for", "are", "but", "not", "you", "all", "can", "had", "her", "was", "one", "our", "out"]);
4213
+ const searchWords = search.toLowerCase().split(/\s+/).filter((w) => w.length >= 3 && !commonWords.has(w)).slice(0, 5);
4214
+ if (searchWords.length === 0) return null;
4215
+ const lines = content.split("\n");
4216
+ let bestMatch = null;
4217
+ for (const line of lines) {
4218
+ const lineLower = line.toLowerCase();
4219
+ let score = 0;
4220
+ for (const word of searchWords) {
4221
+ if (lineLower.includes(word)) {
4222
+ score++;
4223
+ }
4224
+ }
4225
+ const searchStart = search.substring(0, Math.min(20, search.length)).toLowerCase();
4226
+ if (lineLower.includes(searchStart)) {
4227
+ score += 2;
4228
+ }
4229
+ if (score > 0 && (!bestMatch || score > bestMatch.score)) {
4230
+ bestMatch = { line: line.trim(), score };
4231
+ }
4232
+ }
4233
+ return bestMatch && bestMatch.score >= 2 ? bestMatch.line : null;
4234
+ }
4235
+ /**
4236
+ * Colorize raw git diff output with green for additions and red for removals
4237
+ */
4238
+ colorizeGitDiff(diffOutput) {
4239
+ const useTheme = _chunkPGRH5Q77cjs.isThemeInitialized.call(void 0, );
4240
+ const theme = useTheme ? _chunkPGRH5Q77cjs.getTheme.call(void 0, ) : null;
4241
+ if (!diffOutput || diffOutput === "No diff") {
4242
+ return theme ? theme.fg("muted", "No changes") : _chalk2.default.gray("No changes");
4243
+ }
4244
+ const termWidth = process.stdout.columns || 100;
4245
+ const lines = diffOutput.split("\n");
4246
+ const colorizedLines = [];
4247
+ let additions = 0;
4248
+ let deletions = 0;
4249
+ const addedColor = _optionalChain([theme, 'optionalAccess', _67 => _67.getColor, 'call', _68 => _68("diffAdded")]) || "#4caf50";
4250
+ const removedColor = _optionalChain([theme, 'optionalAccess', _69 => _69.getColor, 'call', _70 => _70("diffRemoved")]) || "#f44336";
4251
+ const contextColor = _optionalChain([theme, 'optionalAccess', _71 => _71.getColor, 'call', _72 => _72("diffContext")]) || "#9e9e9e";
4252
+ const accentColor = _optionalChain([theme, 'optionalAccess', _73 => _73.getColor, 'call', _74 => _74("accent")]) || "#00bcd4";
4253
+ const addedRgb = _chunkPGRH5Q77cjs.hexToRgb.call(void 0, addedColor);
4254
+ const removedRgb = _chunkPGRH5Q77cjs.hexToRgb.call(void 0, removedColor);
4255
+ const addBgR = addedRgb ? Math.floor(addedRgb.r * 0.15) : 30;
4256
+ const addBgG = addedRgb ? Math.floor(addedRgb.g * 0.2) : 50;
4257
+ const addBgB = addedRgb ? Math.floor(addedRgb.b * 0.15) : 30;
4258
+ const remBgR = removedRgb ? Math.floor(removedRgb.r * 0.25) : 60;
4259
+ const remBgG = removedRgb ? Math.floor(removedRgb.g * 0.15) : 30;
4260
+ const remBgB = removedRgb ? Math.floor(removedRgb.b * 0.15) : 30;
4261
+ for (const line of lines) {
4262
+ if (line.startsWith("+++") || line.startsWith("---")) {
4263
+ colorizedLines.push(_chalk2.default.bold(line));
4264
+ } else if (line.startsWith("@@")) {
4265
+ colorizedLines.push(_chalk2.default.hex(accentColor)(line));
4266
+ } else if (line.startsWith("+")) {
4267
+ additions++;
4268
+ const content = line.slice(1);
4269
+ const prefix = _chalk2.default.bgHex(addedColor).black(" + ");
4270
+ const lineContent = _chalk2.default.bgRgb(addBgR, addBgG, addBgB)(` ${content} `.padEnd(Math.max(termWidth - 5, content.length + 2)));
4271
+ colorizedLines.push(prefix + lineContent);
4272
+ } else if (line.startsWith("-")) {
4273
+ deletions++;
4274
+ const content = line.slice(1);
4275
+ const prefix = _chalk2.default.bgHex(removedColor).white(" - ");
4276
+ const lineContent = _chalk2.default.bgRgb(remBgR, remBgG, remBgB)(` ${content} `.padEnd(Math.max(termWidth - 5, content.length + 2)));
4277
+ colorizedLines.push(prefix + lineContent);
4278
+ } else if (line.startsWith("diff --git")) {
4279
+ colorizedLines.push(_chalk2.default.bold.hex(accentColor)(line));
4280
+ } else if (line.startsWith("index ") || line.startsWith("new file") || line.startsWith("deleted file")) {
4281
+ colorizedLines.push(_chalk2.default.hex(contextColor)(line));
4282
+ } else {
4283
+ colorizedLines.push(_chalk2.default.hex(contextColor)(" ") + line);
4284
+ }
4285
+ }
4286
+ const addText = additions === 1 ? "1 line" : `${additions} lines`;
4287
+ const delText = deletions === 1 ? "1 line" : `${deletions} lines`;
4288
+ const statsLine = _chalk2.default.hex(contextColor)(` Added ${_chalk2.default.hex(addedColor)(addText)}, removed ${_chalk2.default.hex(removedColor)(delText)}
4289
+ `);
4290
+ return statsLine + colorizedLines.join("\n");
4291
+ }
4292
+ /**
4293
+ * Scan staged changes for secrets before commit
4294
+ * @returns Error message if blocked, undefined if safe to proceed
4295
+ */
4296
+ async scanBeforeCommit() {
4297
+ try {
4298
+ const diff = _child_process.execSync.call(void 0, "git diff --cached", {
4299
+ cwd: this.runtime.workspaceRoot,
4300
+ encoding: "utf-8",
4301
+ maxBuffer: 10 * 1024 * 1024
4302
+ // 10MB
4303
+ });
4304
+ if (!diff.trim()) {
4305
+ return void 0;
4306
+ }
4307
+ const result = this.securityScanner.scanDiff(diff);
4308
+ console.log(this.securityScanner.formatDisplay(result));
4309
+ if (this.securityScanner.shouldBlockCommit(result)) {
4310
+ return `[BLOCKED] Commit blocked: ${result.blockedCount} high-severity secret(s) detected. Remove secrets before committing.`;
4311
+ }
4312
+ return void 0;
4313
+ } catch (e9) {
4314
+ console.log(_chalk2.default.yellow("\n[WARN] Could not scan for secrets (git diff failed)"));
4315
+ return void 0;
4316
+ }
4317
+ }
4318
+ showDiff(oldContent, newContent, filePath) {
4319
+ const diff = _diff.diffLines.call(void 0, oldContent, newContent);
4320
+ const contextLines = 3;
4321
+ const lang = filePath ? detectLanguage(filePath) : "text";
4322
+ const shouldHighlight = lang !== "text";
4323
+ const useTheme = _chunkPGRH5Q77cjs.isThemeInitialized.call(void 0, );
4324
+ const theme = useTheme ? _chunkPGRH5Q77cjs.getTheme.call(void 0, ) : null;
4325
+ let additions = 0;
4326
+ let deletions = 0;
4327
+ for (const part of diff) {
4328
+ const lineCount = part.value.split("\n").filter((l, i, a) => i < a.length - 1 || l !== "").length;
4329
+ if (part.added) additions += lineCount;
4330
+ else if (part.removed) deletions += lineCount;
4331
+ }
4332
+ const termWidth = process.stdout.columns || 100;
4333
+ const addText = additions === 1 ? "1 line" : `${additions} lines`;
4334
+ const delText = deletions === 1 ? "1 line" : `${deletions} lines`;
4335
+ if (theme) {
4336
+ console.log(theme.fg("muted", ` Added ${theme.fg("diffAdded", addText)}, removed ${theme.fg("diffRemoved", delText)}`));
4337
+ } else {
4338
+ console.log(_chalk2.default.gray(` Added ${_chalk2.default.green(addText)}, removed ${_chalk2.default.red(delText)}`));
4339
+ }
4340
+ const hunks = [];
4341
+ let currentHunk = null;
4342
+ let oldLineNum = 1;
4343
+ let newLineNum = 1;
4344
+ let contextBuffer = [];
4345
+ for (const part of diff) {
4346
+ const lines = part.value.split("\n").filter((line, idx, arr) => {
4347
+ return idx < arr.length - 1 || line !== "";
4348
+ });
4349
+ if (!part.added && !part.removed) {
4350
+ if (currentHunk) {
4351
+ const trailing = lines.slice(0, contextLines);
4352
+ for (const line of trailing) {
4353
+ currentHunk.changes.push({ line, type: "context", oldNum: oldLineNum, newNum: newLineNum });
4354
+ oldLineNum++;
4355
+ newLineNum++;
4356
+ }
4357
+ if (lines.length > contextLines * 2) {
4358
+ hunks.push(currentHunk);
4359
+ currentHunk = null;
4360
+ const skipped = lines.length - trailing.length;
4361
+ oldLineNum += skipped - contextLines;
4362
+ newLineNum += skipped - contextLines;
4363
+ contextBuffer = lines.slice(-contextLines).map((line, i) => ({
4364
+ line,
4365
+ oldNum: oldLineNum + i,
4366
+ newNum: newLineNum + i
4367
+ }));
4368
+ oldLineNum += contextLines;
4369
+ newLineNum += contextLines;
4370
+ } else {
4371
+ for (let i = contextLines; i < lines.length; i++) {
4372
+ currentHunk.changes.push({ line: lines[i], type: "context", oldNum: oldLineNum, newNum: newLineNum });
4373
+ oldLineNum++;
4374
+ newLineNum++;
4375
+ }
4376
+ }
4377
+ } else {
4378
+ contextBuffer = lines.slice(-contextLines).map((line, i) => ({
4379
+ line,
4380
+ oldNum: oldLineNum + lines.length - contextLines + i,
4381
+ newNum: newLineNum + lines.length - contextLines + i
4382
+ }));
4383
+ oldLineNum += lines.length;
4384
+ newLineNum += lines.length;
4385
+ }
4386
+ } else {
4387
+ if (!currentHunk) {
4388
+ currentHunk = {
4389
+ oldStart: contextBuffer.length > 0 ? contextBuffer[0].oldNum : oldLineNum,
4390
+ newStart: contextBuffer.length > 0 ? contextBuffer[0].newNum : newLineNum,
4391
+ changes: contextBuffer.map((c) => ({ line: c.line, type: "context", oldNum: c.oldNum, newNum: c.newNum }))
4392
+ };
4393
+ contextBuffer = [];
4394
+ }
4395
+ if (part.added) {
4396
+ for (const line of lines) {
4397
+ currentHunk.changes.push({ line, type: "add", newNum: newLineNum });
4398
+ newLineNum++;
4399
+ }
4400
+ } else {
4401
+ for (const line of lines) {
4402
+ currentHunk.changes.push({ line, type: "remove", oldNum: oldLineNum });
4403
+ oldLineNum++;
4404
+ }
4405
+ }
4406
+ }
4407
+ }
4408
+ if (currentHunk) {
4409
+ hunks.push(currentHunk);
4410
+ }
4411
+ for (const hunk of hunks) {
4412
+ for (const change of hunk.changes) {
4413
+ const lineNum = change.type === "add" ? change.newNum : change.oldNum;
4414
+ const lineNumStr = String(lineNum || 0).padStart(3);
4415
+ const highlighted = shouldHighlight ? highlightLine(change.line, lang) : change.line;
4416
+ if (theme) {
4417
+ const addedColor = theme.getColor("diffAdded");
4418
+ const removedColor = theme.getColor("diffRemoved");
4419
+ const contextColor = theme.getColor("diffContext");
4420
+ if (change.type === "add") {
4421
+ const addedRgb = _chunkPGRH5Q77cjs.hexToRgb.call(void 0, addedColor);
4422
+ const bgR = addedRgb ? Math.floor(addedRgb.r * 0.15) : 30;
4423
+ const bgG = addedRgb ? Math.floor(addedRgb.g * 0.2) : 50;
4424
+ const bgB = addedRgb ? Math.floor(addedRgb.b * 0.15) : 30;
4425
+ const prefix = _chalk2.default.bgHex(addedColor).black(` ${lineNumStr} + `);
4426
+ const content = _chalk2.default.bgRgb(bgR, bgG, bgB)(` ${highlighted} `.padEnd(Math.max(termWidth - 10, change.line.length + 2)));
4427
+ console.log(prefix + content);
4428
+ } else if (change.type === "remove") {
4429
+ const removedRgb = _chunkPGRH5Q77cjs.hexToRgb.call(void 0, removedColor);
4430
+ const bgR = removedRgb ? Math.floor(removedRgb.r * 0.25) : 60;
4431
+ const bgG = removedRgb ? Math.floor(removedRgb.g * 0.15) : 30;
4432
+ const bgB = removedRgb ? Math.floor(removedRgb.b * 0.15) : 30;
4433
+ const prefix = _chalk2.default.bgHex(removedColor).white(` ${lineNumStr} - `);
4434
+ const content = _chalk2.default.bgRgb(bgR, bgG, bgB)(` ${highlighted} `.padEnd(Math.max(termWidth - 10, change.line.length + 2)));
4435
+ console.log(prefix + content);
4436
+ } else {
4437
+ console.log(_chalk2.default.hex(contextColor)(` ${lineNumStr} `) + ` ${highlighted}`);
4438
+ }
4439
+ } else {
4440
+ if (change.type === "add") {
4441
+ const prefix = _chalk2.default.bgGreen.black(` ${lineNumStr} + `);
4442
+ const content = _chalk2.default.bgRgb(30, 50, 30)(` ${highlighted} `.padEnd(Math.max(termWidth - 10, change.line.length + 2)));
4443
+ console.log(prefix + content);
4444
+ } else if (change.type === "remove") {
4445
+ const prefix = _chalk2.default.bgRed.white(` ${lineNumStr} - `);
4446
+ const content = _chalk2.default.bgRgb(60, 30, 30)(` ${highlighted} `.padEnd(Math.max(termWidth - 10, change.line.length + 2)));
4447
+ console.log(prefix + content);
4448
+ } else {
4449
+ console.log(_chalk2.default.gray(` ${lineNumStr} `) + ` ${highlighted}`);
4450
+ }
4451
+ }
4452
+ }
4453
+ }
4454
+ console.log();
4455
+ }
4456
+ };
4457
+
4458
+
4459
+
4460
+
4461
+
4462
+ exports.getAutoCommitInfo = getAutoCommitInfo; exports.ToolsRegistry = ToolsRegistry; exports.ActionExecutor = ActionExecutor;
4463
+ /**
4464
+ * @license
4465
+ * Copyright 2025 Autohand AI LLC
4466
+ * SPDX-License-Identifier: Apache-2.0
4467
+ *
4468
+ * Syntax Highlighting for Terminal Output
4469
+ * Uses regex-based tokenization for common languages
4470
+ */
4471
+ /**
4472
+ * @license
4473
+ * Copyright 2025 Autohand AI LLC
4474
+ * SPDX-License-Identifier: Apache-2.0
4475
+ */
4476
+ /**
4477
+ * @license
4478
+ * Copyright 2025 Autohand AI LLC
4479
+ * SPDX-License-Identifier: Apache-2.0
4480
+ *
4481
+ * Advanced Git Worktree Manager
4482
+ * Provides intelligent worktree automation for parallel development workflows
4483
+ */
4484
+ /**
4485
+ * @license
4486
+ * Copyright 2025 Autohand AI LLC
4487
+ * SPDX-License-Identifier: Apache-2.0
4488
+ *
4489
+ * GitHub and GitLab repository browsing capabilities.
4490
+ */
4491
+ /**
4492
+ * @license
4493
+ * Copyright 2025 Autohand AI LLC
4494
+ * SPDX-License-Identifier: Apache-2.0
4495
+ *
4496
+ * Plan File Storage
4497
+ * Saves/loads plans to/from .autohand/plans/ directory
4498
+ */