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.
- package/README.md +97 -2
- package/assets/icon.png +0 -0
- package/dist/AgentRegistry-7LDL5HJH.js +10 -0
- package/dist/AgentRegistry-NQCLWABO.cjs +10 -0
- package/dist/{AutomodeManager-NGRAO2MH.js → AutomodeManager-MWLKGPZK.js} +2 -0
- package/dist/{AutomodeManager-ZKQMBM4T.cjs → AutomodeManager-NYIZNODK.cjs} +3 -1
- package/dist/CommunitySkillsCache-6QPRMTJO.js +8 -0
- package/dist/CommunitySkillsCache-GTQMOCCO.cjs +8 -0
- package/dist/{GitHubRegistryFetcher-US2JJID4.js → GitHubRegistryFetcher-6JQ5JEDZ.js} +1 -0
- package/dist/{GitHubRegistryFetcher-K744NNAJ.cjs → GitHubRegistryFetcher-S7QFUEKV.cjs} +1 -0
- package/dist/HookManager-Q2KYMCP4.cjs +7 -0
- package/dist/HookManager-TTP4Y6DC.js +7 -0
- package/dist/ImportWizard-35YBJ4AM.cjs +466 -0
- package/dist/ImportWizard-XH7CINCH.js +466 -0
- package/dist/LearnAdvisor-A4Q5PPBI.js +9 -0
- package/dist/LearnAdvisor-GASQD7HT.cjs +9 -0
- package/dist/McpClientManager-7RM6YT35.js +8 -0
- package/dist/McpClientManager-RKD7C6OY.cjs +8 -0
- package/dist/MemoryManager-GUNLRP5S.js +8 -0
- package/dist/MemoryManager-TNSGKDKX.cjs +8 -0
- package/dist/{PermissionManager-U5OMGR3L.js → PermissionManager-ATUV34LQ.js} +4 -3
- package/dist/PermissionManager-KMN53FJP.cjs +11 -0
- package/dist/ProjectProfiler-UMJJSOCE.js +194 -0
- package/dist/ProjectProfiler-ZDWR2ODG.cjs +194 -0
- package/dist/ProviderFactory-MR5B23QJ.js +9 -0
- package/dist/ProviderFactory-VFGCJJX6.cjs +9 -0
- package/dist/SessionManager-FEUAU3ZJ.cjs +10 -0
- package/dist/SessionManager-IKWAK2PI.js +10 -0
- package/dist/SkillsRegistry-KPQFTRIT.cjs +9 -0
- package/dist/SkillsRegistry-XJSKPDF2.js +9 -0
- package/dist/SubAgent-NYH6GWQ3.js +11 -0
- package/dist/SubAgent-PZKBDUBA.cjs +11 -0
- package/dist/{SyncApiClient-AYXYSOJM.js → SyncApiClient-LVIO4C2S.js} +1 -0
- package/dist/{SyncApiClient-ID3KXEMA.cjs → SyncApiClient-ZNYMT36M.cjs} +1 -0
- package/dist/about-HHTF2YFL.js +12 -0
- package/dist/about-JGRVNNQC.cjs +12 -0
- package/dist/actionExecutor-U6IBN2TU.cjs +19 -0
- package/dist/actionExecutor-XT5FW3W6.js +19 -0
- package/dist/add-dir-247K3XRY.js +10 -0
- package/dist/add-dir-GS4DXKKH.cjs +10 -0
- package/dist/agents/builtin/code-cleaner.md +14 -0
- package/dist/agents/builtin/docs-writer.md +14 -0
- package/dist/agents/builtin/researcher.md +14 -0
- package/dist/agents/builtin/reviewer.md +15 -0
- package/dist/agents/builtin/tester.md +15 -0
- package/dist/agents/builtin/todo-resolver.md +15 -0
- package/dist/agents-R6ZEFTVR.cjs +12 -0
- package/dist/agents-WJPQWQF2.js +12 -0
- package/dist/agents-new-HKVEIBDJ.js +14 -0
- package/dist/agents-new-X6GTHIO6.cjs +14 -0
- package/dist/assets/icon.png +0 -0
- package/dist/autoSkill-6TGBTEQD.js +20 -0
- package/dist/autoSkill-H4T6VVDA.cjs +20 -0
- package/dist/automode-BC6NVECO.js +10 -0
- package/dist/automode-WN2RSOGW.cjs +10 -0
- package/dist/{cc-UTTLESTY.js → cc-7LEIJ3KF.js} +1 -0
- package/dist/{cc-2W6M7J45.cjs → cc-Q5MM4AWC.cjs} +1 -0
- package/dist/{chunk-N4ZSG6JJ.cjs → chunk-22D2CNTP.cjs} +2 -2
- package/dist/chunk-245KJE5Y.cjs +55 -0
- package/dist/chunk-24QIWILL.js +51 -0
- package/dist/{chunk-MYNHJHDZ.js → chunk-2AA5MFES.js} +1 -1
- package/dist/{chunk-TSY7JHIV.cjs → chunk-33A755XB.cjs} +2 -2
- package/dist/chunk-33RSHBDH.js +131 -0
- package/dist/{chunk-QRGPAUST.js → chunk-34M3HWLR.js} +2 -2
- package/dist/{chunk-U7CZFKPL.cjs → chunk-3K2ESU53.cjs} +2 -2
- package/dist/{chunk-SIGWDEPS.cjs → chunk-3L53OA4E.cjs} +10 -10
- package/dist/chunk-3OEDGIFW.js +42 -0
- package/dist/chunk-3OTU3RS3.cjs +1607 -0
- package/dist/{chunk-MNSTWHK3.cjs → chunk-3PCTTUNW.cjs} +11 -11
- package/dist/{chunk-P5VDZ6PV.js → chunk-3PDTTAKJ.js} +1 -1
- package/dist/chunk-47CKWKEX.cjs +59 -0
- package/dist/{chunk-Z4J4W6YQ.cjs → chunk-4JNNTOGF.cjs} +2 -48
- package/dist/{chunk-GVZPIQWB.js → chunk-4PKF7WPD.js} +11 -5
- package/dist/{chunk-3S4DEIJP.cjs → chunk-5IXII4HX.cjs} +2 -2
- package/dist/{chunk-CRQKDBLD.js → chunk-5P2NXKP3.js} +98 -64
- package/dist/{chunk-DSKVMFRM.cjs → chunk-643VRA5S.cjs} +12 -4
- package/dist/{chunk-VVBBEYTH.cjs → chunk-6HYLHBQG.cjs} +10 -10
- package/dist/{chunk-L5ZFPWHY.js → chunk-6OYHF6MF.js} +12 -4
- package/dist/{chunk-BPTBKO7D.js → chunk-6RF7UKUS.js} +224 -37
- package/dist/{chunk-YHGTBPEC.js → chunk-6ZCULLCA.js} +1 -1
- package/dist/{chunk-VHBUKGRG.js → chunk-72FKPBT5.js} +4 -4
- package/dist/{chunk-2U5HFVRO.cjs → chunk-7BTSG4ME.cjs} +5165 -2194
- package/dist/chunk-7UOUW76C.js +603 -0
- package/dist/{chunk-FEVHH525.cjs → chunk-A4IJHHV7.cjs} +11 -5
- package/dist/{chunk-B6EBHCK2.cjs → chunk-AEJH23FO.cjs} +6 -6
- package/dist/{chunk-WLTVF77A.js → chunk-ALYU6VTM.js} +1 -1
- package/dist/{chunk-NMWEDN4Z.js → chunk-APIXPPMT.js} +5165 -2194
- package/dist/chunk-AS6RTLN7.cjs +203 -0
- package/dist/{chunk-BHV7CBNT.js → chunk-AYS2ASM7.js} +1 -1
- package/dist/{chunk-GRSVQ5YZ.js → chunk-AYSFIUFW.js} +44 -12
- package/dist/{chunk-NUHYCFHW.cjs → chunk-BVKXEQVG.cjs} +54 -65
- package/dist/chunk-BWN2CLLM.cjs +298 -0
- package/dist/{chunk-4HA7IHLJ.cjs → chunk-C5IJIM2V.cjs} +38 -16
- package/dist/{chunk-SRLY7K6J.js → chunk-CAMZTXV6.js} +2 -2
- package/dist/chunk-CDBPBM2K.cjs +29 -0
- package/dist/chunk-CNBKZEX5.cjs +109 -0
- package/dist/{chunk-WQUQ5JMM.js → chunk-CWMZKFTT.js} +4 -4
- package/dist/{chunk-CKN2BLHK.cjs → chunk-CZXGCVTR.cjs} +2 -2
- package/dist/{chunk-SZP4ULM5.cjs → chunk-DJDE4DTT.cjs} +17 -17
- package/dist/chunk-DN573ME7.cjs +1675 -0
- package/dist/chunk-DRE2RXBZ.js +4498 -0
- package/dist/chunk-DSPQEHDT.js +29 -0
- package/dist/{chunk-SFNT5DYE.cjs → chunk-DVUHHH3B.cjs} +4 -4
- package/dist/chunk-DVZOENQ7.cjs +58 -0
- package/dist/{chunk-PWLLLJHU.js → chunk-EGFT4PGW.js} +3 -1
- package/dist/chunk-EGMZDTSL.js +55 -0
- package/dist/chunk-EZMINVLU.js +123 -0
- package/dist/chunk-FHK7UDOJ.cjs +42 -0
- package/dist/{chunk-KWRUQRXR.js → chunk-FKSDEWDH.js} +44 -10
- package/dist/chunk-FMB3TSWP.cjs +218 -0
- package/dist/chunk-FW774QXH.js +1838 -0
- package/dist/{chunk-MY3TZER2.js → chunk-G27PQQFD.js} +1 -1
- package/dist/{chunk-Y2ZSH3YF.cjs → chunk-G3V4SFET.cjs} +57 -23
- package/dist/chunk-G4CAKI3V.js +58 -0
- package/dist/{chunk-FB6JWNJS.js → chunk-GBHDROGL.js} +54 -65
- package/dist/{chunk-DEAEO7RI.js → chunk-GJH7XMSK.js} +15 -1
- package/dist/chunk-GLBAF54O.js +218 -0
- package/dist/{chunk-S47TCZDL.js → chunk-H5SWOLG6.js} +7 -7
- package/dist/chunk-HBXAA3XB.js +83 -0
- package/dist/{chunk-63BXZQZW.js → chunk-HIVRCQS2.js} +26 -4
- package/dist/{chunk-WOGJXDBU.cjs → chunk-HLHTG5ZU.cjs} +18 -4
- package/dist/{chunk-FK2DVRPJ.js → chunk-HLQV64Y5.js} +170 -4
- package/dist/chunk-HOAHWIQ5.cjs +260 -0
- package/dist/{chunk-D2XFTCRP.js → chunk-HQ7YZKXE.js} +1 -1
- package/dist/{chunk-L42HTMMR.cjs → chunk-HTLINWX6.cjs} +2 -2
- package/dist/{chunk-PKOAXQKW.cjs → chunk-HVKOZ2VP.cjs} +11 -11
- package/dist/chunk-HXGBSJL5.cjs +27 -0
- package/dist/chunk-I5IW3T2Y.js +310 -0
- package/dist/chunk-IETRBBMP.cjs +603 -0
- package/dist/{chunk-MTALRU7R.cjs → chunk-IFFXSTOM.cjs} +3 -3
- package/dist/{chunk-V7YTCNMN.cjs → chunk-IKGWDOGU.cjs} +174 -8
- package/dist/chunk-IQ5RXU6O.js +1675 -0
- package/dist/{chunk-ZBIBLOZL.js → chunk-IVM5F2AE.js} +500 -317
- package/dist/chunk-J4Q7XR3G.js +260 -0
- package/dist/{chunk-XL77XYI2.cjs → chunk-J6QET7EF.cjs} +27 -7
- package/dist/{chunk-TQB222ZB.js → chunk-JCLYQ2JC.js} +2 -2
- package/dist/chunk-JSBRDJBE.js +30 -0
- package/dist/{chunk-XPOHYKR3.js → chunk-JX3DFKBI.js} +2 -2
- package/dist/chunk-JYTDYJVW.js +27 -0
- package/dist/{chunk-6SHHB2VD.js → chunk-KPELYZ6L.js} +2 -2
- package/dist/{chunk-ZLOTP56B.cjs → chunk-KWXVKLQ5.cjs} +5 -5
- package/dist/chunk-L3WAH3EM.cjs +131 -0
- package/dist/{chunk-ZXIQCYYV.cjs → chunk-LA7H35XM.cjs} +9 -9
- package/dist/chunk-LENHP55G.cjs +1838 -0
- package/dist/chunk-LJFUXC56.cjs +123 -0
- package/dist/{chunk-R5OO7MEB.cjs → chunk-LNMYK2F5.cjs} +22 -22
- package/dist/chunk-LQGVEP3E.js +109 -0
- package/dist/{chunk-KXAAEROY.js → chunk-LWUJFGOZ.js} +2 -2
- package/dist/chunk-MAKMSQMQ.cjs +504 -0
- package/dist/{chunk-BG4OQUKP.js → chunk-MBBY4ZIK.js} +1 -1
- package/dist/chunk-MSED7RH2.cjs +267 -0
- package/dist/{chunk-NMGF2KUN.js → chunk-MYISNQH4.js} +1 -1
- package/dist/chunk-N23UAW4I.js +59 -0
- package/dist/chunk-N254NRHT.cjs +30 -0
- package/dist/{chunk-TOTDRAWG.js → chunk-NDMIPTV4.js} +1 -1
- package/dist/{chunk-AIH6GUGB.cjs → chunk-NNPAM4HC.cjs} +5 -5
- package/dist/{chunk-HSPWX4Z2.cjs → chunk-O4IF4NJT.cjs} +231 -44
- package/dist/{chunk-DZHR34H6.cjs → chunk-OGV4WJ5L.cjs} +8 -8
- package/dist/chunk-OHUZKDGX.js +348 -0
- package/dist/{chunk-BRXIEKJ3.cjs → chunk-OLSBBZW6.cjs} +5 -5
- package/dist/{chunk-MILZEEUV.js → chunk-OOKY3HPZ.js} +9 -3
- package/dist/chunk-P47WPOXN.js +298 -0
- package/dist/{chunk-ULMPJUJW.cjs → chunk-PRRCJFU3.cjs} +23 -23
- package/dist/{chunk-SMHY3Q7B.cjs → chunk-Q7XSCYND.cjs} +54 -22
- package/dist/chunk-QCLYBIMM.cjs +51 -0
- package/dist/chunk-QMAKTSZB.cjs +48 -0
- package/dist/{chunk-DTFR3WD6.js → chunk-QNGEW5TC.js} +1 -1
- package/dist/chunk-QOXPOR5D.js +267 -0
- package/dist/chunk-R33VKSH5.cjs +348 -0
- package/dist/{chunk-RJP3SZ7Q.cjs → chunk-RD5XAJR2.cjs} +492 -309
- package/dist/chunk-RGR6ME5J.cjs +844 -0
- package/dist/{chunk-EOGKE5GD.cjs → chunk-RKJTGGMU.cjs} +221 -126
- package/dist/{chunk-GD4AFYJ3.js → chunk-RO6WYEWH.js} +24 -4
- package/dist/chunk-S52YW5ZQ.js +844 -0
- package/dist/{chunk-6DWXHBAY.js → chunk-SAHBLB3E.js} +222 -127
- package/dist/{chunk-JHOQABEF.js → chunk-SCXX4LW5.js} +5 -5
- package/dist/{chunk-GIZL57FE.cjs → chunk-SEKD5FH3.cjs} +3 -1
- package/dist/{chunk-JWPI6O5Z.js → chunk-SKV2F3NM.js} +31 -4
- package/dist/{chunk-FHUNAB2K.cjs → chunk-SKYG33B2.cjs} +33 -6
- package/dist/{chunk-BISFR6ZL.js → chunk-SLQAYV3W.js} +1 -1
- package/dist/{chunk-RFNCTE4V.cjs → chunk-SYVYLZZF.cjs} +2 -2
- package/dist/{chunk-3XJD56Z4.js → chunk-T73IDKDF.js} +10 -3
- package/dist/chunk-TBEGGJNC.cjs +310 -0
- package/dist/{chunk-RRZS5A53.js → chunk-TNZRZQ7Q.js} +1 -1
- package/dist/{chunk-CH4SPVFD.cjs → chunk-TXSDBGKX.cjs} +10 -3
- package/dist/chunk-U3WDY42C.cjs +42 -0
- package/dist/{chunk-425MT6Y5.cjs → chunk-U46VYPLR.cjs} +9 -9
- package/dist/{chunk-OLG7LZBD.js → chunk-VG34MG2U.js} +1 -1
- package/dist/{chunk-XDVG3NM4.js → chunk-W3X6PAC7.js} +2 -48
- package/dist/{chunk-LYMTYC67.js → chunk-WHE2SWHU.js} +2 -2
- package/dist/chunk-WM5PAOTQ.cjs +4498 -0
- package/dist/chunk-WNUVPKBW.js +42 -0
- package/dist/{chunk-EV53SLSB.cjs → chunk-WPVWQSL7.cjs} +4 -4
- package/dist/chunk-WQ3VJXZB.js +118 -0
- package/dist/{chunk-HMRDNRTH.js → chunk-X2MSVKDV.js} +2 -2
- package/dist/chunk-X3WS5LDG.js +504 -0
- package/dist/{chunk-43XS26AQ.cjs → chunk-X5VSP65C.cjs} +4 -4
- package/dist/{chunk-DSCQPWUB.cjs → chunk-X5YJ34FZ.cjs} +15 -15
- package/dist/chunk-XAV24VYN.js +48 -0
- package/dist/chunk-XDLH4EDL.cjs +118 -0
- package/dist/{chunk-X765A7J5.js → chunk-XRZEUWKF.js} +1 -1
- package/dist/{chunk-ZKZRFH37.cjs → chunk-XTB6VJVQ.cjs} +6 -6
- package/dist/{chunk-H3GBSPK5.js → chunk-XX2ZO7DS.js} +14 -6
- package/dist/{chunk-RUZB43HU.cjs → chunk-Y72HH2TF.cjs} +22 -14
- package/dist/chunk-YFXTE422.cjs +92 -0
- package/dist/{chunk-OSUWEUZE.js → chunk-YGN4CQIP.js} +1 -1
- package/dist/{chunk-KC5FPUOF.cjs → chunk-YRLYSQEQ.cjs} +2 -2
- package/dist/{chunk-3KBBARKO.js → chunk-YZXUDM5X.js} +85 -28
- package/dist/chunk-Z36XBUMX.cjs +83 -0
- package/dist/chunk-ZK6HOR62.js +92 -0
- package/dist/{chunk-PDKNHU5G.cjs → chunk-ZQE72E6W.cjs} +22 -16
- package/dist/chunk-ZVY2XD6T.js +1607 -0
- package/dist/{chunk-XBUMKEFN.cjs → chunk-ZYQMLKOK.cjs} +91 -34
- package/dist/clear-UO4MNWZW.cjs +12 -0
- package/dist/clear-ZJ5NYP6E.js +12 -0
- package/dist/communityInstaller-6KCFN7YZ.js +19 -0
- package/dist/communityInstaller-PVSOFDZD.cjs +19 -0
- package/dist/completion-MMF2PN2H.js +14 -0
- package/dist/completion-UI5WKHXI.cjs +14 -0
- package/dist/config-E7RINK4R.cjs +18 -0
- package/dist/config-ZN66VXPS.js +18 -0
- package/dist/constants-6CPCJ3DY.cjs +21 -0
- package/dist/{constants-V6J54N3X.js → constants-UFM5B232.js} +2 -1
- package/dist/{defaultHooks-WLMRQUXG.cjs → defaultHooks-RCXPHF4M.cjs} +3 -1
- package/dist/{defaultHooks-R56VYG7I.js → defaultHooks-RDRMER3Z.js} +2 -0
- package/dist/export-N4XIVDSL.cjs +12 -0
- package/dist/export-W22L4D5C.js +12 -0
- package/dist/extractSessionMemories-SDW2MVBQ.cjs +7 -0
- package/dist/extractSessionMemories-V7K42ZHW.js +7 -0
- package/dist/feedback-DR6ADSNE.cjs +15 -0
- package/dist/feedback-FEEAP4QW.js +15 -0
- package/dist/filesystem-3SGCW2BF.js +10 -0
- package/dist/filesystem-MCFXJQ6R.cjs +10 -0
- package/dist/formatters-6K7QVWQL.cjs +10 -0
- package/dist/formatters-DQHO5I36.js +10 -0
- package/dist/{help-LKKQU2TN.js → help-2BLR7L43.js} +3 -2
- package/dist/help-AQHGTS7P.cjs +12 -0
- package/dist/{history-AV4XBFRK.js → history-5FZ3M2AK.js} +3 -2
- package/dist/history-NIUDRMKA.cjs +14 -0
- package/dist/hooks-2EY4IPKV.js +13 -0
- package/dist/hooks-LJVORRIG.cjs +13 -0
- package/dist/i18n-ARDG2SMC.cjs +33 -0
- package/dist/{i18n-BSAPXM56.js → i18n-K7QOWIBH.js} +2 -1
- package/dist/ide-GFW6IJHD.js +12 -0
- package/dist/ide-N2ZNSSB3.cjs +12 -0
- package/dist/import-DFVN3KNZ.js +10 -0
- package/dist/import-QEME3E4T.cjs +170 -0
- package/dist/import-UXM3VK7B.js +170 -0
- package/dist/import-ZS6DPGU5.cjs +10 -0
- package/dist/index.cjs +11233 -11804
- package/dist/index.js +12594 -13165
- package/dist/init-PY75HA3S.cjs +10 -0
- package/dist/init-QNMWLAVY.js +10 -0
- package/dist/language-5UE4G2BT.cjs +18 -0
- package/dist/language-UXMHEZUJ.js +18 -0
- package/dist/learn-HJ3FLNZC.cjs +20 -0
- package/dist/learn-MVYS3RU5.js +20 -0
- package/dist/{lint-44UQJ673.cjs → lint-D5UOJWIK.cjs} +1 -0
- package/dist/{lint-TA2ZHVLM.js → lint-NJPZWVN2.js} +1 -0
- package/dist/{localProjectPermissions-WQYMGI42.js → localProjectPermissions-N77HA3XK.js} +3 -2
- package/dist/localProjectPermissions-UFSMNTBJ.cjs +18 -0
- package/dist/login-DSE7H63A.js +20 -0
- package/dist/login-V3MEWPKN.cjs +20 -0
- package/dist/logout-BMVCLKKW.js +18 -0
- package/dist/logout-XEG7FHOZ.cjs +18 -0
- package/dist/mcp-PYUR4PHO.js +18 -0
- package/dist/mcp-SG6JFLGC.cjs +18 -0
- package/dist/{mcp-install-2KVKRAMQ.cjs → mcp-install-G27HSS3Z.cjs} +26 -14
- package/dist/{mcp-install-77UXRN6R.js → mcp-install-VESN42PI.js} +21 -9
- package/dist/memory-4ZMMEZ2Z.js +10 -0
- package/dist/memory-QSGMVVGH.cjs +10 -0
- package/dist/message-JUBOK2VU.js +9 -0
- package/dist/message-ZJ5AYAMT.cjs +9 -0
- package/dist/model-NANLBZ4Z.cjs +10 -0
- package/dist/model-ZXNV4AF7.js +10 -0
- package/dist/new-5QJY5JP2.js +12 -0
- package/dist/new-PMMG55UX.cjs +12 -0
- package/dist/{patch-BAAQIYSW.js → patch-5F6VBIT3.js} +2 -0
- package/dist/{patch-J32X2QQP.cjs → patch-MOD7QC3D.cjs} +3 -1
- package/dist/permissions-LECTCJ4H.cjs +13 -0
- package/dist/permissions-VP5VGIBL.js +13 -0
- package/dist/{plan-JFGNRL2S.js → plan-G5CEKJI4.js} +1 -0
- package/dist/{plan-B3CW5DXJ.cjs → plan-QKOHE3LH.cjs} +1 -0
- package/dist/quit-BKOOPHU5.cjs +10 -0
- package/dist/quit-FVFNYACP.js +10 -0
- package/dist/registry-KWZGYJC2.js +2108 -0
- package/dist/registry-YN4FQPOO.cjs +2108 -0
- package/dist/resume-EXFQSQPH.js +13 -0
- package/dist/resume-PP2IQM5S.cjs +13 -0
- package/dist/search-C56FBN67.cjs +17 -0
- package/dist/search-XGZDYBF4.js +17 -0
- package/dist/{session-T3TAZ5ZU.cjs → session-BSU2L5UI.cjs} +1 -0
- package/dist/{session-H5QWKE5E.js → session-SZMRN5KG.js} +1 -0
- package/dist/sessions-54KI3F2Q.js +10 -0
- package/dist/sessions-DDTSPNVW.cjs +10 -0
- package/dist/settings-BDO37TTO.cjs +30 -0
- package/dist/settings-FHRDFPLK.js +30 -0
- package/dist/share-IERCTBGN.cjs +14 -0
- package/dist/share-TGROUE6R.js +14 -0
- package/dist/skills-6OL4OSGA.js +76 -0
- package/dist/skills-FYY6F2WV.cjs +76 -0
- package/dist/skills-OM4IGBAA.cjs +26 -0
- package/dist/skills-S3GRN323.js +26 -0
- package/dist/{skills-install-MQINL3EC.js → skills-install-6CSWC24P.js} +97 -26
- package/dist/{skills-install-IKJZN4G2.cjs → skills-install-O3LZ2ETC.cjs} +106 -35
- package/dist/skills-new-ALD2PTHN.js +15 -0
- package/dist/skills-new-PWLKK7GW.cjs +15 -0
- package/dist/slashCommands-L4ZD33LJ.js +75 -0
- package/dist/slashCommands-YY2VUUDF.cjs +75 -0
- package/dist/status-3PC5XWSS.cjs +11 -0
- package/dist/status-KCLVOYPD.js +11 -0
- package/dist/sync-6SDWG5RK.js +18 -0
- package/dist/sync-7JMZVEQD.cjs +40 -0
- package/dist/{sync-EXYX7HXW.js → sync-KWX67OUN.js} +3 -2
- package/dist/sync-WHURZL3U.cjs +18 -0
- package/dist/tasks-5FPBIFLC.js +9 -0
- package/dist/tasks-TXGKGNH6.cjs +9 -0
- package/dist/team-5YXP3JGR.js +9 -0
- package/dist/team-IIWEZKNR.cjs +9 -0
- package/dist/teammate-2KMKJXAM.cjs +139 -0
- package/dist/teammate-L6EZQ3I2.js +139 -0
- package/dist/theme-BE5A4FPN.cjs +18 -0
- package/dist/theme-YMFCQP7J.js +18 -0
- package/dist/ui/questionModal.cjs +7 -25
- package/dist/ui/questionModal.js +6 -24
- package/dist/undo-KZHUUZTD.cjs +10 -0
- package/dist/undo-NEIEHQVX.js +10 -0
- package/dist/update-TVAJMMBC.js +82 -0
- package/dist/update-Z6BIIQDC.cjs +82 -0
- package/package.json +10 -3
- package/dist/CommunitySkillsCache-ILWHWE5P.js +0 -7
- package/dist/CommunitySkillsCache-KHC6RUJW.cjs +0 -7
- package/dist/HookManager-X47HCM5G.cjs +0 -6
- package/dist/HookManager-ZXKHCD7U.js +0 -6
- package/dist/MemoryManager-6ZT7IDO5.cjs +0 -7
- package/dist/MemoryManager-AJGS5AKB.js +0 -7
- package/dist/PermissionManager-HG6W2DGU.cjs +0 -10
- package/dist/SessionManager-BJ2G6VV4.cjs +0 -9
- package/dist/SessionManager-ENPGYK5J.js +0 -9
- package/dist/SkillsRegistry-6ZFOCT25.cjs +0 -8
- package/dist/SkillsRegistry-C2SHOZ5D.js +0 -8
- package/dist/about-3BJTNSLK.js +0 -11
- package/dist/about-EABQNJGV.cjs +0 -11
- package/dist/add-dir-7FD4DMDA.cjs +0 -9
- package/dist/add-dir-LOYJ4YB5.js +0 -9
- package/dist/agents-2Y6ASV7C.js +0 -10
- package/dist/agents-UOSPKLQL.cjs +0 -10
- package/dist/agents-new-23NSGAM5.js +0 -13
- package/dist/agents-new-WI2EL7IJ.cjs +0 -13
- package/dist/automode-LGWTY3UX.js +0 -9
- package/dist/automode-WLBQ7MN7.cjs +0 -9
- package/dist/chunk-5UBW2BGC.js +0 -33
- package/dist/chunk-I6DBWNLN.cjs +0 -169
- package/dist/chunk-IZBCMJHJ.cjs +0 -33
- package/dist/completion-7WGMHKOR.cjs +0 -13
- package/dist/completion-KH33NSGP.js +0 -13
- package/dist/constants-RBQTR32A.cjs +0 -20
- package/dist/export-3QN3IH7A.js +0 -11
- package/dist/export-BI54X3MP.cjs +0 -11
- package/dist/feedback-CI4OIPOS.cjs +0 -14
- package/dist/feedback-GFPL5STE.js +0 -14
- package/dist/formatters-N5IJKYZY.cjs +0 -8
- package/dist/formatters-UG6VZJJ5.js +0 -8
- package/dist/help-CWMUGD3V.cjs +0 -11
- package/dist/history-73VBEMSI.cjs +0 -13
- package/dist/hooks-62UDQBGH.cjs +0 -12
- package/dist/hooks-XORDJD5X.js +0 -12
- package/dist/i18n-X2IU2EZD.cjs +0 -32
- package/dist/ide-RPKZALQV.js +0 -11
- package/dist/ide-YMNXJB6A.cjs +0 -11
- package/dist/init-J5HR4R7U.js +0 -9
- package/dist/init-JCC7RVMC.cjs +0 -9
- package/dist/language-AZISJCEZ.js +0 -16
- package/dist/language-F65RA6FZ.cjs +0 -16
- package/dist/localProjectPermissions-2EATUDZM.cjs +0 -17
- package/dist/login-5HLPMECE.js +0 -18
- package/dist/login-ISWYYBXP.cjs +0 -18
- package/dist/logout-3EKZM5J3.cjs +0 -16
- package/dist/logout-GE7TSZ24.js +0 -16
- package/dist/mcp-EW64QRFA.cjs +0 -15
- package/dist/mcp-VHS7AMF2.js +0 -15
- package/dist/memory-2I473RU3.js +0 -9
- package/dist/memory-JZ6NPSP3.cjs +0 -9
- package/dist/model-GXZLARPT.js +0 -9
- package/dist/model-Y274DBDO.cjs +0 -9
- package/dist/new-BG5VIGZ7.cjs +0 -9
- package/dist/new-YXFDQOA7.js +0 -9
- package/dist/permissions-QILEAGBP.cjs +0 -12
- package/dist/permissions-WVEOVMWO.js +0 -12
- package/dist/quit-NC32OEJG.cjs +0 -9
- package/dist/quit-WRRIGU33.js +0 -9
- package/dist/resume-GJIKIDPR.cjs +0 -12
- package/dist/resume-RMJNCAOK.js +0 -12
- package/dist/search-UIWIXB73.js +0 -14
- package/dist/search-WQNXDA2E.cjs +0 -14
- package/dist/sessions-HPFX2GDD.js +0 -9
- package/dist/sessions-SAQU6MFA.cjs +0 -9
- package/dist/share-2WH5ZVOO.cjs +0 -13
- package/dist/share-PSSWWVV5.js +0 -13
- package/dist/skills-LJZA6PVJ.js +0 -13
- package/dist/skills-YTYGART7.cjs +0 -13
- package/dist/skills-new-3WCU3CWB.js +0 -14
- package/dist/skills-new-O5LFVFZU.cjs +0 -14
- package/dist/slashCommands-7IRDOXOQ.cjs +0 -55
- package/dist/slashCommands-C6CAQA25.js +0 -55
- package/dist/status-4EDV2LSY.cjs +0 -10
- package/dist/status-NU7TJDCE.js +0 -10
- package/dist/sync-3GFSEIAZ.js +0 -16
- package/dist/sync-6M3WRKMH.cjs +0 -39
- package/dist/sync-CQNQDNTJ.cjs +0 -16
- package/dist/theme-EMJGULMI.cjs +0 -16
- package/dist/theme-FGDSXNU3.js +0 -16
- package/dist/undo-CTXQYE7C.cjs +0 -9
- package/dist/undo-HX2ZMECP.js +0 -9
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildNpxIsolatedCacheEnv,
|
|
3
|
+
isNpxCommand,
|
|
4
|
+
isRetriableNpxInstallError,
|
|
5
|
+
normalizeMcpCommandForSpawn
|
|
6
|
+
} from "./chunk-WQ3VJXZB.js";
|
|
7
|
+
|
|
8
|
+
// src/mcp/McpClientManager.ts
|
|
9
|
+
import { spawn } from "child_process";
|
|
10
|
+
import { EventEmitter } from "events";
|
|
11
|
+
|
|
12
|
+
// src/mcp/types.ts
|
|
13
|
+
var VALID_TRANSPORTS = ["stdio", "sse", "http"];
|
|
14
|
+
function validateMcpServerConfig(config) {
|
|
15
|
+
if (!config.name || typeof config.name !== "string" || config.name.trim() === "") {
|
|
16
|
+
throw new Error('MCP server config requires a non-empty "name" field');
|
|
17
|
+
}
|
|
18
|
+
if (!VALID_TRANSPORTS.includes(config.transport)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`MCP server config has invalid "transport" type: "${config.transport}". Must be one of: ${VALID_TRANSPORTS.join(", ")}`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
if (config.transport === "stdio") {
|
|
24
|
+
if (!config.command || typeof config.command !== "string") {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`MCP stdio server "${config.name}" requires a "command" field`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (config.transport === "sse" || config.transport === "http") {
|
|
31
|
+
if (!config.url || typeof config.url !== "string") {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`MCP ${config.transport} server "${config.name}" requires a "url" field`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function convertMcpToolToAutohand(mcpTool, serverName) {
|
|
39
|
+
const prefixedName = `mcp__${serverName}__${mcpTool.name}`;
|
|
40
|
+
return {
|
|
41
|
+
name: prefixedName,
|
|
42
|
+
description: mcpTool.description ?? "",
|
|
43
|
+
parameters: {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: mcpTool.inputSchema.properties ?? {},
|
|
46
|
+
...mcpTool.inputSchema.required && mcpTool.inputSchema.required.length > 0 ? { required: mcpTool.inputSchema.required } : {}
|
|
47
|
+
},
|
|
48
|
+
serverName
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/mcp/McpClientManager.ts
|
|
53
|
+
var McpStdioConnection = class _McpStdioConnection extends EventEmitter {
|
|
54
|
+
constructor(config, framing) {
|
|
55
|
+
super();
|
|
56
|
+
this.config = config;
|
|
57
|
+
this.framing = framing;
|
|
58
|
+
this.process = null;
|
|
59
|
+
this.lineBuffer = "";
|
|
60
|
+
this.frameBuffer = Buffer.alloc(0);
|
|
61
|
+
this.nextId = 1;
|
|
62
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
63
|
+
}
|
|
64
|
+
static {
|
|
65
|
+
/** Default timeout for RPC requests in milliseconds */
|
|
66
|
+
this.REQUEST_TIMEOUT_MS = 3e4;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Spawns the server process and sets up communication channels.
|
|
70
|
+
*/
|
|
71
|
+
async start() {
|
|
72
|
+
if (!this.config.command) {
|
|
73
|
+
throw new Error(`Cannot start stdio connection: no command specified for server "${this.config.name}"`);
|
|
74
|
+
}
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
try {
|
|
77
|
+
const normalized = normalizeMcpCommandForSpawn(this.config.command, this.config.args);
|
|
78
|
+
this.process = spawn(normalized.command, normalized.args ?? [], {
|
|
79
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
80
|
+
env: {
|
|
81
|
+
...process.env,
|
|
82
|
+
...this.config.env
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
this.process.stdout?.on("data", (data) => {
|
|
86
|
+
this.handleStdoutData(data);
|
|
87
|
+
});
|
|
88
|
+
this.process.stderr?.on("data", (data) => {
|
|
89
|
+
this.emit("stderr", data.toString());
|
|
90
|
+
});
|
|
91
|
+
this.process.on("error", (err) => {
|
|
92
|
+
this.emit("error", err);
|
|
93
|
+
reject(err);
|
|
94
|
+
});
|
|
95
|
+
this.process.on("close", (code) => {
|
|
96
|
+
this.cleanup();
|
|
97
|
+
this.emit("close", code);
|
|
98
|
+
});
|
|
99
|
+
setTimeout(() => resolve(), 100);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Sends a JSON-RPC 2.0 request and waits for the response.
|
|
107
|
+
*/
|
|
108
|
+
async request(method, params) {
|
|
109
|
+
if (!this.process?.stdin?.writable) {
|
|
110
|
+
throw new Error(`MCP server "${this.config.name}" is not connected`);
|
|
111
|
+
}
|
|
112
|
+
const id = this.nextId++;
|
|
113
|
+
const request = {
|
|
114
|
+
jsonrpc: "2.0",
|
|
115
|
+
id,
|
|
116
|
+
method,
|
|
117
|
+
...params !== void 0 ? { params } : {}
|
|
118
|
+
};
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const timer = setTimeout(() => {
|
|
121
|
+
this.pendingRequests.delete(id);
|
|
122
|
+
reject(new Error(`MCP request "${method}" timed out after ${_McpStdioConnection.REQUEST_TIMEOUT_MS}ms`));
|
|
123
|
+
}, _McpStdioConnection.REQUEST_TIMEOUT_MS);
|
|
124
|
+
this.pendingRequests.set(id, { resolve, reject, timer });
|
|
125
|
+
const message = this.serializeMessage(request);
|
|
126
|
+
this.process.stdin.write(message);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sends a JSON-RPC 2.0 notification (no response expected).
|
|
131
|
+
*/
|
|
132
|
+
notify(method, params) {
|
|
133
|
+
if (!this.process?.stdin?.writable) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const notification = {
|
|
137
|
+
jsonrpc: "2.0",
|
|
138
|
+
method,
|
|
139
|
+
...params !== void 0 ? { params } : {}
|
|
140
|
+
};
|
|
141
|
+
const message = this.serializeMessage(notification);
|
|
142
|
+
this.process.stdin.write(message);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Stops the server process and cleans up resources.
|
|
146
|
+
*/
|
|
147
|
+
async stop() {
|
|
148
|
+
if (this.process) {
|
|
149
|
+
this.process.stdin?.end();
|
|
150
|
+
this.process.kill("SIGTERM");
|
|
151
|
+
const forceKillTimer = setTimeout(() => {
|
|
152
|
+
if (this.process && !this.process.killed) {
|
|
153
|
+
this.process.kill("SIGKILL");
|
|
154
|
+
}
|
|
155
|
+
}, 5e3);
|
|
156
|
+
await new Promise((resolve) => {
|
|
157
|
+
if (this.process) {
|
|
158
|
+
this.process.on("close", () => {
|
|
159
|
+
clearTimeout(forceKillTimer);
|
|
160
|
+
resolve();
|
|
161
|
+
});
|
|
162
|
+
} else {
|
|
163
|
+
clearTimeout(forceKillTimer);
|
|
164
|
+
resolve();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
this.cleanup();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parses incoming stdout data as newline-delimited JSON-RPC messages.
|
|
172
|
+
*/
|
|
173
|
+
handleStdoutData(data) {
|
|
174
|
+
if (this.framing === "newline") {
|
|
175
|
+
this.parseLineDelimitedData(data);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
this.parseContentLengthData(data);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Routes incoming JSON-RPC responses to their pending request handlers.
|
|
182
|
+
*/
|
|
183
|
+
handleMessage(message) {
|
|
184
|
+
if (message.id !== void 0 && this.pendingRequests.has(message.id)) {
|
|
185
|
+
const pending = this.pendingRequests.get(message.id);
|
|
186
|
+
this.pendingRequests.delete(message.id);
|
|
187
|
+
clearTimeout(pending.timer);
|
|
188
|
+
if (message.error) {
|
|
189
|
+
pending.reject(
|
|
190
|
+
new Error(`MCP error (${message.error.code}): ${message.error.message}`)
|
|
191
|
+
);
|
|
192
|
+
} else {
|
|
193
|
+
pending.resolve(message.result);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
this.emit("notification", message);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Cleans up all pending requests and resets state.
|
|
201
|
+
*/
|
|
202
|
+
cleanup() {
|
|
203
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
204
|
+
clearTimeout(pending.timer);
|
|
205
|
+
pending.reject(new Error("MCP connection closed"));
|
|
206
|
+
this.pendingRequests.delete(id);
|
|
207
|
+
}
|
|
208
|
+
this.process = null;
|
|
209
|
+
this.lineBuffer = "";
|
|
210
|
+
this.frameBuffer = Buffer.alloc(0);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Serializes JSON-RPC payload according to configured stdio framing mode.
|
|
214
|
+
*/
|
|
215
|
+
serializeMessage(payload) {
|
|
216
|
+
const json = JSON.stringify(payload);
|
|
217
|
+
if (this.framing === "newline") {
|
|
218
|
+
return `${json}
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
const contentLength = Buffer.byteLength(json, "utf8");
|
|
222
|
+
return `Content-Length: ${contentLength}\r
|
|
223
|
+
\r
|
|
224
|
+
${json}`;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Parses newline-delimited JSON-RPC messages (legacy mode).
|
|
228
|
+
*/
|
|
229
|
+
parseLineDelimitedData(data) {
|
|
230
|
+
this.lineBuffer += data.toString();
|
|
231
|
+
let newlineIndex;
|
|
232
|
+
while ((newlineIndex = this.lineBuffer.indexOf("\n")) !== -1) {
|
|
233
|
+
const line = this.lineBuffer.slice(0, newlineIndex).trim();
|
|
234
|
+
this.lineBuffer = this.lineBuffer.slice(newlineIndex + 1);
|
|
235
|
+
if (line.length === 0) continue;
|
|
236
|
+
this.handleJsonPayload(line);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Parses Content-Length framed JSON-RPC messages (MCP stdio spec).
|
|
241
|
+
*/
|
|
242
|
+
parseContentLengthData(data) {
|
|
243
|
+
this.frameBuffer = Buffer.concat([this.frameBuffer, data]);
|
|
244
|
+
while (this.frameBuffer.length > 0) {
|
|
245
|
+
const header = this.findHeaderEnd(this.frameBuffer);
|
|
246
|
+
if (!header) {
|
|
247
|
+
const preview = this.frameBuffer.toString("utf8", 0, Math.min(this.frameBuffer.length, 256));
|
|
248
|
+
const trimmed = preview.trimStart();
|
|
249
|
+
const looksLikeJsonLine = trimmed.startsWith("{") || trimmed.startsWith("[");
|
|
250
|
+
if (looksLikeJsonLine && this.frameBuffer.includes(10)) {
|
|
251
|
+
this.parseLineDelimitedData(this.frameBuffer);
|
|
252
|
+
this.frameBuffer = Buffer.alloc(0);
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const headersText = this.frameBuffer.subarray(0, header.index).toString("utf8");
|
|
257
|
+
const contentLength = this.extractContentLength(headersText);
|
|
258
|
+
if (contentLength === null) {
|
|
259
|
+
const newlineIndex = this.frameBuffer.indexOf("\n");
|
|
260
|
+
if (newlineIndex === -1) return;
|
|
261
|
+
const line = this.frameBuffer.subarray(0, newlineIndex).toString("utf8").trim();
|
|
262
|
+
this.frameBuffer = this.frameBuffer.subarray(newlineIndex + 1);
|
|
263
|
+
if (line.length > 0) {
|
|
264
|
+
this.handleJsonPayload(line);
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const payloadStart = header.index + header.separatorLength;
|
|
269
|
+
const payloadEnd = payloadStart + contentLength;
|
|
270
|
+
if (this.frameBuffer.length < payloadEnd) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const json = this.frameBuffer.subarray(payloadStart, payloadEnd).toString("utf8").trim();
|
|
274
|
+
this.frameBuffer = this.frameBuffer.subarray(payloadEnd);
|
|
275
|
+
if (json.length > 0) {
|
|
276
|
+
this.handleJsonPayload(json);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Finds the end of a stdio frame header block.
|
|
282
|
+
*/
|
|
283
|
+
findHeaderEnd(buffer) {
|
|
284
|
+
const crlfIndex = buffer.indexOf("\r\n\r\n");
|
|
285
|
+
const lfIndex = buffer.indexOf("\n\n");
|
|
286
|
+
if (crlfIndex === -1 && lfIndex === -1) return null;
|
|
287
|
+
if (crlfIndex !== -1 && (lfIndex === -1 || crlfIndex < lfIndex)) {
|
|
288
|
+
return { index: crlfIndex, separatorLength: 4 };
|
|
289
|
+
}
|
|
290
|
+
return { index: lfIndex, separatorLength: 2 };
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Extracts Content-Length header value from frame headers.
|
|
294
|
+
*/
|
|
295
|
+
extractContentLength(headers) {
|
|
296
|
+
const lines = headers.split(/\r?\n/);
|
|
297
|
+
for (const line of lines) {
|
|
298
|
+
const match = /^content-length\s*:\s*(\d+)\s*$/i.exec(line.trim());
|
|
299
|
+
if (!match) continue;
|
|
300
|
+
const parsed = Number.parseInt(match[1], 10);
|
|
301
|
+
if (Number.isNaN(parsed) || parsed < 0) return null;
|
|
302
|
+
return parsed;
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Parses and routes a single JSON-RPC payload.
|
|
308
|
+
*/
|
|
309
|
+
handleJsonPayload(json) {
|
|
310
|
+
try {
|
|
311
|
+
const message = JSON.parse(json);
|
|
312
|
+
this.handleMessage(message);
|
|
313
|
+
} catch {
|
|
314
|
+
this.emit("stderr", `Non-JSON output: ${json}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var McpHttpConnection = class _McpHttpConnection extends EventEmitter {
|
|
319
|
+
constructor(config) {
|
|
320
|
+
super();
|
|
321
|
+
this.config = config;
|
|
322
|
+
this.nextId = 1;
|
|
323
|
+
this.sessionId = null;
|
|
324
|
+
}
|
|
325
|
+
static {
|
|
326
|
+
/** Default timeout for HTTP requests in milliseconds */
|
|
327
|
+
this.REQUEST_TIMEOUT_MS = 3e4;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* No-op for HTTP transport (no persistent process to start).
|
|
331
|
+
*/
|
|
332
|
+
async start() {
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Sends a JSON-RPC 2.0 request via HTTP POST and returns the response.
|
|
336
|
+
*/
|
|
337
|
+
async request(method, params) {
|
|
338
|
+
if (!this.config.url) {
|
|
339
|
+
throw new Error(`MCP HTTP server "${this.config.name}" has no URL configured`);
|
|
340
|
+
}
|
|
341
|
+
const id = this.nextId++;
|
|
342
|
+
const body = {
|
|
343
|
+
jsonrpc: "2.0",
|
|
344
|
+
id,
|
|
345
|
+
method,
|
|
346
|
+
...params !== void 0 ? { params } : {}
|
|
347
|
+
};
|
|
348
|
+
const headers = {
|
|
349
|
+
"Content-Type": "application/json",
|
|
350
|
+
"Accept": "application/json, text/event-stream",
|
|
351
|
+
...this.config.headers ?? {}
|
|
352
|
+
};
|
|
353
|
+
if (this.sessionId) {
|
|
354
|
+
headers["Mcp-Session-Id"] = this.sessionId;
|
|
355
|
+
}
|
|
356
|
+
const controller = new AbortController();
|
|
357
|
+
const timeout = setTimeout(() => controller.abort(), _McpHttpConnection.REQUEST_TIMEOUT_MS);
|
|
358
|
+
try {
|
|
359
|
+
const response = await fetch(this.config.url, {
|
|
360
|
+
method: "POST",
|
|
361
|
+
headers,
|
|
362
|
+
body: JSON.stringify(body),
|
|
363
|
+
signal: controller.signal
|
|
364
|
+
});
|
|
365
|
+
clearTimeout(timeout);
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
const text = await response.text().catch(() => "");
|
|
368
|
+
throw new Error(
|
|
369
|
+
`MCP HTTP request "${method}" failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
const newSessionId = response.headers.get("mcp-session-id");
|
|
373
|
+
if (newSessionId) {
|
|
374
|
+
this.sessionId = newSessionId;
|
|
375
|
+
}
|
|
376
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
377
|
+
if (contentType.includes("text/event-stream")) {
|
|
378
|
+
const text = await response.text();
|
|
379
|
+
return this.parseSSEResponse(text, id);
|
|
380
|
+
}
|
|
381
|
+
const result = await response.json();
|
|
382
|
+
if (result.error) {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`MCP error (${result.error.code}): ${result.error.message}`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
return result.result;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
clearTimeout(timeout);
|
|
390
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
391
|
+
throw new Error(`MCP HTTP request "${method}" timed out after ${_McpHttpConnection.REQUEST_TIMEOUT_MS}ms`);
|
|
392
|
+
}
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Sends a JSON-RPC 2.0 notification via HTTP POST (fire-and-forget).
|
|
398
|
+
*/
|
|
399
|
+
notify(method, params) {
|
|
400
|
+
if (!this.config.url) return;
|
|
401
|
+
const body = {
|
|
402
|
+
jsonrpc: "2.0",
|
|
403
|
+
method,
|
|
404
|
+
...params !== void 0 ? { params } : {}
|
|
405
|
+
};
|
|
406
|
+
const headers = {
|
|
407
|
+
"Content-Type": "application/json",
|
|
408
|
+
...this.config.headers ?? {}
|
|
409
|
+
};
|
|
410
|
+
if (this.sessionId) {
|
|
411
|
+
headers["Mcp-Session-Id"] = this.sessionId;
|
|
412
|
+
}
|
|
413
|
+
fetch(this.config.url, {
|
|
414
|
+
method: "POST",
|
|
415
|
+
headers,
|
|
416
|
+
body: JSON.stringify(body)
|
|
417
|
+
}).catch(() => {
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* No persistent process to stop for HTTP transport.
|
|
422
|
+
*/
|
|
423
|
+
async stop() {
|
|
424
|
+
this.sessionId = null;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Parses an SSE (text/event-stream) response to extract the JSON-RPC result.
|
|
428
|
+
*/
|
|
429
|
+
parseSSEResponse(text, _expectedId) {
|
|
430
|
+
const lines = text.split("\n");
|
|
431
|
+
let lastData = "";
|
|
432
|
+
for (const line of lines) {
|
|
433
|
+
if (line.startsWith("data: ")) {
|
|
434
|
+
lastData = line.slice(6);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (!lastData) {
|
|
438
|
+
throw new Error("No data found in SSE response");
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const parsed = JSON.parse(lastData);
|
|
442
|
+
if (parsed.error) {
|
|
443
|
+
throw new Error(`MCP error (${parsed.error.code}): ${parsed.error.message}`);
|
|
444
|
+
}
|
|
445
|
+
return parsed.result;
|
|
446
|
+
} catch (error) {
|
|
447
|
+
if (error instanceof SyntaxError) {
|
|
448
|
+
throw new Error(`Invalid JSON in SSE response: ${lastData.slice(0, 100)}`);
|
|
449
|
+
}
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var McpClientManager = class {
|
|
455
|
+
constructor() {
|
|
456
|
+
this.servers = /* @__PURE__ */ new Map();
|
|
457
|
+
this.connections = /* @__PURE__ */ new Map();
|
|
458
|
+
}
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Static Helper Methods
|
|
461
|
+
// ============================================================================
|
|
462
|
+
/**
|
|
463
|
+
* Checks if a tool name belongs to MCP (starts with mcp__ prefix).
|
|
464
|
+
* @param toolName - The tool name to check
|
|
465
|
+
* @returns true if the tool is an MCP tool
|
|
466
|
+
*/
|
|
467
|
+
static isMcpTool(toolName) {
|
|
468
|
+
return toolName.startsWith("mcp__");
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Extracts the server name and tool name from a prefixed MCP tool name.
|
|
472
|
+
* The expected format is `mcp__<serverName>__<toolName>`.
|
|
473
|
+
*
|
|
474
|
+
* @param prefixedName - The full prefixed tool name
|
|
475
|
+
* @returns Object with serverName and toolName, or null if invalid format
|
|
476
|
+
*/
|
|
477
|
+
static parseMcpToolName(prefixedName) {
|
|
478
|
+
if (!prefixedName.startsWith("mcp__")) return null;
|
|
479
|
+
const withoutPrefix = prefixedName.slice(5);
|
|
480
|
+
const separatorIndex = withoutPrefix.indexOf("__");
|
|
481
|
+
if (separatorIndex <= 0) return null;
|
|
482
|
+
const serverName = withoutPrefix.slice(0, separatorIndex);
|
|
483
|
+
const toolName = withoutPrefix.slice(separatorIndex + 2);
|
|
484
|
+
if (!serverName || !toolName) return null;
|
|
485
|
+
return { serverName, toolName };
|
|
486
|
+
}
|
|
487
|
+
// ============================================================================
|
|
488
|
+
// Connection Management
|
|
489
|
+
// ============================================================================
|
|
490
|
+
/**
|
|
491
|
+
* Connects to all configured MCP servers.
|
|
492
|
+
* Servers with `autoConnect: false` are skipped.
|
|
493
|
+
* Connection failures for individual servers are caught and logged
|
|
494
|
+
* but do not prevent other servers from connecting.
|
|
495
|
+
*
|
|
496
|
+
* @param configs - Array of server configurations
|
|
497
|
+
*/
|
|
498
|
+
async connectAll(configs) {
|
|
499
|
+
const connectPromises = configs.filter((config) => config.autoConnect !== false).map(async (config) => {
|
|
500
|
+
try {
|
|
501
|
+
await this.connect(config);
|
|
502
|
+
} catch (error) {
|
|
503
|
+
this.servers.set(config.name, {
|
|
504
|
+
config,
|
|
505
|
+
status: "error",
|
|
506
|
+
tools: [],
|
|
507
|
+
error: error instanceof Error ? error.message : String(error)
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
await Promise.all(connectPromises);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Connects to a single MCP server. Performs the MCP initialize handshake,
|
|
515
|
+
* discovers available tools, and registers them.
|
|
516
|
+
*
|
|
517
|
+
* @param config - Server configuration
|
|
518
|
+
* @throws {Error} If the configuration is invalid or connection fails
|
|
519
|
+
*/
|
|
520
|
+
async connect(config) {
|
|
521
|
+
validateMcpServerConfig(config);
|
|
522
|
+
if (this.servers.has(config.name)) {
|
|
523
|
+
await this.disconnect(config.name);
|
|
524
|
+
}
|
|
525
|
+
if (config.transport === "stdio") {
|
|
526
|
+
await this.connectStdio(config);
|
|
527
|
+
} else if (config.transport === "http") {
|
|
528
|
+
await this.connectHttp(config);
|
|
529
|
+
} else if (config.transport === "sse") {
|
|
530
|
+
await this.connectSse(config);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Disconnects from a specific MCP server.
|
|
535
|
+
*
|
|
536
|
+
* @param serverName - Name of the server to disconnect
|
|
537
|
+
* @throws {Error} If the server is not found
|
|
538
|
+
*/
|
|
539
|
+
async disconnect(serverName) {
|
|
540
|
+
const connection = this.connections.get(serverName);
|
|
541
|
+
if (!connection && !this.servers.has(serverName)) {
|
|
542
|
+
throw new Error(`MCP server not found: "${serverName}"`);
|
|
543
|
+
}
|
|
544
|
+
if (connection) {
|
|
545
|
+
await connection.stop();
|
|
546
|
+
this.connections.delete(serverName);
|
|
547
|
+
}
|
|
548
|
+
this.servers.delete(serverName);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Disconnects from all connected MCP servers.
|
|
552
|
+
*/
|
|
553
|
+
async disconnectAll() {
|
|
554
|
+
const disconnectPromises = Array.from(this.servers.keys()).map(
|
|
555
|
+
(name) => this.disconnect(name).catch(() => {
|
|
556
|
+
})
|
|
557
|
+
);
|
|
558
|
+
await Promise.all(disconnectPromises);
|
|
559
|
+
}
|
|
560
|
+
// ============================================================================
|
|
561
|
+
// Tool Discovery
|
|
562
|
+
// ============================================================================
|
|
563
|
+
/**
|
|
564
|
+
* Returns all known servers with their status and tool count.
|
|
565
|
+
* @returns Array of server summaries
|
|
566
|
+
*/
|
|
567
|
+
getServers() {
|
|
568
|
+
const result = [];
|
|
569
|
+
for (const [name, state] of this.servers) {
|
|
570
|
+
result.push({
|
|
571
|
+
name,
|
|
572
|
+
status: state.status,
|
|
573
|
+
toolCount: state.tools.length
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Returns all available tools from all connected servers.
|
|
580
|
+
* @returns Array of tool definitions
|
|
581
|
+
*/
|
|
582
|
+
getAllTools() {
|
|
583
|
+
const allTools = [];
|
|
584
|
+
for (const state of this.servers.values()) {
|
|
585
|
+
if (state.status === "connected") {
|
|
586
|
+
allTools.push(...state.tools);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return allTools;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Returns tools from a specific server.
|
|
593
|
+
* @param serverName - Name of the server
|
|
594
|
+
* @returns Array of tool definitions from that server
|
|
595
|
+
*/
|
|
596
|
+
getToolsForServer(serverName) {
|
|
597
|
+
const state = this.servers.get(serverName);
|
|
598
|
+
if (!state || state.status !== "connected") return [];
|
|
599
|
+
return state.tools;
|
|
600
|
+
}
|
|
601
|
+
// ============================================================================
|
|
602
|
+
// Tool Execution
|
|
603
|
+
// ============================================================================
|
|
604
|
+
/**
|
|
605
|
+
* Calls a tool on a specific MCP server.
|
|
606
|
+
*
|
|
607
|
+
* @param serverName - Name of the server providing the tool
|
|
608
|
+
* @param toolName - Name of the tool (without mcp__ prefix)
|
|
609
|
+
* @param args - Arguments to pass to the tool
|
|
610
|
+
* @returns The tool's result
|
|
611
|
+
* @throws {Error} If the server is not connected or the tool call fails
|
|
612
|
+
*/
|
|
613
|
+
async callTool(serverName, toolName, args) {
|
|
614
|
+
const connection = this.connections.get(serverName);
|
|
615
|
+
const state = this.servers.get(serverName);
|
|
616
|
+
if (!connection || !state || state.status !== "connected") {
|
|
617
|
+
throw new Error(`MCP server not found or not connected: "${serverName}"`);
|
|
618
|
+
}
|
|
619
|
+
const toolArgs = { ...args };
|
|
620
|
+
delete toolArgs.type;
|
|
621
|
+
const result = await connection.request("tools/call", {
|
|
622
|
+
name: toolName,
|
|
623
|
+
arguments: toolArgs
|
|
624
|
+
});
|
|
625
|
+
return result;
|
|
626
|
+
}
|
|
627
|
+
// ============================================================================
|
|
628
|
+
// Server Status
|
|
629
|
+
// ============================================================================
|
|
630
|
+
/**
|
|
631
|
+
* Lists all known servers with their connection status and tool count.
|
|
632
|
+
* @returns Array of server status objects
|
|
633
|
+
*/
|
|
634
|
+
listServers() {
|
|
635
|
+
return Array.from(this.servers.values()).map((state) => ({
|
|
636
|
+
name: state.config.name,
|
|
637
|
+
status: state.status,
|
|
638
|
+
toolCount: state.tools.length,
|
|
639
|
+
error: state.error
|
|
640
|
+
}));
|
|
641
|
+
}
|
|
642
|
+
// ============================================================================
|
|
643
|
+
// Private: Transport-Specific Connection Logic
|
|
644
|
+
// ============================================================================
|
|
645
|
+
/**
|
|
646
|
+
* Connects to an MCP server via stdio transport.
|
|
647
|
+
* Spawns the server process, performs the MCP initialize handshake,
|
|
648
|
+
* and discovers available tools.
|
|
649
|
+
*/
|
|
650
|
+
async connectStdio(config) {
|
|
651
|
+
try {
|
|
652
|
+
const connected = await this.connectStdioWithFallbackFraming(config);
|
|
653
|
+
this.registerConnectedStdioServer(config, connected.connection, connected.tools);
|
|
654
|
+
} catch (error) {
|
|
655
|
+
if (!this.shouldRetryNpxWithIsolatedCache(config, error)) {
|
|
656
|
+
throw error;
|
|
657
|
+
}
|
|
658
|
+
const retryConfig = {
|
|
659
|
+
...config,
|
|
660
|
+
env: buildNpxIsolatedCacheEnv(config.env, config.name)
|
|
661
|
+
};
|
|
662
|
+
try {
|
|
663
|
+
const connected = await this.connectStdioWithFallbackFraming(retryConfig);
|
|
664
|
+
this.registerConnectedStdioServer(config, connected.connection, connected.tools);
|
|
665
|
+
} catch (retryError) {
|
|
666
|
+
const initialMessage = error instanceof Error ? error.message : String(error);
|
|
667
|
+
const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
|
|
668
|
+
throw new Error(`${initialMessage}
|
|
669
|
+
Retry with isolated npm cache failed: ${retryMessage}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
shouldRetryNpxWithIsolatedCache(config, error) {
|
|
674
|
+
if (!config.command || !isNpxCommand(config.command)) {
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
678
|
+
return isRetriableNpxInstallError(message);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Some MCP servers still use newline-delimited JSON-RPC over stdio.
|
|
682
|
+
* Start with Content-Length framing (spec), then fallback to newline when
|
|
683
|
+
* initialize stalls/closes without a successful handshake.
|
|
684
|
+
*/
|
|
685
|
+
shouldRetryWithNewlineFraming(error) {
|
|
686
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
687
|
+
return message.includes('MCP request "initialize" timed out') || message.includes("MCP connection closed before initialization completed") || message.includes("MCP connection closed (server exited with code");
|
|
688
|
+
}
|
|
689
|
+
async connectStdioWithFallbackFraming(config) {
|
|
690
|
+
try {
|
|
691
|
+
return await this.connectStdioWithFraming(config, "content-length");
|
|
692
|
+
} catch (contentLengthError) {
|
|
693
|
+
if (!this.shouldRetryWithNewlineFraming(contentLengthError)) {
|
|
694
|
+
throw contentLengthError;
|
|
695
|
+
}
|
|
696
|
+
try {
|
|
697
|
+
return await this.connectStdioWithFraming(config, "newline");
|
|
698
|
+
} catch (newlineError) {
|
|
699
|
+
const first = contentLengthError instanceof Error ? contentLengthError.message : String(contentLengthError);
|
|
700
|
+
const second = newlineError instanceof Error ? newlineError.message : String(newlineError);
|
|
701
|
+
throw new Error(`${first}
|
|
702
|
+
Retry with newline framing failed: ${second}`);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Tries to establish a stdio MCP connection with a specific framing mode.
|
|
708
|
+
*/
|
|
709
|
+
async connectStdioWithFraming(config, framing) {
|
|
710
|
+
const connection = new McpStdioConnection(config, framing);
|
|
711
|
+
let connectionError = null;
|
|
712
|
+
let stderrOutput = "";
|
|
713
|
+
let closeCode;
|
|
714
|
+
let handshakeComplete = false;
|
|
715
|
+
connection.on("error", (err) => {
|
|
716
|
+
connectionError = err;
|
|
717
|
+
const state = this.servers.get(config.name);
|
|
718
|
+
if (state) {
|
|
719
|
+
state.status = "error";
|
|
720
|
+
state.error = err.message;
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
connection.on("close", (code) => {
|
|
724
|
+
closeCode = code;
|
|
725
|
+
if (handshakeComplete || connectionError) return;
|
|
726
|
+
connectionError = new Error(
|
|
727
|
+
typeof code === "number" ? `MCP server process exited with code ${code}` : "MCP server process exited before completing initialization"
|
|
728
|
+
);
|
|
729
|
+
});
|
|
730
|
+
connection.on("stderr", (data) => {
|
|
731
|
+
stderrOutput += data;
|
|
732
|
+
});
|
|
733
|
+
try {
|
|
734
|
+
await connection.start();
|
|
735
|
+
if (connectionError) {
|
|
736
|
+
throw connectionError;
|
|
737
|
+
}
|
|
738
|
+
await connection.request("initialize", {
|
|
739
|
+
protocolVersion: "2024-11-05",
|
|
740
|
+
capabilities: {
|
|
741
|
+
tools: {}
|
|
742
|
+
},
|
|
743
|
+
clientInfo: {
|
|
744
|
+
name: "autohand",
|
|
745
|
+
version: "1.0.0"
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
connection.notify("notifications/initialized");
|
|
749
|
+
const toolsResult = await connection.request("tools/list", {});
|
|
750
|
+
const tools = (toolsResult?.tools ?? []).map(
|
|
751
|
+
(rawTool) => convertMcpToolToAutohand(rawTool, config.name)
|
|
752
|
+
);
|
|
753
|
+
handshakeComplete = true;
|
|
754
|
+
return { connection, tools };
|
|
755
|
+
} catch (error) {
|
|
756
|
+
await connection.stop().catch(() => {
|
|
757
|
+
});
|
|
758
|
+
let errMsg = error instanceof Error ? error.message : String(error);
|
|
759
|
+
if (errMsg === "MCP connection closed") {
|
|
760
|
+
errMsg = typeof closeCode === "number" ? `MCP connection closed (server exited with code ${closeCode})` : "MCP connection closed before initialization completed";
|
|
761
|
+
}
|
|
762
|
+
const detail = stderrOutput.trim();
|
|
763
|
+
if (detail) {
|
|
764
|
+
const stderrSnippet = detail.length > 500 ? detail.slice(-500) : detail;
|
|
765
|
+
throw new Error(`${errMsg}
|
|
766
|
+
Server stderr (tail): ${stderrSnippet}`);
|
|
767
|
+
}
|
|
768
|
+
throw new Error(errMsg);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Stores connected server state and attaches lifecycle listeners.
|
|
773
|
+
*/
|
|
774
|
+
registerConnectedStdioServer(config, connection, tools) {
|
|
775
|
+
connection.on("close", (code) => {
|
|
776
|
+
const state = this.servers.get(config.name);
|
|
777
|
+
if (state && state.status === "connected") {
|
|
778
|
+
state.status = "error";
|
|
779
|
+
state.error = typeof code === "number" ? `MCP server process exited with code ${code}` : "MCP server disconnected unexpectedly";
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
this.servers.set(config.name, {
|
|
783
|
+
config,
|
|
784
|
+
status: "connected",
|
|
785
|
+
tools
|
|
786
|
+
});
|
|
787
|
+
this.connections.set(config.name, connection);
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Connects to an MCP server via HTTP (Streamable HTTP) transport.
|
|
791
|
+
* Sends JSON-RPC requests as HTTP POST to the configured URL.
|
|
792
|
+
*/
|
|
793
|
+
async connectHttp(config) {
|
|
794
|
+
const connection = new McpHttpConnection(config);
|
|
795
|
+
try {
|
|
796
|
+
await connection.start();
|
|
797
|
+
await connection.request("initialize", {
|
|
798
|
+
protocolVersion: "2024-11-05",
|
|
799
|
+
capabilities: {
|
|
800
|
+
tools: {}
|
|
801
|
+
},
|
|
802
|
+
clientInfo: {
|
|
803
|
+
name: "autohand",
|
|
804
|
+
version: "1.0.0"
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
connection.notify("notifications/initialized");
|
|
808
|
+
const toolsResult = await connection.request("tools/list", {});
|
|
809
|
+
const tools = (toolsResult?.tools ?? []).map(
|
|
810
|
+
(rawTool) => convertMcpToolToAutohand(rawTool, config.name)
|
|
811
|
+
);
|
|
812
|
+
this.servers.set(config.name, {
|
|
813
|
+
config,
|
|
814
|
+
status: "connected",
|
|
815
|
+
tools
|
|
816
|
+
});
|
|
817
|
+
this.connections.set(config.name, connection);
|
|
818
|
+
} catch (error) {
|
|
819
|
+
await connection.stop().catch(() => {
|
|
820
|
+
});
|
|
821
|
+
throw error;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Connects to an MCP server via SSE transport.
|
|
826
|
+
* Currently a placeholder -- SSE transport requires an HTTP client
|
|
827
|
+
* with SSE support which will be added in a future iteration.
|
|
828
|
+
*/
|
|
829
|
+
async connectSse(config) {
|
|
830
|
+
this.servers.set(config.name, {
|
|
831
|
+
config,
|
|
832
|
+
status: "error",
|
|
833
|
+
tools: [],
|
|
834
|
+
error: "SSE transport is not yet implemented. Use stdio or http transport instead."
|
|
835
|
+
});
|
|
836
|
+
throw new Error(
|
|
837
|
+
`SSE transport for MCP server "${config.name}" is not yet implemented. Use stdio or http transport instead.`
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
export {
|
|
843
|
+
McpClientManager
|
|
844
|
+
};
|