autohand-cli 0.7.14 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-IWVPRKFF.cjs +466 -0
- package/dist/ImportWizard-KASGQPUY.js +466 -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-2GO5PQ6M.cjs +11 -0
- package/dist/{PermissionManager-U5OMGR3L.js → PermissionManager-K7UWSNB6.js} +4 -3
- package/dist/ProjectProfiler-UMJJSOCE.js +194 -0
- package/dist/ProjectProfiler-ZDWR2ODG.cjs +194 -0
- package/dist/ProviderFactory-EFFQBRQ6.cjs +9 -0
- package/dist/ProviderFactory-S3LWTQQC.js +9 -0
- package/dist/SessionManager-FEUAU3ZJ.cjs +10 -0
- package/dist/SessionManager-IKWAK2PI.js +10 -0
- package/dist/SkillsRegistry-GDEGFP6O.cjs +9 -0
- package/dist/SkillsRegistry-SI5RUHQ4.js +9 -0
- package/dist/SubAgent-I75HELJG.js +11 -0
- package/dist/SubAgent-K3QP6WHC.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-B2AGTV6N.js +12 -0
- package/dist/about-V2HWEZZO.cjs +12 -0
- package/dist/actionExecutor-6XCVL2SJ.js +19 -0
- package/dist/actionExecutor-YRUJNB5G.cjs +19 -0
- package/dist/add-dir-7FBQ5IFV.js +10 -0
- package/dist/add-dir-ALBSYRV3.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-FCGEWTA3.cjs +12 -0
- package/dist/agents-FENGUSJD.js +12 -0
- package/dist/agents-new-FU3O55CO.js +14 -0
- package/dist/agents-new-SAFTJ7TK.cjs +14 -0
- package/dist/assets/icon.png +0 -0
- package/dist/automode-CYLGXQ4A.cjs +10 -0
- package/dist/automode-O7G3DUYN.js +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-24QIWILL.js +51 -0
- package/dist/{chunk-MYNHJHDZ.js → chunk-2AA5MFES.js} +1 -1
- package/dist/{chunk-KWRUQRXR.js → chunk-2ELK5DMH.js} +44 -10
- package/dist/chunk-2JYIR3EC.cjs +1176 -0
- package/dist/{chunk-CRQKDBLD.js → chunk-2RIAPTET.js} +90 -66
- package/dist/{chunk-TSY7JHIV.cjs → chunk-33A755XB.cjs} +2 -2
- package/dist/chunk-3OEDGIFW.js +42 -0
- package/dist/{chunk-P5VDZ6PV.js → chunk-3PDTTAKJ.js} +1 -1
- package/dist/{chunk-ULMPJUJW.cjs → chunk-3WCOFXQS.cjs} +23 -23
- package/dist/{chunk-PDKNHU5G.cjs → chunk-4HKTYHNL.cjs} +22 -16
- package/dist/{chunk-Z4J4W6YQ.cjs → chunk-4JNNTOGF.cjs} +2 -48
- package/dist/chunk-55B6SBHK.js +260 -0
- package/dist/chunk-5DDDUUBM.cjs +29 -0
- package/dist/{chunk-TQB222ZB.js → chunk-5EIEWVYX.js} +2 -2
- package/dist/{chunk-SMHY3Q7B.cjs → chunk-5GGX6WNY.cjs} +54 -22
- package/dist/{chunk-3S4DEIJP.cjs → chunk-5IXII4HX.cjs} +2 -2
- package/dist/{chunk-3KBBARKO.js → chunk-5OBNULPU.js} +85 -28
- package/dist/{chunk-VVBBEYTH.cjs → chunk-5YJG6H6P.cjs} +10 -10
- package/dist/{chunk-PKOAXQKW.cjs → chunk-63WXWFDI.cjs} +11 -11
- package/dist/{chunk-DSKVMFRM.cjs → chunk-643VRA5S.cjs} +12 -4
- package/dist/{chunk-L5ZFPWHY.js → chunk-6OYHF6MF.js} +12 -4
- package/dist/chunk-7GDVDSNI.js +1176 -0
- package/dist/chunk-7QEE6SW6.cjs +260 -0
- package/dist/chunk-7UOUW76C.js +603 -0
- package/dist/{chunk-SZP4ULM5.cjs → chunk-AFN7LH5N.cjs} +17 -17
- package/dist/chunk-AHD5JJ6F.cjs +78 -0
- package/dist/{chunk-WLTVF77A.js → chunk-ALYU6VTM.js} +1 -1
- package/dist/{chunk-BRXIEKJ3.cjs → chunk-AMT2UZBI.cjs} +5 -5
- package/dist/{chunk-SFNT5DYE.cjs → chunk-BT35E7NE.cjs} +4 -4
- package/dist/{chunk-NUHYCFHW.cjs → chunk-BVKXEQVG.cjs} +54 -65
- package/dist/chunk-CDMGQR4L.cjs +4470 -0
- package/dist/chunk-CNBKZEX5.cjs +109 -0
- package/dist/{chunk-GD4AFYJ3.js → chunk-CVVEYUFR.js} +1 -1
- package/dist/chunk-CWALFEGU.js +58 -0
- package/dist/{chunk-MTALRU7R.cjs → chunk-D3YCFT5O.cjs} +3 -3
- package/dist/{chunk-CH4SPVFD.cjs → chunk-D6VG7B5X.cjs} +9 -3
- package/dist/{chunk-TOTDRAWG.js → chunk-DH7DKCUL.js} +1 -1
- package/dist/{chunk-RFNCTE4V.cjs → chunk-DLG43ZJ7.cjs} +2 -2
- package/dist/chunk-DN573ME7.cjs +1675 -0
- package/dist/{chunk-63BXZQZW.js → chunk-E23CMMNJ.js} +20 -4
- package/dist/{chunk-4HA7IHLJ.cjs → chunk-EEGK5DYE.cjs} +32 -16
- package/dist/{chunk-DTFR3WD6.js → chunk-EF4LKUQY.js} +1 -1
- package/dist/{chunk-PWLLLJHU.js → chunk-EGFT4PGW.js} +3 -1
- package/dist/{chunk-S47TCZDL.js → chunk-EIU7K7CM.js} +7 -7
- package/dist/{chunk-BISFR6ZL.js → chunk-EPNYD4NV.js} +1 -1
- package/dist/chunk-EZMINVLU.js +123 -0
- package/dist/{chunk-LYMTYC67.js → chunk-F23EVNJU.js} +2 -2
- package/dist/chunk-FHK7UDOJ.cjs +42 -0
- package/dist/chunk-FMB3TSWP.cjs +218 -0
- package/dist/{chunk-XBUMKEFN.cjs → chunk-FPAE6ORV.cjs} +91 -34
- package/dist/{chunk-DEAEO7RI.js → chunk-FYZ67R4R.js} +1 -1
- package/dist/{chunk-6SHHB2VD.js → chunk-G7SZIOHF.js} +2 -2
- package/dist/{chunk-FB6JWNJS.js → chunk-GBHDROGL.js} +54 -65
- package/dist/chunk-GCHELXLO.js +131 -0
- package/dist/{chunk-XPOHYKR3.js → chunk-GHSBZ3YB.js} +2 -2
- package/dist/chunk-GLBAF54O.js +218 -0
- package/dist/chunk-GO3N7LRW.cjs +131 -0
- package/dist/{chunk-Y2ZSH3YF.cjs → chunk-H6ZGZEBG.cjs} +57 -23
- package/dist/{chunk-DSCQPWUB.cjs → chunk-HA7OAVOB.cjs} +15 -15
- package/dist/{chunk-NMWEDN4Z.js → chunk-HFMLWH7B.js} +108 -0
- package/dist/{chunk-D2XFTCRP.js → chunk-HQ7YZKXE.js} +1 -1
- package/dist/{chunk-L42HTMMR.cjs → chunk-HTLINWX6.cjs} +2 -2
- package/dist/chunk-IETRBBMP.cjs +603 -0
- package/dist/chunk-IQ5RXU6O.js +1675 -0
- package/dist/{chunk-GVZPIQWB.js → chunk-ITB3FS72.js} +11 -5
- package/dist/{chunk-B6EBHCK2.cjs → chunk-IUMJYXBX.cjs} +6 -6
- package/dist/{chunk-ZBIBLOZL.js → chunk-IVM5F2AE.js} +500 -317
- package/dist/{chunk-GRSVQ5YZ.js → chunk-IWVQ2EW3.js} +44 -12
- package/dist/chunk-JJWCQLOU.cjs +59 -0
- package/dist/{chunk-KXAAEROY.js → chunk-JMFDD7IZ.js} +2 -2
- package/dist/chunk-JSBRDJBE.js +30 -0
- package/dist/chunk-LJFUXC56.cjs +123 -0
- package/dist/chunk-LL3PQ2U6.js +4470 -0
- package/dist/chunk-LQ4LQQG6.cjs +27 -0
- package/dist/chunk-LQGVEP3E.js +109 -0
- package/dist/{chunk-425MT6Y5.cjs → chunk-LVE6Z5SL.cjs} +9 -9
- package/dist/{chunk-XL77XYI2.cjs → chunk-LXDOQTXQ.cjs} +4 -4
- package/dist/{chunk-BG4OQUKP.js → chunk-MBBY4ZIK.js} +1 -1
- package/dist/{chunk-ZXIQCYYV.cjs → chunk-MGMXR67S.cjs} +9 -9
- package/dist/{chunk-FHUNAB2K.cjs → chunk-MHLE6AVN.cjs} +33 -6
- package/dist/chunk-MHSDHPC4.cjs +58 -0
- package/dist/chunk-MUBW5UDH.cjs +55 -0
- package/dist/{chunk-MNSTWHK3.cjs → chunk-MVWOQBCC.cjs} +11 -11
- package/dist/chunk-N254NRHT.cjs +30 -0
- package/dist/{chunk-SRLY7K6J.js → chunk-OBLIITWJ.js} +2 -2
- package/dist/{chunk-SIGWDEPS.cjs → chunk-OI7OIGNB.cjs} +10 -10
- package/dist/{chunk-V7YTCNMN.cjs → chunk-OPR34VHL.cjs} +5 -5
- package/dist/chunk-OUHQZFN4.js +78 -0
- package/dist/{chunk-HMRDNRTH.js → chunk-PEC45WYS.js} +2 -2
- package/dist/{chunk-OSUWEUZE.js → chunk-PUOE5BCN.js} +1 -1
- package/dist/chunk-Q2VYSHWU.js +59 -0
- package/dist/chunk-Q3MJ6CYS.cjs +193 -0
- package/dist/{chunk-QRGPAUST.js → chunk-Q5RN7RXC.js} +2 -2
- package/dist/{chunk-43XS26AQ.cjs → chunk-Q5RX3XGB.cjs} +4 -4
- package/dist/chunk-QCLYBIMM.cjs +51 -0
- package/dist/chunk-QMAKTSZB.cjs +48 -0
- package/dist/chunk-QT2VZNFA.js +29 -0
- package/dist/{chunk-3XJD56Z4.js → chunk-QUFAULH7.js} +9 -3
- 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-NMGF2KUN.js → chunk-RO46YAPI.js} +1 -1
- package/dist/{chunk-2U5HFVRO.cjs → chunk-RVUQKMXX.cjs} +108 -0
- package/dist/chunk-S52YW5ZQ.js +844 -0
- package/dist/{chunk-ZLOTP56B.cjs → chunk-S6BDWWUG.cjs} +5 -5
- package/dist/{chunk-6DWXHBAY.js → chunk-SAHBLB3E.js} +222 -127
- package/dist/chunk-SALLHB2I.js +27 -0
- package/dist/{chunk-GIZL57FE.cjs → chunk-SEKD5FH3.cjs} +3 -1
- package/dist/{chunk-DZHR34H6.cjs → chunk-SHFA46CS.cjs} +8 -8
- package/dist/{chunk-MILZEEUV.js → chunk-SIHRD34Z.js} +2 -2
- package/dist/{chunk-BPTBKO7D.js → chunk-SO3QQJAZ.js} +216 -36
- package/dist/{chunk-HSPWX4Z2.cjs → chunk-SRQW3B6J.cjs} +223 -43
- package/dist/{chunk-MY3TZER2.js → chunk-T63AMO6H.js} +1 -1
- package/dist/{chunk-X765A7J5.js → chunk-TERCG25S.js} +1 -1
- package/dist/{chunk-WOGJXDBU.cjs → chunk-TFSRRZWP.cjs} +3 -3
- package/dist/{chunk-RRZS5A53.js → chunk-TQHOVHRS.js} +1 -1
- package/dist/{chunk-JHOQABEF.js → chunk-TWEKBHUO.js} +5 -5
- package/dist/chunk-U3WDY42C.cjs +42 -0
- package/dist/{chunk-CKN2BLHK.cjs → chunk-UBS46QL3.cjs} +2 -2
- package/dist/{chunk-H3GBSPK5.js → chunk-UGTFKUW4.js} +14 -6
- package/dist/chunk-UJTCTTUF.cjs +271 -0
- package/dist/{chunk-RUZB43HU.cjs → chunk-UTI6ZQEY.cjs} +22 -14
- package/dist/{chunk-OLG7LZBD.js → chunk-VG34MG2U.js} +1 -1
- package/dist/{chunk-ZKZRFH37.cjs → chunk-VJYPP6PP.cjs} +6 -6
- package/dist/{chunk-YHGTBPEC.js → chunk-VNQ5GL34.js} +1 -1
- package/dist/{chunk-XDVG3NM4.js → chunk-W3X6PAC7.js} +2 -48
- package/dist/{chunk-FK2DVRPJ.js → chunk-WFUUXADU.js} +2 -2
- package/dist/{chunk-R5OO7MEB.cjs → chunk-WGTJOIB7.cjs} +22 -22
- package/dist/{chunk-VHBUKGRG.js → chunk-WJDPVW7T.js} +4 -4
- 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-WTNBX2JO.js +271 -0
- package/dist/chunk-XAV24VYN.js +48 -0
- package/dist/chunk-XDLH4EDL.cjs +118 -0
- package/dist/{chunk-U7CZFKPL.cjs → chunk-XMNHZRUB.cjs} +2 -2
- package/dist/chunk-XUDSXGGV.cjs +1822 -0
- package/dist/{chunk-WQUQ5JMM.js → chunk-XWASJ2QL.js} +4 -4
- package/dist/chunk-Y2SXUCNJ.js +55 -0
- package/dist/{chunk-AIH6GUGB.cjs → chunk-YDCDGTK6.cjs} +5 -5
- package/dist/chunk-YFXTE422.cjs +92 -0
- package/dist/chunk-YKS55CMT.js +1822 -0
- package/dist/{chunk-KC5FPUOF.cjs → chunk-YRLYSQEQ.cjs} +2 -2
- package/dist/{chunk-JWPI6O5Z.js → chunk-YS34SVY5.js} +31 -4
- package/dist/{chunk-FEVHH525.cjs → chunk-YYB42DCU.cjs} +4 -4
- package/dist/chunk-ZK6HOR62.js +92 -0
- package/dist/{chunk-BHV7CBNT.js → chunk-ZSE42BRE.js} +1 -1
- package/dist/clear-ES5WCZRF.cjs +12 -0
- package/dist/clear-J7XS6T5W.js +12 -0
- package/dist/completion-XQTDTJLK.cjs +14 -0
- package/dist/completion-XR6ZONJQ.js +14 -0
- package/dist/config-2TB3A55J.js +18 -0
- package/dist/config-RDMVIV26.cjs +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-EWAYH353.cjs +12 -0
- package/dist/export-ZWA6XGVS.js +12 -0
- package/dist/extractSessionMemories-SDW2MVBQ.cjs +7 -0
- package/dist/extractSessionMemories-V7K42ZHW.js +7 -0
- package/dist/feedback-5RV6ODW4.js +15 -0
- package/dist/feedback-ZPITHFJR.cjs +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-I5GRCA3S.js} +3 -2
- package/dist/help-X52PZM24.cjs +12 -0
- package/dist/history-4WIOZ4TW.cjs +14 -0
- package/dist/{history-AV4XBFRK.js → history-OCHJBJW7.js} +3 -2
- package/dist/hooks-IAVTXUAI.cjs +13 -0
- package/dist/hooks-YF6HL23E.js +13 -0
- package/dist/{i18n-BSAPXM56.js → i18n-KHBXUALK.js} +2 -1
- package/dist/i18n-MVQIAZWS.cjs +33 -0
- package/dist/ide-4R3BEBIS.js +12 -0
- package/dist/ide-C7WSPQTR.cjs +12 -0
- package/dist/import-2ICSKDL7.cjs +10 -0
- package/dist/import-EAAX5HJR.js +170 -0
- package/dist/import-KRVVYJCZ.js +10 -0
- package/dist/import-PQJPNXA4.cjs +170 -0
- package/dist/index.cjs +7503 -11251
- package/dist/index.js +8735 -12483
- package/dist/init-6K3NRDOM.js +10 -0
- package/dist/init-AOUGGITS.cjs +10 -0
- package/dist/language-Q7YFDVSR.cjs +18 -0
- package/dist/language-Y6ZC7LET.js +18 -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-6OAH2NEH.cjs +20 -0
- package/dist/login-DL3377MD.js +20 -0
- package/dist/logout-ELQBUMTU.cjs +18 -0
- package/dist/logout-TLYA5W45.js +18 -0
- package/dist/mcp-BHOIBYUB.js +18 -0
- package/dist/mcp-TNUEXR5T.cjs +18 -0
- package/dist/{mcp-install-2KVKRAMQ.cjs → mcp-install-GROTZHAW.cjs} +26 -14
- package/dist/{mcp-install-77UXRN6R.js → mcp-install-KSADVDBE.js} +21 -9
- package/dist/memory-6DRFA43C.js +10 -0
- package/dist/memory-IORZE6WF.cjs +10 -0
- package/dist/message-JUBOK2VU.js +9 -0
- package/dist/message-ZJ5AYAMT.cjs +9 -0
- package/dist/model-CJPSPGIC.cjs +10 -0
- package/dist/model-MQXC56ES.js +10 -0
- package/dist/new-7D2B7IWM.cjs +12 -0
- package/dist/new-7VYM36RC.js +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-MM77OSFO.js +13 -0
- package/dist/permissions-W2F62DJ6.cjs +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-7D2RDGTD.cjs +10 -0
- package/dist/quit-PKBSEJOL.js +10 -0
- package/dist/registry-A5XLMQVC.cjs +1828 -0
- package/dist/registry-WQLWHOLY.js +1828 -0
- package/dist/resume-FBKXSDOA.js +13 -0
- package/dist/resume-KLPDYPWQ.cjs +13 -0
- package/dist/search-7RNYTCNO.js +17 -0
- package/dist/search-UESMQZC3.cjs +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-TSSUFWIJ.cjs +10 -0
- package/dist/sessions-WAXBUQTU.js +10 -0
- package/dist/settings-D6JXX5RG.js +30 -0
- package/dist/settings-RKYGXKDG.cjs +30 -0
- package/dist/share-GLX4YHS4.cjs +14 -0
- package/dist/share-U2M2KBFJ.js +14 -0
- package/dist/skills-63QLZMUO.cjs +14 -0
- package/dist/{skills-LJZA6PVJ.js → skills-BAMMXP3Q.js} +3 -2
- package/dist/{skills-install-MQINL3EC.js → skills-install-QNQWC2MV.js} +99 -28
- package/dist/{skills-install-IKJZN4G2.cjs → skills-install-UMK5H3SO.cjs} +107 -36
- package/dist/skills-new-NYKNHJHV.cjs +15 -0
- package/dist/skills-new-NZFGFKML.js +15 -0
- package/dist/slashCommands-EJ23C3Z4.cjs +69 -0
- package/dist/slashCommands-JQIL4EWX.js +69 -0
- package/dist/status-BKC7GBNQ.js +11 -0
- package/dist/status-FU3CPJWQ.cjs +11 -0
- package/dist/sync-3IEIHXIP.cjs +18 -0
- package/dist/sync-7JMZVEQD.cjs +40 -0
- package/dist/{sync-EXYX7HXW.js → sync-KWX67OUN.js} +3 -2
- package/dist/sync-YVPFT7SL.js +18 -0
- package/dist/tasks-5FPBIFLC.js +9 -0
- package/dist/tasks-TXGKGNH6.cjs +9 -0
- package/dist/team-GVK5L73L.cjs +9 -0
- package/dist/team-RWIKCLTG.js +9 -0
- package/dist/teammate-3C4MLRGH.js +139 -0
- package/dist/teammate-7C3UDQSH.cjs +139 -0
- package/dist/theme-A2CEHI7W.js +18 -0
- package/dist/theme-LNOQOVR4.cjs +18 -0
- package/dist/ui/questionModal.cjs +7 -25
- package/dist/ui/questionModal.js +6 -24
- package/dist/undo-F2IZJQUV.js +10 -0
- package/dist/undo-QEV42XLU.cjs +10 -0
- package/dist/update-TVAJMMBC.js +82 -0
- package/dist/update-Z6BIIQDC.cjs +82 -0
- package/package.json +9 -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-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,1828 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AUTOHAND_PATHS
|
|
3
|
+
} from "./chunk-EGFT4PGW.js";
|
|
4
|
+
import "./chunk-JSBRDJBE.js";
|
|
5
|
+
|
|
6
|
+
// src/import/importers/ClaudeImporter.ts
|
|
7
|
+
import path2 from "path";
|
|
8
|
+
import fse2 from "fs-extra";
|
|
9
|
+
|
|
10
|
+
// src/import/importers/BaseImporter.ts
|
|
11
|
+
import os from "os";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import crypto from "crypto";
|
|
14
|
+
import fse from "fs-extra";
|
|
15
|
+
var BaseImporter = class {
|
|
16
|
+
// ---------------------------------------------------------------
|
|
17
|
+
// Resolved home path
|
|
18
|
+
// ---------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Expands a `~/` prefix to the user's home directory.
|
|
21
|
+
* Returns absolute paths unchanged.
|
|
22
|
+
*/
|
|
23
|
+
get resolvedHomePath() {
|
|
24
|
+
if (this.homePath.startsWith("~/") || this.homePath === "~") {
|
|
25
|
+
return path.join(os.homedir(), this.homePath.slice(2));
|
|
26
|
+
}
|
|
27
|
+
return this.homePath;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------
|
|
30
|
+
// Detection
|
|
31
|
+
// ---------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Checks whether this agent's data directory exists on disk.
|
|
34
|
+
*/
|
|
35
|
+
async detect() {
|
|
36
|
+
return fse.pathExists(this.resolvedHomePath);
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------
|
|
39
|
+
// JSONL reader
|
|
40
|
+
// ---------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Reads a JSONL file and returns an array of parsed records.
|
|
43
|
+
* Blank lines and malformed JSON lines are silently skipped.
|
|
44
|
+
*/
|
|
45
|
+
async readJsonlFile(filePath) {
|
|
46
|
+
const content = await fse.readFile(filePath, "utf-8");
|
|
47
|
+
const records = [];
|
|
48
|
+
for (const line of content.split("\n")) {
|
|
49
|
+
const trimmed = line.trim();
|
|
50
|
+
if (!trimmed) continue;
|
|
51
|
+
try {
|
|
52
|
+
records.push(JSON.parse(trimmed));
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return records;
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------
|
|
59
|
+
// Retry with exponential backoff
|
|
60
|
+
// ---------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Retries `fn` up to `maxRetries` times with exponential backoff.
|
|
63
|
+
* Throws the last error if all retries are exhausted.
|
|
64
|
+
*/
|
|
65
|
+
async withRetry(fn, maxRetries = 3, baseDelay = 1e3) {
|
|
66
|
+
let lastError;
|
|
67
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
68
|
+
try {
|
|
69
|
+
return await fn();
|
|
70
|
+
} catch (err) {
|
|
71
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
72
|
+
if (attempt < maxRetries - 1) {
|
|
73
|
+
await this.delay(baseDelay * Math.pow(2, attempt));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw lastError;
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------
|
|
80
|
+
// Session writing
|
|
81
|
+
// ---------------------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* Creates a new Autohand session directory with metadata and conversation data.
|
|
84
|
+
* Returns the generated session ID, or `null` if the session was already imported
|
|
85
|
+
* (deduplication by source + originalId).
|
|
86
|
+
*/
|
|
87
|
+
async writeAutohandSession(opts) {
|
|
88
|
+
if (await this.isAlreadyImported(opts.source, opts.originalId)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const timestamp = Date.now();
|
|
92
|
+
const uuid = crypto.randomUUID();
|
|
93
|
+
const sessionId = `${uuid}-${timestamp}`;
|
|
94
|
+
const sessionDir = path.join(AUTOHAND_PATHS.sessions, sessionId);
|
|
95
|
+
await fse.ensureDir(sessionDir);
|
|
96
|
+
const metadata = {
|
|
97
|
+
sessionId,
|
|
98
|
+
createdAt: opts.createdAt,
|
|
99
|
+
lastActiveAt: opts.closedAt ?? opts.createdAt,
|
|
100
|
+
closedAt: opts.closedAt,
|
|
101
|
+
projectPath: opts.projectPath,
|
|
102
|
+
projectName: opts.projectName,
|
|
103
|
+
model: opts.model,
|
|
104
|
+
messageCount: opts.messages.length,
|
|
105
|
+
summary: opts.summary,
|
|
106
|
+
status: opts.status ?? "completed",
|
|
107
|
+
importedFrom: {
|
|
108
|
+
source: opts.source,
|
|
109
|
+
originalId: opts.originalId,
|
|
110
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
await fse.writeJson(path.join(sessionDir, "metadata.json"), metadata, { spaces: 2 });
|
|
114
|
+
const jsonl = opts.messages.map((msg) => JSON.stringify(msg)).join("\n") + "\n";
|
|
115
|
+
await fse.writeFile(path.join(sessionDir, "conversation.jsonl"), jsonl, "utf-8");
|
|
116
|
+
await this.updateSessionIndex(metadata);
|
|
117
|
+
return sessionId;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Checks whether a session from `source` with `originalId` was already imported.
|
|
121
|
+
* Uses the session index for O(n) lookup with `importedFrom` field.
|
|
122
|
+
*/
|
|
123
|
+
async isAlreadyImported(source, originalId) {
|
|
124
|
+
const indexPath = path.join(AUTOHAND_PATHS.sessions, "index.json");
|
|
125
|
+
if (!await fse.pathExists(indexPath)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const loaded = await fse.readJson(indexPath);
|
|
130
|
+
if (!loaded || !Array.isArray(loaded.sessions)) return false;
|
|
131
|
+
return loaded.sessions.some(
|
|
132
|
+
(s) => s.importedFrom?.source === source && s.importedFrom?.originalId === originalId
|
|
133
|
+
);
|
|
134
|
+
} catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// ---------------------------------------------------------------
|
|
139
|
+
// Session index management
|
|
140
|
+
// ---------------------------------------------------------------
|
|
141
|
+
/**
|
|
142
|
+
* Adds a session entry to `~/.autohand/sessions/index.json`.
|
|
143
|
+
* Creates the file if it does not exist.
|
|
144
|
+
*/
|
|
145
|
+
async updateSessionIndex(metadata) {
|
|
146
|
+
const indexPath = path.join(AUTOHAND_PATHS.sessions, "index.json");
|
|
147
|
+
let index = { sessions: [], byProject: {} };
|
|
148
|
+
if (await fse.pathExists(indexPath)) {
|
|
149
|
+
try {
|
|
150
|
+
const loaded = await fse.readJson(indexPath);
|
|
151
|
+
if (loaded && typeof loaded === "object" && Array.isArray(loaded.sessions) && loaded.byProject && typeof loaded.byProject === "object") {
|
|
152
|
+
index = loaded;
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const entry = {
|
|
158
|
+
id: metadata.sessionId,
|
|
159
|
+
projectPath: metadata.projectPath,
|
|
160
|
+
createdAt: metadata.createdAt,
|
|
161
|
+
summary: metadata.summary
|
|
162
|
+
};
|
|
163
|
+
if (metadata.importedFrom) {
|
|
164
|
+
entry.importedFrom = {
|
|
165
|
+
source: metadata.importedFrom.source,
|
|
166
|
+
originalId: metadata.importedFrom.originalId
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
index.sessions.push(entry);
|
|
170
|
+
if (!index.byProject[metadata.projectPath]) {
|
|
171
|
+
index.byProject[metadata.projectPath] = [];
|
|
172
|
+
}
|
|
173
|
+
index.byProject[metadata.projectPath].push(metadata.sessionId);
|
|
174
|
+
await fse.ensureDir(AUTOHAND_PATHS.sessions);
|
|
175
|
+
await fse.writeJson(indexPath, index, { spaces: 2 });
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------
|
|
178
|
+
// Utility
|
|
179
|
+
// ---------------------------------------------------------------
|
|
180
|
+
/**
|
|
181
|
+
* Safely read and parse a JSON file with pre-validation.
|
|
182
|
+
* Returns the parsed data, or throws with a descriptive error message.
|
|
183
|
+
* Handles empty files, corrupted JSON, and non-object content gracefully.
|
|
184
|
+
*/
|
|
185
|
+
async safeReadJson(filePath) {
|
|
186
|
+
const content = await fse.readFile(filePath, "utf-8");
|
|
187
|
+
if (!content.trim()) {
|
|
188
|
+
throw new Error(`File is empty: ${path.basename(filePath)}`);
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const parsed = JSON.parse(content);
|
|
192
|
+
return parsed;
|
|
193
|
+
} catch (err) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Invalid JSON in ${path.basename(filePath)}: ${err instanceof Error ? err.message : String(err)}`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Simple promise-based delay.
|
|
201
|
+
*/
|
|
202
|
+
delay(ms) {
|
|
203
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// src/import/importers/ClaudeImporter.ts
|
|
208
|
+
var ClaudeImporter = class extends BaseImporter {
|
|
209
|
+
constructor() {
|
|
210
|
+
super(...arguments);
|
|
211
|
+
this.name = "claude";
|
|
212
|
+
this.displayName = "Claude Code";
|
|
213
|
+
this.homePath = "~/.claude";
|
|
214
|
+
}
|
|
215
|
+
// ---------------------------------------------------------------
|
|
216
|
+
// scan()
|
|
217
|
+
// ---------------------------------------------------------------
|
|
218
|
+
async scan() {
|
|
219
|
+
const available = /* @__PURE__ */ new Map();
|
|
220
|
+
const home = this.resolvedHomePath;
|
|
221
|
+
if (!await fse2.pathExists(home)) {
|
|
222
|
+
return { source: this.name, available };
|
|
223
|
+
}
|
|
224
|
+
const projectsDir = path2.join(home, "projects");
|
|
225
|
+
let sessionCount = 0;
|
|
226
|
+
let memoryCount = 0;
|
|
227
|
+
if (await fse2.pathExists(projectsDir)) {
|
|
228
|
+
const entries = await fse2.readdir(projectsDir, { withFileTypes: true });
|
|
229
|
+
const projectDirs = entries.filter((e) => e.isDirectory());
|
|
230
|
+
for (const dir of projectDirs) {
|
|
231
|
+
const projectDir = path2.join(projectsDir, dir.name);
|
|
232
|
+
const projectEntries = await fse2.readdir(projectDir, { withFileTypes: true });
|
|
233
|
+
const jsonlFiles = projectEntries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
234
|
+
sessionCount += jsonlFiles.length;
|
|
235
|
+
const hasMemoryDir = await fse2.pathExists(path2.join(projectDir, "memory"));
|
|
236
|
+
const hasClaudeMd = await fse2.pathExists(path2.join(projectDir, "CLAUDE.md"));
|
|
237
|
+
if (hasMemoryDir || hasClaudeMd) {
|
|
238
|
+
memoryCount++;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (sessionCount > 0) {
|
|
243
|
+
available.set("sessions", {
|
|
244
|
+
count: sessionCount,
|
|
245
|
+
description: `${sessionCount} session file${sessionCount !== 1 ? "s" : ""} across project directories`
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const settingsPath = path2.join(home, "settings.json");
|
|
249
|
+
if (await fse2.pathExists(settingsPath)) {
|
|
250
|
+
available.set("settings", { count: 1, description: "Claude Code settings.json" });
|
|
251
|
+
}
|
|
252
|
+
const skillsDir = path2.join(home, "skills");
|
|
253
|
+
if (await fse2.pathExists(skillsDir)) {
|
|
254
|
+
const skillEntries = await fse2.readdir(skillsDir, { withFileTypes: true });
|
|
255
|
+
const skillFiles = skillEntries.filter((e) => e.isFile());
|
|
256
|
+
if (skillFiles.length > 0) {
|
|
257
|
+
available.set("skills", {
|
|
258
|
+
count: skillFiles.length,
|
|
259
|
+
description: `${skillFiles.length} skill file${skillFiles.length !== 1 ? "s" : ""}`
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (memoryCount > 0) {
|
|
264
|
+
available.set("memory", {
|
|
265
|
+
count: memoryCount,
|
|
266
|
+
description: `${memoryCount} project${memoryCount !== 1 ? "s" : ""} with memory data`
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return { source: this.name, available };
|
|
270
|
+
}
|
|
271
|
+
// ---------------------------------------------------------------
|
|
272
|
+
// import()
|
|
273
|
+
// ---------------------------------------------------------------
|
|
274
|
+
async import(categories, onProgress) {
|
|
275
|
+
const start = Date.now();
|
|
276
|
+
const imported = /* @__PURE__ */ new Map();
|
|
277
|
+
const errors = [];
|
|
278
|
+
for (const category of categories) {
|
|
279
|
+
switch (category) {
|
|
280
|
+
case "sessions":
|
|
281
|
+
await this.importSessions(imported, errors, onProgress);
|
|
282
|
+
break;
|
|
283
|
+
case "settings":
|
|
284
|
+
await this.importSettings(imported, errors, onProgress);
|
|
285
|
+
break;
|
|
286
|
+
case "skills":
|
|
287
|
+
await this.importSkills(imported, errors, onProgress);
|
|
288
|
+
break;
|
|
289
|
+
case "memory":
|
|
290
|
+
await this.importMemory(imported, errors, onProgress);
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
source: this.name,
|
|
298
|
+
imported,
|
|
299
|
+
errors,
|
|
300
|
+
duration: Date.now() - start
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// ---------------------------------------------------------------
|
|
304
|
+
// Sessions
|
|
305
|
+
// ---------------------------------------------------------------
|
|
306
|
+
async importSessions(imported, errors, onProgress) {
|
|
307
|
+
const home = this.resolvedHomePath;
|
|
308
|
+
const projectsDir = path2.join(home, "projects");
|
|
309
|
+
let success = 0;
|
|
310
|
+
let failed = 0;
|
|
311
|
+
let skipped = 0;
|
|
312
|
+
const skipReasons = {};
|
|
313
|
+
const trackSkip = (reason) => {
|
|
314
|
+
skipped++;
|
|
315
|
+
skipReasons[reason] = (skipReasons[reason] ?? 0) + 1;
|
|
316
|
+
};
|
|
317
|
+
if (!await fse2.pathExists(projectsDir)) {
|
|
318
|
+
imported.set("sessions", { success: 0, failed: 0, skipped: 0 });
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const projectEntries = await fse2.readdir(projectsDir, { withFileTypes: true });
|
|
322
|
+
const projectDirs = projectEntries.filter((e) => e.isDirectory());
|
|
323
|
+
const allSessionFiles = [];
|
|
324
|
+
for (const dir of projectDirs) {
|
|
325
|
+
const projectDir = path2.join(projectsDir, dir.name);
|
|
326
|
+
const entries = await fse2.readdir(projectDir, { withFileTypes: true });
|
|
327
|
+
const jsonlFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
328
|
+
for (const f of jsonlFiles) {
|
|
329
|
+
allSessionFiles.push({
|
|
330
|
+
filePath: path2.join(projectDir, f.name),
|
|
331
|
+
projectDirName: dir.name
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const total = allSessionFiles.length;
|
|
336
|
+
for (let i = 0; i < allSessionFiles.length; i++) {
|
|
337
|
+
const { filePath, projectDirName } = allSessionFiles[i];
|
|
338
|
+
onProgress?.({
|
|
339
|
+
category: "sessions",
|
|
340
|
+
current: i + 1,
|
|
341
|
+
total,
|
|
342
|
+
item: path2.basename(filePath),
|
|
343
|
+
status: "importing"
|
|
344
|
+
});
|
|
345
|
+
try {
|
|
346
|
+
const fileContent = await fse2.readFile(filePath, "utf-8");
|
|
347
|
+
if (!fileContent.trim()) {
|
|
348
|
+
trackSkip("empty file");
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const records = await this.readJsonlFile(filePath);
|
|
352
|
+
if (records.length === 0) {
|
|
353
|
+
trackSkip("no valid JSON records");
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const events = records;
|
|
357
|
+
const relevantEvents = events.filter(
|
|
358
|
+
(e) => (e.type === "user" || e.type === "assistant") && !e.isMeta && e.message
|
|
359
|
+
);
|
|
360
|
+
if (relevantEvents.length === 0) {
|
|
361
|
+
trackSkip("no user/assistant messages");
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const sessionGroups = /* @__PURE__ */ new Map();
|
|
365
|
+
for (const event of relevantEvents) {
|
|
366
|
+
const sid = event.sessionId ?? "unknown";
|
|
367
|
+
if (!sessionGroups.has(sid)) {
|
|
368
|
+
sessionGroups.set(sid, []);
|
|
369
|
+
}
|
|
370
|
+
sessionGroups.get(sid).push(event);
|
|
371
|
+
}
|
|
372
|
+
for (const [sessionId, sessionEvents] of sessionGroups) {
|
|
373
|
+
const messages = sessionEvents.map((e) => ({
|
|
374
|
+
role: e.message.role,
|
|
375
|
+
content: this.extractContent(e.message.content),
|
|
376
|
+
timestamp: e.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
377
|
+
}));
|
|
378
|
+
const firstEvent = sessionEvents[0];
|
|
379
|
+
const cwd = firstEvent.cwd ?? this.projectDirNameToPath(projectDirName);
|
|
380
|
+
const model = this.extractModel(sessionEvents) ?? "unknown";
|
|
381
|
+
const projectName = path2.basename(cwd);
|
|
382
|
+
const result = await this.writeAutohandSession({
|
|
383
|
+
projectPath: cwd,
|
|
384
|
+
projectName,
|
|
385
|
+
model,
|
|
386
|
+
messages,
|
|
387
|
+
source: this.name,
|
|
388
|
+
originalId: sessionId,
|
|
389
|
+
createdAt: messages[0].timestamp,
|
|
390
|
+
closedAt: messages[messages.length - 1].timestamp,
|
|
391
|
+
summary: this.buildSummary(messages),
|
|
392
|
+
status: "completed"
|
|
393
|
+
});
|
|
394
|
+
if (result === null) {
|
|
395
|
+
trackSkip("already imported");
|
|
396
|
+
} else {
|
|
397
|
+
success++;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} catch (err) {
|
|
401
|
+
failed++;
|
|
402
|
+
errors.push({
|
|
403
|
+
category: "sessions",
|
|
404
|
+
item: path2.basename(filePath),
|
|
405
|
+
error: err instanceof Error ? err.message : String(err),
|
|
406
|
+
retriable: true
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
imported.set("sessions", {
|
|
411
|
+
success,
|
|
412
|
+
failed,
|
|
413
|
+
skipped,
|
|
414
|
+
...Object.keys(skipReasons).length > 0 ? { skipReasons } : {}
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
// ---------------------------------------------------------------
|
|
418
|
+
// Settings
|
|
419
|
+
// ---------------------------------------------------------------
|
|
420
|
+
async importSettings(imported, errors, onProgress) {
|
|
421
|
+
const settingsPath = path2.join(this.resolvedHomePath, "settings.json");
|
|
422
|
+
if (!await fse2.pathExists(settingsPath)) {
|
|
423
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
onProgress?.({
|
|
427
|
+
category: "settings",
|
|
428
|
+
current: 1,
|
|
429
|
+
total: 1,
|
|
430
|
+
item: "settings.json",
|
|
431
|
+
status: "importing"
|
|
432
|
+
});
|
|
433
|
+
try {
|
|
434
|
+
const settings = await this.safeReadJson(settingsPath);
|
|
435
|
+
const permissions = settings.permissions;
|
|
436
|
+
if (permissions?.allow) {
|
|
437
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
438
|
+
await fse2.ensureDir(configDir);
|
|
439
|
+
const importedSettingsPath = path2.join(configDir, "imported-claude-settings.json");
|
|
440
|
+
await fse2.writeJson(importedSettingsPath, {
|
|
441
|
+
importedFrom: "claude",
|
|
442
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
443
|
+
permissions: permissions.allow,
|
|
444
|
+
raw: settings
|
|
445
|
+
}, { spaces: 2 });
|
|
446
|
+
}
|
|
447
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
448
|
+
onProgress?.({
|
|
449
|
+
category: "settings",
|
|
450
|
+
current: 1,
|
|
451
|
+
total: 1,
|
|
452
|
+
item: "settings.json",
|
|
453
|
+
status: "done"
|
|
454
|
+
});
|
|
455
|
+
} catch (err) {
|
|
456
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
457
|
+
errors.push({
|
|
458
|
+
category: "settings",
|
|
459
|
+
item: "settings.json",
|
|
460
|
+
error: err instanceof Error ? err.message : String(err),
|
|
461
|
+
retriable: false
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
// ---------------------------------------------------------------
|
|
466
|
+
// Skills
|
|
467
|
+
// ---------------------------------------------------------------
|
|
468
|
+
async importSkills(imported, errors, onProgress) {
|
|
469
|
+
const skillsDir = path2.join(this.resolvedHomePath, "skills");
|
|
470
|
+
if (!await fse2.pathExists(skillsDir)) {
|
|
471
|
+
imported.set("skills", { success: 0, failed: 0, skipped: 1 });
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const entries = await fse2.readdir(skillsDir, { withFileTypes: true });
|
|
475
|
+
const skillFiles = entries.filter((e) => e.isFile());
|
|
476
|
+
let success = 0;
|
|
477
|
+
let failed = 0;
|
|
478
|
+
const total = skillFiles.length;
|
|
479
|
+
const destDir = path2.join(AUTOHAND_PATHS.skills, "imported-claude");
|
|
480
|
+
for (let i = 0; i < skillFiles.length; i++) {
|
|
481
|
+
const file = skillFiles[i];
|
|
482
|
+
const src = path2.join(skillsDir, file.name);
|
|
483
|
+
const dest = path2.join(destDir, file.name);
|
|
484
|
+
onProgress?.({
|
|
485
|
+
category: "skills",
|
|
486
|
+
current: i + 1,
|
|
487
|
+
total,
|
|
488
|
+
item: file.name,
|
|
489
|
+
status: "importing"
|
|
490
|
+
});
|
|
491
|
+
try {
|
|
492
|
+
await fse2.ensureDir(destDir);
|
|
493
|
+
await fse2.copy(src, dest);
|
|
494
|
+
success++;
|
|
495
|
+
} catch (err) {
|
|
496
|
+
failed++;
|
|
497
|
+
errors.push({
|
|
498
|
+
category: "skills",
|
|
499
|
+
item: file.name,
|
|
500
|
+
error: err instanceof Error ? err.message : String(err),
|
|
501
|
+
retriable: true
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
imported.set("skills", { success, failed, skipped: 0 });
|
|
506
|
+
}
|
|
507
|
+
// ---------------------------------------------------------------
|
|
508
|
+
// Memory
|
|
509
|
+
// ---------------------------------------------------------------
|
|
510
|
+
async importMemory(imported, errors, onProgress) {
|
|
511
|
+
const projectsDir = path2.join(this.resolvedHomePath, "projects");
|
|
512
|
+
let success = 0;
|
|
513
|
+
let failed = 0;
|
|
514
|
+
if (!await fse2.pathExists(projectsDir)) {
|
|
515
|
+
imported.set("memory", { success: 0, failed: 0, skipped: 0 });
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const entries = await fse2.readdir(projectsDir, { withFileTypes: true });
|
|
519
|
+
const projectDirs = entries.filter((e) => e.isDirectory());
|
|
520
|
+
const total = projectDirs.length;
|
|
521
|
+
for (let i = 0; i < projectDirs.length; i++) {
|
|
522
|
+
const dir = projectDirs[i];
|
|
523
|
+
const projectDir = path2.join(projectsDir, dir.name);
|
|
524
|
+
const hasMemoryDir = await fse2.pathExists(path2.join(projectDir, "memory"));
|
|
525
|
+
const hasClaudeMd = await fse2.pathExists(path2.join(projectDir, "CLAUDE.md"));
|
|
526
|
+
if (!hasMemoryDir && !hasClaudeMd) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
onProgress?.({
|
|
530
|
+
category: "memory",
|
|
531
|
+
current: i + 1,
|
|
532
|
+
total,
|
|
533
|
+
item: dir.name,
|
|
534
|
+
status: "importing"
|
|
535
|
+
});
|
|
536
|
+
try {
|
|
537
|
+
const projectHash = dir.name.replace(/[^a-zA-Z0-9-]/g, "_");
|
|
538
|
+
const destDir = path2.join(AUTOHAND_PATHS.projects, projectHash, "imported-claude");
|
|
539
|
+
await fse2.ensureDir(destDir);
|
|
540
|
+
if (hasMemoryDir) {
|
|
541
|
+
await fse2.copy(path2.join(projectDir, "memory"), path2.join(destDir, "memory"));
|
|
542
|
+
}
|
|
543
|
+
if (hasClaudeMd) {
|
|
544
|
+
await fse2.copy(path2.join(projectDir, "CLAUDE.md"), path2.join(destDir, "CLAUDE.md"));
|
|
545
|
+
}
|
|
546
|
+
success++;
|
|
547
|
+
} catch (err) {
|
|
548
|
+
failed++;
|
|
549
|
+
errors.push({
|
|
550
|
+
category: "memory",
|
|
551
|
+
item: dir.name,
|
|
552
|
+
error: err instanceof Error ? err.message : String(err),
|
|
553
|
+
retriable: true
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
imported.set("memory", { success, failed, skipped: 0 });
|
|
558
|
+
}
|
|
559
|
+
// ---------------------------------------------------------------
|
|
560
|
+
// Helpers
|
|
561
|
+
// ---------------------------------------------------------------
|
|
562
|
+
/**
|
|
563
|
+
* Extract text content from a Claude message content field.
|
|
564
|
+
* Content can be a string or an array of content blocks.
|
|
565
|
+
*/
|
|
566
|
+
extractContent(content) {
|
|
567
|
+
if (typeof content === "string") {
|
|
568
|
+
return content;
|
|
569
|
+
}
|
|
570
|
+
if (Array.isArray(content)) {
|
|
571
|
+
return content.filter((block) => block.type === "text" && block.text).map((block) => block.text).join("");
|
|
572
|
+
}
|
|
573
|
+
return "";
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Extract the model name from session events. Takes the first found model.
|
|
577
|
+
*/
|
|
578
|
+
extractModel(events) {
|
|
579
|
+
for (const event of events) {
|
|
580
|
+
if (event.message?.model) {
|
|
581
|
+
return event.message.model;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return void 0;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Convert a project directory name (e.g. "-Users-me-project") to a path.
|
|
588
|
+
*/
|
|
589
|
+
projectDirNameToPath(dirName) {
|
|
590
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Build a brief summary from the first real user message.
|
|
594
|
+
* Skips system-injected context (XML tags, CLAUDE.md, etc.)
|
|
595
|
+
*/
|
|
596
|
+
buildSummary(messages) {
|
|
597
|
+
for (const msg of messages) {
|
|
598
|
+
if (msg.role !== "user") continue;
|
|
599
|
+
const cleaned = this.stripSystemContent(msg.content);
|
|
600
|
+
if (cleaned.length > 0) {
|
|
601
|
+
const text = cleaned.slice(0, 100);
|
|
602
|
+
return text.length < cleaned.length ? `${text}...` : text;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return "Imported Claude session";
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Strip system-injected XML tags and their content from a message,
|
|
609
|
+
* returning only the actual user text.
|
|
610
|
+
*/
|
|
611
|
+
stripSystemContent(text) {
|
|
612
|
+
let cleaned = text;
|
|
613
|
+
const systemTags = [
|
|
614
|
+
"local-command-caveat",
|
|
615
|
+
"system-reminder",
|
|
616
|
+
"user_instructions",
|
|
617
|
+
"environment_context",
|
|
618
|
+
"context",
|
|
619
|
+
"automatic_reminders",
|
|
620
|
+
"user_request",
|
|
621
|
+
"bash-input",
|
|
622
|
+
"bash-stdout",
|
|
623
|
+
"bash-stderr"
|
|
624
|
+
];
|
|
625
|
+
for (const tag of systemTags) {
|
|
626
|
+
const pattern = new RegExp(`<${tag}>[\\s\\S]*?</${tag}>`, "g");
|
|
627
|
+
cleaned = cleaned.replace(pattern, "");
|
|
628
|
+
}
|
|
629
|
+
return cleaned.trim();
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/import/importers/CodexImporter.ts
|
|
634
|
+
import path3 from "path";
|
|
635
|
+
import fse3 from "fs-extra";
|
|
636
|
+
var CodexImporter = class extends BaseImporter {
|
|
637
|
+
constructor() {
|
|
638
|
+
super(...arguments);
|
|
639
|
+
this.name = "codex";
|
|
640
|
+
this.displayName = "OpenAI Codex";
|
|
641
|
+
this.homePath = "~/.codex";
|
|
642
|
+
}
|
|
643
|
+
// ---------------------------------------------------------------
|
|
644
|
+
// scan()
|
|
645
|
+
// ---------------------------------------------------------------
|
|
646
|
+
async scan() {
|
|
647
|
+
const available = /* @__PURE__ */ new Map();
|
|
648
|
+
const home = this.resolvedHomePath;
|
|
649
|
+
if (!await fse3.pathExists(home)) {
|
|
650
|
+
return { source: this.name, available };
|
|
651
|
+
}
|
|
652
|
+
const sessionsDir = path3.join(home, "sessions");
|
|
653
|
+
if (await fse3.pathExists(sessionsDir)) {
|
|
654
|
+
const sessionFiles = await this.walkJsonlFiles(sessionsDir);
|
|
655
|
+
if (sessionFiles.length > 0) {
|
|
656
|
+
available.set("sessions", {
|
|
657
|
+
count: sessionFiles.length,
|
|
658
|
+
description: `${sessionFiles.length} session file${sessionFiles.length !== 1 ? "s" : ""}`
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (await fse3.pathExists(path3.join(home, "config.toml"))) {
|
|
663
|
+
available.set("settings", { count: 1, description: "Codex config.toml" });
|
|
664
|
+
}
|
|
665
|
+
const skillsDir = path3.join(home, "skills");
|
|
666
|
+
if (await fse3.pathExists(skillsDir)) {
|
|
667
|
+
const skillEntries = await fse3.readdir(skillsDir, { withFileTypes: true });
|
|
668
|
+
const skillFiles = skillEntries.filter((e) => e.isFile());
|
|
669
|
+
if (skillFiles.length > 0) {
|
|
670
|
+
available.set("skills", {
|
|
671
|
+
count: skillFiles.length,
|
|
672
|
+
description: `${skillFiles.length} skill file${skillFiles.length !== 1 ? "s" : ""}`
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const rulesDir = path3.join(home, "rules");
|
|
677
|
+
if (await fse3.pathExists(rulesDir)) {
|
|
678
|
+
const ruleEntries = await fse3.readdir(rulesDir, { withFileTypes: true });
|
|
679
|
+
const ruleFiles = ruleEntries.filter((e) => e.isFile());
|
|
680
|
+
if (ruleFiles.length > 0) {
|
|
681
|
+
available.set("memory", {
|
|
682
|
+
count: ruleFiles.length,
|
|
683
|
+
description: `${ruleFiles.length} rule file${ruleFiles.length !== 1 ? "s" : ""}`
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return { source: this.name, available };
|
|
688
|
+
}
|
|
689
|
+
// ---------------------------------------------------------------
|
|
690
|
+
// import()
|
|
691
|
+
// ---------------------------------------------------------------
|
|
692
|
+
async import(categories, onProgress) {
|
|
693
|
+
const start = Date.now();
|
|
694
|
+
const imported = /* @__PURE__ */ new Map();
|
|
695
|
+
const errors = [];
|
|
696
|
+
for (const category of categories) {
|
|
697
|
+
switch (category) {
|
|
698
|
+
case "sessions":
|
|
699
|
+
await this.importSessions(imported, errors, onProgress);
|
|
700
|
+
break;
|
|
701
|
+
case "settings":
|
|
702
|
+
await this.importSettings(imported, errors, onProgress);
|
|
703
|
+
break;
|
|
704
|
+
case "skills":
|
|
705
|
+
await this.importSkills(imported, errors, onProgress);
|
|
706
|
+
break;
|
|
707
|
+
default:
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
source: this.name,
|
|
713
|
+
imported,
|
|
714
|
+
errors,
|
|
715
|
+
duration: Date.now() - start
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
// ---------------------------------------------------------------
|
|
719
|
+
// Sessions
|
|
720
|
+
// ---------------------------------------------------------------
|
|
721
|
+
async importSessions(imported, errors, onProgress) {
|
|
722
|
+
const sessionsDir = path3.join(this.resolvedHomePath, "sessions");
|
|
723
|
+
let success = 0;
|
|
724
|
+
let failed = 0;
|
|
725
|
+
let skipped = 0;
|
|
726
|
+
const skipReasons = {};
|
|
727
|
+
const trackSkip = (reason) => {
|
|
728
|
+
skipped++;
|
|
729
|
+
skipReasons[reason] = (skipReasons[reason] ?? 0) + 1;
|
|
730
|
+
};
|
|
731
|
+
if (!await fse3.pathExists(sessionsDir)) {
|
|
732
|
+
imported.set("sessions", { success: 0, failed: 0, skipped: 0 });
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const sessionFiles = await this.walkJsonlFiles(sessionsDir);
|
|
736
|
+
const total = sessionFiles.length;
|
|
737
|
+
for (let i = 0; i < sessionFiles.length; i++) {
|
|
738
|
+
const filePath = sessionFiles[i];
|
|
739
|
+
onProgress?.({
|
|
740
|
+
category: "sessions",
|
|
741
|
+
current: i + 1,
|
|
742
|
+
total,
|
|
743
|
+
item: path3.basename(filePath),
|
|
744
|
+
status: "importing"
|
|
745
|
+
});
|
|
746
|
+
try {
|
|
747
|
+
const fileContent = await fse3.readFile(filePath, "utf-8");
|
|
748
|
+
if (!fileContent.trim()) {
|
|
749
|
+
trackSkip("empty file");
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
const records = await this.readJsonlFile(filePath);
|
|
753
|
+
if (records.length === 0) {
|
|
754
|
+
trackSkip("no valid JSON records");
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
const events = records;
|
|
758
|
+
const metaEvent = events.find((e) => e.type === "session_meta");
|
|
759
|
+
const sessionId = metaEvent?.payload?.id ?? path3.basename(filePath, ".jsonl");
|
|
760
|
+
const cwd = metaEvent?.payload?.cwd ?? "/unknown";
|
|
761
|
+
const messages = [];
|
|
762
|
+
for (const event of events) {
|
|
763
|
+
if (event.type === "response_item") {
|
|
764
|
+
const payload = event.payload;
|
|
765
|
+
if (payload.type === "message" && payload.role && payload.content) {
|
|
766
|
+
const text = payload.content.filter((c) => (c.type === "input_text" || c.type === "output_text") && c.text).map((c) => c.text).join("");
|
|
767
|
+
if (text && !this.isSystemMessage(text)) {
|
|
768
|
+
messages.push({
|
|
769
|
+
role: payload.role,
|
|
770
|
+
content: text,
|
|
771
|
+
timestamp: event.timestamp
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
} else if (event.type === "event_msg") {
|
|
776
|
+
const payload = event.payload;
|
|
777
|
+
if (payload.type === "agent_message" && payload.message) {
|
|
778
|
+
messages.push({
|
|
779
|
+
role: "assistant",
|
|
780
|
+
content: payload.message,
|
|
781
|
+
timestamp: event.timestamp
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (messages.length === 0) {
|
|
787
|
+
trackSkip("no user messages (only system content)");
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const projectName = path3.basename(cwd);
|
|
791
|
+
const result = await this.writeAutohandSession({
|
|
792
|
+
projectPath: cwd,
|
|
793
|
+
projectName,
|
|
794
|
+
model: "codex",
|
|
795
|
+
messages,
|
|
796
|
+
source: this.name,
|
|
797
|
+
originalId: sessionId,
|
|
798
|
+
createdAt: messages[0].timestamp,
|
|
799
|
+
closedAt: messages[messages.length - 1].timestamp,
|
|
800
|
+
summary: this.buildSummary(messages),
|
|
801
|
+
status: "completed"
|
|
802
|
+
});
|
|
803
|
+
if (result === null) {
|
|
804
|
+
trackSkip("already imported");
|
|
805
|
+
} else {
|
|
806
|
+
success++;
|
|
807
|
+
}
|
|
808
|
+
} catch (err) {
|
|
809
|
+
failed++;
|
|
810
|
+
errors.push({
|
|
811
|
+
category: "sessions",
|
|
812
|
+
item: path3.basename(filePath),
|
|
813
|
+
error: err instanceof Error ? err.message : String(err),
|
|
814
|
+
retriable: true
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
imported.set("sessions", {
|
|
819
|
+
success,
|
|
820
|
+
failed,
|
|
821
|
+
skipped,
|
|
822
|
+
...Object.keys(skipReasons).length > 0 ? { skipReasons } : {}
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
// ---------------------------------------------------------------
|
|
826
|
+
// Settings (TOML)
|
|
827
|
+
// ---------------------------------------------------------------
|
|
828
|
+
async importSettings(imported, errors, onProgress) {
|
|
829
|
+
const configPath = path3.join(this.resolvedHomePath, "config.toml");
|
|
830
|
+
if (!await fse3.pathExists(configPath)) {
|
|
831
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
onProgress?.({
|
|
835
|
+
category: "settings",
|
|
836
|
+
current: 1,
|
|
837
|
+
total: 1,
|
|
838
|
+
item: "config.toml",
|
|
839
|
+
status: "importing"
|
|
840
|
+
});
|
|
841
|
+
try {
|
|
842
|
+
const tomlContent = await fse3.readFile(configPath, "utf-8");
|
|
843
|
+
const parsed = this.parseToml(tomlContent);
|
|
844
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
845
|
+
await fse3.ensureDir(configDir);
|
|
846
|
+
await fse3.writeJson(
|
|
847
|
+
path3.join(configDir, "imported-codex-settings.json"),
|
|
848
|
+
{
|
|
849
|
+
importedFrom: "codex",
|
|
850
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
851
|
+
parsed,
|
|
852
|
+
raw: tomlContent
|
|
853
|
+
},
|
|
854
|
+
{ spaces: 2 }
|
|
855
|
+
);
|
|
856
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
857
|
+
onProgress?.({
|
|
858
|
+
category: "settings",
|
|
859
|
+
current: 1,
|
|
860
|
+
total: 1,
|
|
861
|
+
item: "config.toml",
|
|
862
|
+
status: "done"
|
|
863
|
+
});
|
|
864
|
+
} catch (err) {
|
|
865
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
866
|
+
errors.push({
|
|
867
|
+
category: "settings",
|
|
868
|
+
item: "config.toml",
|
|
869
|
+
error: err instanceof Error ? err.message : String(err),
|
|
870
|
+
retriable: false
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
// ---------------------------------------------------------------
|
|
875
|
+
// Skills
|
|
876
|
+
// ---------------------------------------------------------------
|
|
877
|
+
async importSkills(imported, errors, onProgress) {
|
|
878
|
+
const skillsDir = path3.join(this.resolvedHomePath, "skills");
|
|
879
|
+
if (!await fse3.pathExists(skillsDir)) {
|
|
880
|
+
imported.set("skills", { success: 0, failed: 0, skipped: 1 });
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
const entries = await fse3.readdir(skillsDir, { withFileTypes: true });
|
|
884
|
+
const skillFiles = entries.filter((e) => e.isFile());
|
|
885
|
+
let success = 0;
|
|
886
|
+
let failed = 0;
|
|
887
|
+
const total = skillFiles.length;
|
|
888
|
+
const destDir = path3.join(AUTOHAND_PATHS.skills, "imported-codex");
|
|
889
|
+
for (let i = 0; i < skillFiles.length; i++) {
|
|
890
|
+
const file = skillFiles[i];
|
|
891
|
+
const src = path3.join(skillsDir, file.name);
|
|
892
|
+
const dest = path3.join(destDir, file.name);
|
|
893
|
+
onProgress?.({
|
|
894
|
+
category: "skills",
|
|
895
|
+
current: i + 1,
|
|
896
|
+
total,
|
|
897
|
+
item: file.name,
|
|
898
|
+
status: "importing"
|
|
899
|
+
});
|
|
900
|
+
try {
|
|
901
|
+
await fse3.ensureDir(destDir);
|
|
902
|
+
await fse3.copy(src, dest);
|
|
903
|
+
success++;
|
|
904
|
+
} catch (err) {
|
|
905
|
+
failed++;
|
|
906
|
+
errors.push({
|
|
907
|
+
category: "skills",
|
|
908
|
+
item: file.name,
|
|
909
|
+
error: err instanceof Error ? err.message : String(err),
|
|
910
|
+
retriable: true
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
imported.set("skills", { success, failed, skipped: 0 });
|
|
915
|
+
}
|
|
916
|
+
// ---------------------------------------------------------------
|
|
917
|
+
// Helpers
|
|
918
|
+
// ---------------------------------------------------------------
|
|
919
|
+
/**
|
|
920
|
+
* Recursively walk a directory tree and collect all .jsonl file paths.
|
|
921
|
+
*/
|
|
922
|
+
async walkJsonlFiles(dir) {
|
|
923
|
+
const results = [];
|
|
924
|
+
const entries = await fse3.readdir(dir, { withFileTypes: true });
|
|
925
|
+
for (const entry of entries) {
|
|
926
|
+
const fullPath = path3.join(dir, entry.name);
|
|
927
|
+
if (entry.isDirectory()) {
|
|
928
|
+
const nested = await this.walkJsonlFiles(fullPath);
|
|
929
|
+
results.push(...nested);
|
|
930
|
+
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
931
|
+
results.push(fullPath);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return results;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Simple TOML parser. Handles:
|
|
938
|
+
* - `key = "value"` (quoted strings)
|
|
939
|
+
* - `key = value` (unquoted – numbers, booleans, bare strings)
|
|
940
|
+
* - `[section]` and `[section.subsection]` headers
|
|
941
|
+
* - `# comments`
|
|
942
|
+
* - blank lines
|
|
943
|
+
*
|
|
944
|
+
* Returns a flat object with dotted keys for sections
|
|
945
|
+
* (e.g. `{ "section.key": "value" }`).
|
|
946
|
+
*/
|
|
947
|
+
parseToml(content) {
|
|
948
|
+
const result = {};
|
|
949
|
+
let currentSection = "";
|
|
950
|
+
for (const rawLine of content.split("\n")) {
|
|
951
|
+
const line = rawLine.trim();
|
|
952
|
+
if (!line || line.startsWith("#")) continue;
|
|
953
|
+
const sectionMatch = line.match(/^\[([^\]]+)\]$/);
|
|
954
|
+
if (sectionMatch) {
|
|
955
|
+
currentSection = sectionMatch[1];
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
const kvMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*=\s*(.+)$/);
|
|
959
|
+
if (!kvMatch) continue;
|
|
960
|
+
const key = currentSection ? `${currentSection}.${kvMatch[1]}` : kvMatch[1];
|
|
961
|
+
let value = kvMatch[2].trim();
|
|
962
|
+
const inlineComment = value.indexOf(" #");
|
|
963
|
+
if (inlineComment > 0) {
|
|
964
|
+
value = value.slice(0, inlineComment).trim();
|
|
965
|
+
}
|
|
966
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
967
|
+
result[key] = value.slice(1, -1);
|
|
968
|
+
} else if (value === "true") {
|
|
969
|
+
result[key] = true;
|
|
970
|
+
} else if (value === "false") {
|
|
971
|
+
result[key] = false;
|
|
972
|
+
} else if (/^-?\d+(\.\d+)?$/.test(value)) {
|
|
973
|
+
result[key] = Number(value);
|
|
974
|
+
} else {
|
|
975
|
+
result[key] = value;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return result;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Detect system-injected context messages that should not be imported.
|
|
982
|
+
* These are Codex CLI-generated system prompts, environment info, etc.
|
|
983
|
+
*/
|
|
984
|
+
isSystemMessage(text) {
|
|
985
|
+
const trimmed = text.trimStart();
|
|
986
|
+
return trimmed.startsWith("<user_instructions>") || trimmed.startsWith("<environment_context>") || trimmed.startsWith("<user_request>") || trimmed.startsWith("<automatic_reminders>") || trimmed.startsWith("<system-reminder>") || trimmed.startsWith("<context>") || trimmed.startsWith("# Agents Guidance\n");
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Build a brief summary from the first real user message.
|
|
990
|
+
*/
|
|
991
|
+
buildSummary(messages) {
|
|
992
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
993
|
+
if (!firstUser) return "Imported Codex session";
|
|
994
|
+
const text = firstUser.content.trim().slice(0, 100);
|
|
995
|
+
return text.length < firstUser.content.trim().length ? `${text}...` : text;
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
// src/import/importers/GeminiImporter.ts
|
|
1000
|
+
import path4 from "path";
|
|
1001
|
+
import fse4 from "fs-extra";
|
|
1002
|
+
var GeminiImporter = class extends BaseImporter {
|
|
1003
|
+
constructor() {
|
|
1004
|
+
super(...arguments);
|
|
1005
|
+
this.name = "gemini";
|
|
1006
|
+
this.displayName = "Google Gemini";
|
|
1007
|
+
this.homePath = "~/.gemini";
|
|
1008
|
+
}
|
|
1009
|
+
// ---------------------------------------------------------------
|
|
1010
|
+
// scan()
|
|
1011
|
+
// ---------------------------------------------------------------
|
|
1012
|
+
async scan() {
|
|
1013
|
+
const available = /* @__PURE__ */ new Map();
|
|
1014
|
+
const home = this.resolvedHomePath;
|
|
1015
|
+
if (!await fse4.pathExists(home)) {
|
|
1016
|
+
return { source: this.name, available };
|
|
1017
|
+
}
|
|
1018
|
+
const settingsPath = path4.join(home, "settings.json");
|
|
1019
|
+
const hasSettings = await fse4.pathExists(settingsPath);
|
|
1020
|
+
if (hasSettings) {
|
|
1021
|
+
available.set("settings", { count: 1, description: "Gemini settings.json" });
|
|
1022
|
+
try {
|
|
1023
|
+
const settings = await this.safeReadJson(settingsPath);
|
|
1024
|
+
const hooks = settings.hooks;
|
|
1025
|
+
if (hooks) {
|
|
1026
|
+
const hookSections = Object.keys(hooks).filter(
|
|
1027
|
+
(k) => Array.isArray(hooks[k]) && hooks[k].length > 0
|
|
1028
|
+
);
|
|
1029
|
+
if (hookSections.length > 0) {
|
|
1030
|
+
available.set("hooks", {
|
|
1031
|
+
count: hookSections.length,
|
|
1032
|
+
description: `${hookSections.length} hook section${hookSections.length !== 1 ? "s" : ""} (${hookSections.join(", ")})`
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
} catch {
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
const geminiMdPath = path4.join(home, "GEMINI.md");
|
|
1040
|
+
if (await fse4.pathExists(geminiMdPath)) {
|
|
1041
|
+
available.set("memory", { count: 1, description: "GEMINI.md project memory" });
|
|
1042
|
+
}
|
|
1043
|
+
return { source: this.name, available };
|
|
1044
|
+
}
|
|
1045
|
+
// ---------------------------------------------------------------
|
|
1046
|
+
// import()
|
|
1047
|
+
// ---------------------------------------------------------------
|
|
1048
|
+
async import(categories, onProgress) {
|
|
1049
|
+
const start = Date.now();
|
|
1050
|
+
const imported = /* @__PURE__ */ new Map();
|
|
1051
|
+
const errors = [];
|
|
1052
|
+
for (const category of categories) {
|
|
1053
|
+
switch (category) {
|
|
1054
|
+
case "settings":
|
|
1055
|
+
await this.importSettings(imported, errors, onProgress);
|
|
1056
|
+
break;
|
|
1057
|
+
case "hooks":
|
|
1058
|
+
await this.importHooks(imported, errors, onProgress);
|
|
1059
|
+
break;
|
|
1060
|
+
case "memory":
|
|
1061
|
+
await this.importMemory(imported, errors, onProgress);
|
|
1062
|
+
break;
|
|
1063
|
+
default:
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
return {
|
|
1068
|
+
source: this.name,
|
|
1069
|
+
imported,
|
|
1070
|
+
errors,
|
|
1071
|
+
duration: Date.now() - start
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
// ---------------------------------------------------------------
|
|
1075
|
+
// Settings
|
|
1076
|
+
// ---------------------------------------------------------------
|
|
1077
|
+
async importSettings(imported, errors, onProgress) {
|
|
1078
|
+
const settingsPath = path4.join(this.resolvedHomePath, "settings.json");
|
|
1079
|
+
if (!await fse4.pathExists(settingsPath)) {
|
|
1080
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
onProgress?.({
|
|
1084
|
+
category: "settings",
|
|
1085
|
+
current: 1,
|
|
1086
|
+
total: 1,
|
|
1087
|
+
item: "settings.json",
|
|
1088
|
+
status: "importing"
|
|
1089
|
+
});
|
|
1090
|
+
try {
|
|
1091
|
+
const settings = await this.safeReadJson(settingsPath);
|
|
1092
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1093
|
+
await fse4.ensureDir(configDir);
|
|
1094
|
+
await fse4.writeJson(
|
|
1095
|
+
path4.join(configDir, "imported-gemini-settings.json"),
|
|
1096
|
+
{
|
|
1097
|
+
importedFrom: "gemini",
|
|
1098
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1099
|
+
raw: settings
|
|
1100
|
+
},
|
|
1101
|
+
{ spaces: 2 }
|
|
1102
|
+
);
|
|
1103
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
1104
|
+
onProgress?.({
|
|
1105
|
+
category: "settings",
|
|
1106
|
+
current: 1,
|
|
1107
|
+
total: 1,
|
|
1108
|
+
item: "settings.json",
|
|
1109
|
+
status: "done"
|
|
1110
|
+
});
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
1113
|
+
errors.push({
|
|
1114
|
+
category: "settings",
|
|
1115
|
+
item: "settings.json",
|
|
1116
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1117
|
+
retriable: false
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
// ---------------------------------------------------------------
|
|
1122
|
+
// Hooks
|
|
1123
|
+
// ---------------------------------------------------------------
|
|
1124
|
+
async importHooks(imported, errors, onProgress) {
|
|
1125
|
+
const settingsPath = path4.join(this.resolvedHomePath, "settings.json");
|
|
1126
|
+
if (!await fse4.pathExists(settingsPath)) {
|
|
1127
|
+
imported.set("hooks", { success: 0, failed: 0, skipped: 1 });
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
onProgress?.({
|
|
1131
|
+
category: "hooks",
|
|
1132
|
+
current: 1,
|
|
1133
|
+
total: 1,
|
|
1134
|
+
item: "hooks from settings.json",
|
|
1135
|
+
status: "importing"
|
|
1136
|
+
});
|
|
1137
|
+
try {
|
|
1138
|
+
const settings = await this.safeReadJson(settingsPath);
|
|
1139
|
+
const hooks = settings.hooks;
|
|
1140
|
+
if (!hooks || Object.keys(hooks).length === 0) {
|
|
1141
|
+
imported.set("hooks", { success: 0, failed: 0, skipped: 1 });
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1145
|
+
await fse4.ensureDir(configDir);
|
|
1146
|
+
await fse4.writeJson(
|
|
1147
|
+
path4.join(configDir, "imported-gemini-hooks.json"),
|
|
1148
|
+
{
|
|
1149
|
+
importedFrom: "gemini",
|
|
1150
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1151
|
+
hooks
|
|
1152
|
+
},
|
|
1153
|
+
{ spaces: 2 }
|
|
1154
|
+
);
|
|
1155
|
+
imported.set("hooks", { success: 1, failed: 0, skipped: 0 });
|
|
1156
|
+
onProgress?.({
|
|
1157
|
+
category: "hooks",
|
|
1158
|
+
current: 1,
|
|
1159
|
+
total: 1,
|
|
1160
|
+
item: "hooks from settings.json",
|
|
1161
|
+
status: "done"
|
|
1162
|
+
});
|
|
1163
|
+
} catch (err) {
|
|
1164
|
+
imported.set("hooks", { success: 0, failed: 1, skipped: 0 });
|
|
1165
|
+
errors.push({
|
|
1166
|
+
category: "hooks",
|
|
1167
|
+
item: "hooks from settings.json",
|
|
1168
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1169
|
+
retriable: false
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
// ---------------------------------------------------------------
|
|
1174
|
+
// Memory
|
|
1175
|
+
// ---------------------------------------------------------------
|
|
1176
|
+
async importMemory(imported, errors, onProgress) {
|
|
1177
|
+
const geminiMdPath = path4.join(this.resolvedHomePath, "GEMINI.md");
|
|
1178
|
+
if (!await fse4.pathExists(geminiMdPath)) {
|
|
1179
|
+
imported.set("memory", { success: 0, failed: 0, skipped: 1 });
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
onProgress?.({
|
|
1183
|
+
category: "memory",
|
|
1184
|
+
current: 1,
|
|
1185
|
+
total: 1,
|
|
1186
|
+
item: "GEMINI.md",
|
|
1187
|
+
status: "importing"
|
|
1188
|
+
});
|
|
1189
|
+
try {
|
|
1190
|
+
const destDir = path4.join(AUTOHAND_PATHS.memory, "imported-gemini");
|
|
1191
|
+
await fse4.ensureDir(destDir);
|
|
1192
|
+
await fse4.copy(geminiMdPath, path4.join(destDir, "GEMINI.md"));
|
|
1193
|
+
imported.set("memory", { success: 1, failed: 0, skipped: 0 });
|
|
1194
|
+
onProgress?.({
|
|
1195
|
+
category: "memory",
|
|
1196
|
+
current: 1,
|
|
1197
|
+
total: 1,
|
|
1198
|
+
item: "GEMINI.md",
|
|
1199
|
+
status: "done"
|
|
1200
|
+
});
|
|
1201
|
+
} catch (err) {
|
|
1202
|
+
imported.set("memory", { success: 0, failed: 1, skipped: 0 });
|
|
1203
|
+
errors.push({
|
|
1204
|
+
category: "memory",
|
|
1205
|
+
item: "GEMINI.md",
|
|
1206
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1207
|
+
retriable: true
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1213
|
+
// src/import/importers/CursorImporter.ts
|
|
1214
|
+
import path5 from "path";
|
|
1215
|
+
import fse5 from "fs-extra";
|
|
1216
|
+
var CursorImporter = class extends BaseImporter {
|
|
1217
|
+
constructor() {
|
|
1218
|
+
super(...arguments);
|
|
1219
|
+
this.name = "cursor";
|
|
1220
|
+
this.displayName = "Cursor";
|
|
1221
|
+
this.homePath = "~/.cursor";
|
|
1222
|
+
}
|
|
1223
|
+
// ---------------------------------------------------------------
|
|
1224
|
+
// scan()
|
|
1225
|
+
// ---------------------------------------------------------------
|
|
1226
|
+
async scan() {
|
|
1227
|
+
const available = /* @__PURE__ */ new Map();
|
|
1228
|
+
const home = this.resolvedHomePath;
|
|
1229
|
+
if (!await fse5.pathExists(home)) {
|
|
1230
|
+
return { source: this.name, available };
|
|
1231
|
+
}
|
|
1232
|
+
const hooksPath = path5.join(home, "hooks.json");
|
|
1233
|
+
if (await fse5.pathExists(hooksPath)) {
|
|
1234
|
+
available.set("settings", { count: 1, description: "Cursor hooks.json preferences" });
|
|
1235
|
+
available.set("hooks", { count: 1, description: "Cursor hook configurations" });
|
|
1236
|
+
}
|
|
1237
|
+
const mcpPath = path5.join(home, "mcp.json");
|
|
1238
|
+
if (await fse5.pathExists(mcpPath)) {
|
|
1239
|
+
available.set("mcp", { count: 1, description: "Cursor MCP server configurations" });
|
|
1240
|
+
}
|
|
1241
|
+
return { source: this.name, available };
|
|
1242
|
+
}
|
|
1243
|
+
// ---------------------------------------------------------------
|
|
1244
|
+
// import()
|
|
1245
|
+
// ---------------------------------------------------------------
|
|
1246
|
+
async import(categories, onProgress) {
|
|
1247
|
+
const start = Date.now();
|
|
1248
|
+
const imported = /* @__PURE__ */ new Map();
|
|
1249
|
+
const errors = [];
|
|
1250
|
+
for (const category of categories) {
|
|
1251
|
+
switch (category) {
|
|
1252
|
+
case "settings":
|
|
1253
|
+
await this.importSettings(imported, errors, onProgress);
|
|
1254
|
+
break;
|
|
1255
|
+
case "hooks":
|
|
1256
|
+
await this.importHooks(imported, errors, onProgress);
|
|
1257
|
+
break;
|
|
1258
|
+
case "mcp":
|
|
1259
|
+
await this.importMcp(imported, errors, onProgress);
|
|
1260
|
+
break;
|
|
1261
|
+
default:
|
|
1262
|
+
break;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return {
|
|
1266
|
+
source: this.name,
|
|
1267
|
+
imported,
|
|
1268
|
+
errors,
|
|
1269
|
+
duration: Date.now() - start
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
// ---------------------------------------------------------------
|
|
1273
|
+
// Settings
|
|
1274
|
+
// ---------------------------------------------------------------
|
|
1275
|
+
async importSettings(imported, errors, onProgress) {
|
|
1276
|
+
const hooksPath = path5.join(this.resolvedHomePath, "hooks.json");
|
|
1277
|
+
if (!await fse5.pathExists(hooksPath)) {
|
|
1278
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
onProgress?.({
|
|
1282
|
+
category: "settings",
|
|
1283
|
+
current: 1,
|
|
1284
|
+
total: 1,
|
|
1285
|
+
item: "hooks.json",
|
|
1286
|
+
status: "importing"
|
|
1287
|
+
});
|
|
1288
|
+
try {
|
|
1289
|
+
const hooksData = await this.safeReadJson(hooksPath);
|
|
1290
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1291
|
+
await fse5.ensureDir(configDir);
|
|
1292
|
+
await fse5.writeJson(
|
|
1293
|
+
path5.join(configDir, "imported-cursor-settings.json"),
|
|
1294
|
+
{
|
|
1295
|
+
importedFrom: "cursor",
|
|
1296
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1297
|
+
raw: hooksData
|
|
1298
|
+
},
|
|
1299
|
+
{ spaces: 2 }
|
|
1300
|
+
);
|
|
1301
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
1302
|
+
onProgress?.({
|
|
1303
|
+
category: "settings",
|
|
1304
|
+
current: 1,
|
|
1305
|
+
total: 1,
|
|
1306
|
+
item: "hooks.json",
|
|
1307
|
+
status: "done"
|
|
1308
|
+
});
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
1311
|
+
errors.push({
|
|
1312
|
+
category: "settings",
|
|
1313
|
+
item: "hooks.json",
|
|
1314
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1315
|
+
retriable: false
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
// ---------------------------------------------------------------
|
|
1320
|
+
// Hooks
|
|
1321
|
+
// ---------------------------------------------------------------
|
|
1322
|
+
async importHooks(imported, errors, onProgress) {
|
|
1323
|
+
const hooksPath = path5.join(this.resolvedHomePath, "hooks.json");
|
|
1324
|
+
if (!await fse5.pathExists(hooksPath)) {
|
|
1325
|
+
imported.set("hooks", { success: 0, failed: 0, skipped: 1 });
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
onProgress?.({
|
|
1329
|
+
category: "hooks",
|
|
1330
|
+
current: 1,
|
|
1331
|
+
total: 1,
|
|
1332
|
+
item: "hooks.json",
|
|
1333
|
+
status: "importing"
|
|
1334
|
+
});
|
|
1335
|
+
try {
|
|
1336
|
+
const hooksData = await this.safeReadJson(hooksPath);
|
|
1337
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1338
|
+
await fse5.ensureDir(configDir);
|
|
1339
|
+
await fse5.writeJson(
|
|
1340
|
+
path5.join(configDir, "imported-cursor-hooks.json"),
|
|
1341
|
+
{
|
|
1342
|
+
importedFrom: "cursor",
|
|
1343
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1344
|
+
hooks: hooksData.hooks ?? hooksData
|
|
1345
|
+
},
|
|
1346
|
+
{ spaces: 2 }
|
|
1347
|
+
);
|
|
1348
|
+
imported.set("hooks", { success: 1, failed: 0, skipped: 0 });
|
|
1349
|
+
onProgress?.({
|
|
1350
|
+
category: "hooks",
|
|
1351
|
+
current: 1,
|
|
1352
|
+
total: 1,
|
|
1353
|
+
item: "hooks.json",
|
|
1354
|
+
status: "done"
|
|
1355
|
+
});
|
|
1356
|
+
} catch (err) {
|
|
1357
|
+
imported.set("hooks", { success: 0, failed: 1, skipped: 0 });
|
|
1358
|
+
errors.push({
|
|
1359
|
+
category: "hooks",
|
|
1360
|
+
item: "hooks.json",
|
|
1361
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1362
|
+
retriable: false
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
// ---------------------------------------------------------------
|
|
1367
|
+
// MCP
|
|
1368
|
+
// ---------------------------------------------------------------
|
|
1369
|
+
async importMcp(imported, errors, onProgress) {
|
|
1370
|
+
const mcpPath = path5.join(this.resolvedHomePath, "mcp.json");
|
|
1371
|
+
if (!await fse5.pathExists(mcpPath)) {
|
|
1372
|
+
imported.set("mcp", { success: 0, failed: 0, skipped: 1 });
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
onProgress?.({
|
|
1376
|
+
category: "mcp",
|
|
1377
|
+
current: 1,
|
|
1378
|
+
total: 1,
|
|
1379
|
+
item: "mcp.json",
|
|
1380
|
+
status: "importing"
|
|
1381
|
+
});
|
|
1382
|
+
try {
|
|
1383
|
+
const mcpData = await this.safeReadJson(mcpPath);
|
|
1384
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1385
|
+
await fse5.ensureDir(configDir);
|
|
1386
|
+
await fse5.writeJson(
|
|
1387
|
+
path5.join(configDir, "imported-cursor-mcp.json"),
|
|
1388
|
+
{
|
|
1389
|
+
importedFrom: "cursor",
|
|
1390
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1391
|
+
mcpServers: mcpData.mcpServers ?? mcpData
|
|
1392
|
+
},
|
|
1393
|
+
{ spaces: 2 }
|
|
1394
|
+
);
|
|
1395
|
+
imported.set("mcp", { success: 1, failed: 0, skipped: 0 });
|
|
1396
|
+
onProgress?.({
|
|
1397
|
+
category: "mcp",
|
|
1398
|
+
current: 1,
|
|
1399
|
+
total: 1,
|
|
1400
|
+
item: "mcp.json",
|
|
1401
|
+
status: "done"
|
|
1402
|
+
});
|
|
1403
|
+
} catch (err) {
|
|
1404
|
+
imported.set("mcp", { success: 0, failed: 1, skipped: 0 });
|
|
1405
|
+
errors.push({
|
|
1406
|
+
category: "mcp",
|
|
1407
|
+
item: "mcp.json",
|
|
1408
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1409
|
+
retriable: false
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
// src/import/importers/ClineImporter.ts
|
|
1416
|
+
import path6 from "path";
|
|
1417
|
+
import fse6 from "fs-extra";
|
|
1418
|
+
var ClineImporter = class extends BaseImporter {
|
|
1419
|
+
constructor() {
|
|
1420
|
+
super(...arguments);
|
|
1421
|
+
this.name = "cline";
|
|
1422
|
+
this.displayName = "Cline";
|
|
1423
|
+
this.homePath = "~/.cline";
|
|
1424
|
+
}
|
|
1425
|
+
// ---------------------------------------------------------------
|
|
1426
|
+
// scan()
|
|
1427
|
+
// ---------------------------------------------------------------
|
|
1428
|
+
async scan() {
|
|
1429
|
+
const available = /* @__PURE__ */ new Map();
|
|
1430
|
+
const home = this.resolvedHomePath;
|
|
1431
|
+
if (!await fse6.pathExists(home)) {
|
|
1432
|
+
return { source: this.name, available };
|
|
1433
|
+
}
|
|
1434
|
+
const globalStatePath = path6.join(home, "data", "globalState.json");
|
|
1435
|
+
if (await fse6.pathExists(globalStatePath)) {
|
|
1436
|
+
available.set("settings", {
|
|
1437
|
+
count: 1,
|
|
1438
|
+
description: "Cline global state (model preferences, auto-approval, browser settings)"
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
return { source: this.name, available };
|
|
1442
|
+
}
|
|
1443
|
+
// ---------------------------------------------------------------
|
|
1444
|
+
// import()
|
|
1445
|
+
// ---------------------------------------------------------------
|
|
1446
|
+
async import(categories, onProgress) {
|
|
1447
|
+
const start = Date.now();
|
|
1448
|
+
const imported = /* @__PURE__ */ new Map();
|
|
1449
|
+
const errors = [];
|
|
1450
|
+
for (const category of categories) {
|
|
1451
|
+
switch (category) {
|
|
1452
|
+
case "settings":
|
|
1453
|
+
await this.importSettings(imported, errors, onProgress);
|
|
1454
|
+
break;
|
|
1455
|
+
default:
|
|
1456
|
+
break;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return {
|
|
1460
|
+
source: this.name,
|
|
1461
|
+
imported,
|
|
1462
|
+
errors,
|
|
1463
|
+
duration: Date.now() - start
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
// ---------------------------------------------------------------
|
|
1467
|
+
// Settings
|
|
1468
|
+
// ---------------------------------------------------------------
|
|
1469
|
+
async importSettings(imported, errors, onProgress) {
|
|
1470
|
+
const globalStatePath = path6.join(this.resolvedHomePath, "data", "globalState.json");
|
|
1471
|
+
if (!await fse6.pathExists(globalStatePath)) {
|
|
1472
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
onProgress?.({
|
|
1476
|
+
category: "settings",
|
|
1477
|
+
current: 1,
|
|
1478
|
+
total: 1,
|
|
1479
|
+
item: "globalState.json",
|
|
1480
|
+
status: "importing"
|
|
1481
|
+
});
|
|
1482
|
+
try {
|
|
1483
|
+
const state = await this.safeReadJson(globalStatePath);
|
|
1484
|
+
const extracted = {};
|
|
1485
|
+
if (state.apiModelId) extracted.model = state.apiModelId;
|
|
1486
|
+
if (state.autoApprovalSettings) extracted.autoApproval = state.autoApprovalSettings;
|
|
1487
|
+
if (state.browserSettings) extracted.browser = state.browserSettings;
|
|
1488
|
+
if (state.workspaceRoots) extracted.workspaceRoots = state.workspaceRoots;
|
|
1489
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1490
|
+
await fse6.ensureDir(configDir);
|
|
1491
|
+
await fse6.writeJson(
|
|
1492
|
+
path6.join(configDir, "imported-cline-settings.json"),
|
|
1493
|
+
{
|
|
1494
|
+
importedFrom: "cline",
|
|
1495
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1496
|
+
...extracted,
|
|
1497
|
+
raw: state
|
|
1498
|
+
},
|
|
1499
|
+
{ spaces: 2 }
|
|
1500
|
+
);
|
|
1501
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
1502
|
+
onProgress?.({
|
|
1503
|
+
category: "settings",
|
|
1504
|
+
current: 1,
|
|
1505
|
+
total: 1,
|
|
1506
|
+
item: "globalState.json",
|
|
1507
|
+
status: "done"
|
|
1508
|
+
});
|
|
1509
|
+
} catch (err) {
|
|
1510
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
1511
|
+
errors.push({
|
|
1512
|
+
category: "settings",
|
|
1513
|
+
item: "globalState.json",
|
|
1514
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1515
|
+
retriable: false
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1520
|
+
|
|
1521
|
+
// src/import/importers/ContinueImporter.ts
|
|
1522
|
+
import path7 from "path";
|
|
1523
|
+
import fse7 from "fs-extra";
|
|
1524
|
+
var ContinueImporter = class extends BaseImporter {
|
|
1525
|
+
constructor() {
|
|
1526
|
+
super(...arguments);
|
|
1527
|
+
this.name = "continue";
|
|
1528
|
+
this.displayName = "Continue.dev";
|
|
1529
|
+
this.homePath = "~/.continue";
|
|
1530
|
+
}
|
|
1531
|
+
// ---------------------------------------------------------------
|
|
1532
|
+
// scan()
|
|
1533
|
+
// ---------------------------------------------------------------
|
|
1534
|
+
async scan() {
|
|
1535
|
+
const available = /* @__PURE__ */ new Map();
|
|
1536
|
+
const home = this.resolvedHomePath;
|
|
1537
|
+
if (!await fse7.pathExists(home)) {
|
|
1538
|
+
return { source: this.name, available };
|
|
1539
|
+
}
|
|
1540
|
+
const configPath = path7.join(home, "config.json");
|
|
1541
|
+
if (await fse7.pathExists(configPath)) {
|
|
1542
|
+
available.set("settings", {
|
|
1543
|
+
count: 1,
|
|
1544
|
+
description: "Continue.dev config (models, context providers, slash commands, embeddings)"
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
return { source: this.name, available };
|
|
1548
|
+
}
|
|
1549
|
+
// ---------------------------------------------------------------
|
|
1550
|
+
// import()
|
|
1551
|
+
// ---------------------------------------------------------------
|
|
1552
|
+
async import(categories, onProgress) {
|
|
1553
|
+
const start = Date.now();
|
|
1554
|
+
const imported = /* @__PURE__ */ new Map();
|
|
1555
|
+
const errors = [];
|
|
1556
|
+
for (const category of categories) {
|
|
1557
|
+
switch (category) {
|
|
1558
|
+
case "settings":
|
|
1559
|
+
await this.importSettings(imported, errors, onProgress);
|
|
1560
|
+
break;
|
|
1561
|
+
default:
|
|
1562
|
+
break;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return {
|
|
1566
|
+
source: this.name,
|
|
1567
|
+
imported,
|
|
1568
|
+
errors,
|
|
1569
|
+
duration: Date.now() - start
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
// ---------------------------------------------------------------
|
|
1573
|
+
// Settings
|
|
1574
|
+
// ---------------------------------------------------------------
|
|
1575
|
+
async importSettings(imported, errors, onProgress) {
|
|
1576
|
+
const configPath = path7.join(this.resolvedHomePath, "config.json");
|
|
1577
|
+
if (!await fse7.pathExists(configPath)) {
|
|
1578
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
onProgress?.({
|
|
1582
|
+
category: "settings",
|
|
1583
|
+
current: 1,
|
|
1584
|
+
total: 1,
|
|
1585
|
+
item: "config.json",
|
|
1586
|
+
status: "importing"
|
|
1587
|
+
});
|
|
1588
|
+
try {
|
|
1589
|
+
const config = await this.safeReadJson(configPath);
|
|
1590
|
+
const extracted = {
|
|
1591
|
+
importedFrom: "continue",
|
|
1592
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1593
|
+
};
|
|
1594
|
+
if (config.models) extracted.models = config.models;
|
|
1595
|
+
if (config.contextProviders) extracted.contextProviders = config.contextProviders;
|
|
1596
|
+
if (config.slashCommands) extracted.slashCommands = config.slashCommands;
|
|
1597
|
+
if (config.embeddingsProvider) extracted.embeddingsProvider = config.embeddingsProvider;
|
|
1598
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1599
|
+
await fse7.ensureDir(configDir);
|
|
1600
|
+
await fse7.writeJson(
|
|
1601
|
+
path7.join(configDir, "imported-continue-settings.json"),
|
|
1602
|
+
extracted,
|
|
1603
|
+
{ spaces: 2 }
|
|
1604
|
+
);
|
|
1605
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
1606
|
+
onProgress?.({
|
|
1607
|
+
category: "settings",
|
|
1608
|
+
current: 1,
|
|
1609
|
+
total: 1,
|
|
1610
|
+
item: "config.json",
|
|
1611
|
+
status: "done"
|
|
1612
|
+
});
|
|
1613
|
+
} catch (err) {
|
|
1614
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
1615
|
+
errors.push({
|
|
1616
|
+
category: "settings",
|
|
1617
|
+
item: "config.json",
|
|
1618
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1619
|
+
retriable: false
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
// src/import/importers/AugmentImporter.ts
|
|
1626
|
+
import path8 from "path";
|
|
1627
|
+
import fse8 from "fs-extra";
|
|
1628
|
+
var AugmentImporter = class extends BaseImporter {
|
|
1629
|
+
constructor() {
|
|
1630
|
+
super(...arguments);
|
|
1631
|
+
this.name = "augment";
|
|
1632
|
+
this.displayName = "Augment";
|
|
1633
|
+
this.homePath = "~/.augment";
|
|
1634
|
+
}
|
|
1635
|
+
// ---------------------------------------------------------------
|
|
1636
|
+
// scan()
|
|
1637
|
+
// ---------------------------------------------------------------
|
|
1638
|
+
async scan() {
|
|
1639
|
+
const available = /* @__PURE__ */ new Map();
|
|
1640
|
+
const home = this.resolvedHomePath;
|
|
1641
|
+
if (!await fse8.pathExists(home)) {
|
|
1642
|
+
return { source: this.name, available };
|
|
1643
|
+
}
|
|
1644
|
+
const mcpPath = path8.join(home, "mcp.json");
|
|
1645
|
+
if (await fse8.pathExists(mcpPath)) {
|
|
1646
|
+
available.set("mcp", { count: 1, description: "Augment MCP server configurations" });
|
|
1647
|
+
}
|
|
1648
|
+
const settingsPath = path8.join(home, "settings.json");
|
|
1649
|
+
if (await fse8.pathExists(settingsPath)) {
|
|
1650
|
+
available.set("settings", { count: 1, description: "Augment settings" });
|
|
1651
|
+
}
|
|
1652
|
+
return { source: this.name, available };
|
|
1653
|
+
}
|
|
1654
|
+
// ---------------------------------------------------------------
|
|
1655
|
+
// import()
|
|
1656
|
+
// ---------------------------------------------------------------
|
|
1657
|
+
async import(categories, onProgress) {
|
|
1658
|
+
const start = Date.now();
|
|
1659
|
+
const imported = /* @__PURE__ */ new Map();
|
|
1660
|
+
const errors = [];
|
|
1661
|
+
for (const category of categories) {
|
|
1662
|
+
switch (category) {
|
|
1663
|
+
case "mcp":
|
|
1664
|
+
await this.importMcp(imported, errors, onProgress);
|
|
1665
|
+
break;
|
|
1666
|
+
case "settings":
|
|
1667
|
+
await this.importSettings(imported, errors, onProgress);
|
|
1668
|
+
break;
|
|
1669
|
+
default:
|
|
1670
|
+
break;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return {
|
|
1674
|
+
source: this.name,
|
|
1675
|
+
imported,
|
|
1676
|
+
errors,
|
|
1677
|
+
duration: Date.now() - start
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
// ---------------------------------------------------------------
|
|
1681
|
+
// MCP
|
|
1682
|
+
// ---------------------------------------------------------------
|
|
1683
|
+
async importMcp(imported, errors, onProgress) {
|
|
1684
|
+
const mcpPath = path8.join(this.resolvedHomePath, "mcp.json");
|
|
1685
|
+
if (!await fse8.pathExists(mcpPath)) {
|
|
1686
|
+
imported.set("mcp", { success: 0, failed: 0, skipped: 1 });
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
onProgress?.({
|
|
1690
|
+
category: "mcp",
|
|
1691
|
+
current: 1,
|
|
1692
|
+
total: 1,
|
|
1693
|
+
item: "mcp.json",
|
|
1694
|
+
status: "importing"
|
|
1695
|
+
});
|
|
1696
|
+
try {
|
|
1697
|
+
const mcpData = await this.safeReadJson(mcpPath);
|
|
1698
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1699
|
+
await fse8.ensureDir(configDir);
|
|
1700
|
+
await fse8.writeJson(
|
|
1701
|
+
path8.join(configDir, "imported-augment-mcp.json"),
|
|
1702
|
+
{
|
|
1703
|
+
importedFrom: "augment",
|
|
1704
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1705
|
+
mcpServers: mcpData.mcpServers ?? mcpData
|
|
1706
|
+
},
|
|
1707
|
+
{ spaces: 2 }
|
|
1708
|
+
);
|
|
1709
|
+
imported.set("mcp", { success: 1, failed: 0, skipped: 0 });
|
|
1710
|
+
onProgress?.({
|
|
1711
|
+
category: "mcp",
|
|
1712
|
+
current: 1,
|
|
1713
|
+
total: 1,
|
|
1714
|
+
item: "mcp.json",
|
|
1715
|
+
status: "done"
|
|
1716
|
+
});
|
|
1717
|
+
} catch (err) {
|
|
1718
|
+
imported.set("mcp", { success: 0, failed: 1, skipped: 0 });
|
|
1719
|
+
errors.push({
|
|
1720
|
+
category: "mcp",
|
|
1721
|
+
item: "mcp.json",
|
|
1722
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1723
|
+
retriable: false
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
// ---------------------------------------------------------------
|
|
1728
|
+
// Settings
|
|
1729
|
+
// ---------------------------------------------------------------
|
|
1730
|
+
async importSettings(imported, errors, onProgress) {
|
|
1731
|
+
const settingsPath = path8.join(this.resolvedHomePath, "settings.json");
|
|
1732
|
+
if (!await fse8.pathExists(settingsPath)) {
|
|
1733
|
+
imported.set("settings", { success: 0, failed: 0, skipped: 1 });
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
onProgress?.({
|
|
1737
|
+
category: "settings",
|
|
1738
|
+
current: 1,
|
|
1739
|
+
total: 1,
|
|
1740
|
+
item: "settings.json",
|
|
1741
|
+
status: "importing"
|
|
1742
|
+
});
|
|
1743
|
+
try {
|
|
1744
|
+
const settings = await this.safeReadJson(settingsPath);
|
|
1745
|
+
const configDir = AUTOHAND_PATHS.config;
|
|
1746
|
+
await fse8.ensureDir(configDir);
|
|
1747
|
+
await fse8.writeJson(
|
|
1748
|
+
path8.join(configDir, "imported-augment-settings.json"),
|
|
1749
|
+
{
|
|
1750
|
+
importedFrom: "augment",
|
|
1751
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1752
|
+
raw: settings
|
|
1753
|
+
},
|
|
1754
|
+
{ spaces: 2 }
|
|
1755
|
+
);
|
|
1756
|
+
imported.set("settings", { success: 1, failed: 0, skipped: 0 });
|
|
1757
|
+
onProgress?.({
|
|
1758
|
+
category: "settings",
|
|
1759
|
+
current: 1,
|
|
1760
|
+
total: 1,
|
|
1761
|
+
item: "settings.json",
|
|
1762
|
+
status: "done"
|
|
1763
|
+
});
|
|
1764
|
+
} catch (err) {
|
|
1765
|
+
imported.set("settings", { success: 0, failed: 1, skipped: 0 });
|
|
1766
|
+
errors.push({
|
|
1767
|
+
category: "settings",
|
|
1768
|
+
item: "settings.json",
|
|
1769
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1770
|
+
retriable: false
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
|
|
1776
|
+
// src/import/registry.ts
|
|
1777
|
+
var ImporterRegistry = class {
|
|
1778
|
+
constructor() {
|
|
1779
|
+
this.importers = /* @__PURE__ */ new Map();
|
|
1780
|
+
this.register(new ClaudeImporter());
|
|
1781
|
+
this.register(new CodexImporter());
|
|
1782
|
+
this.register(new GeminiImporter());
|
|
1783
|
+
this.register(new CursorImporter());
|
|
1784
|
+
this.register(new ClineImporter());
|
|
1785
|
+
this.register(new ContinueImporter());
|
|
1786
|
+
this.register(new AugmentImporter());
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Register an importer instance by its source name.
|
|
1790
|
+
*/
|
|
1791
|
+
register(importer) {
|
|
1792
|
+
this.importers.set(importer.name, importer);
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Get an importer by its source name.
|
|
1796
|
+
* Returns undefined if the source is not registered.
|
|
1797
|
+
*/
|
|
1798
|
+
get(name) {
|
|
1799
|
+
return this.importers.get(name);
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Get all registered importers.
|
|
1803
|
+
*/
|
|
1804
|
+
getAll() {
|
|
1805
|
+
return Array.from(this.importers.values());
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Detect which agent data directories exist on disk.
|
|
1809
|
+
* Runs all detect() calls in parallel for speed.
|
|
1810
|
+
*/
|
|
1811
|
+
async detectAvailable() {
|
|
1812
|
+
const results = await Promise.all(
|
|
1813
|
+
this.getAll().map(async (importer) => ({
|
|
1814
|
+
importer,
|
|
1815
|
+
exists: await importer.detect()
|
|
1816
|
+
}))
|
|
1817
|
+
);
|
|
1818
|
+
return results.filter((r) => r.exists).map((r) => r.importer);
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
export {
|
|
1822
|
+
ImporterRegistry
|
|
1823
|
+
};
|
|
1824
|
+
/**
|
|
1825
|
+
* @license
|
|
1826
|
+
* Copyright 2025 Autohand AI LLC
|
|
1827
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1828
|
+
*/
|