@caspian2026/agent-sdk 0.0.8 → 0.0.9
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/dist/chunk-04h360ha.js +57 -0
- package/dist/{chunk-jmkn11my.js → chunk-04pw5akr.js} +20 -20
- package/dist/{chunk-veap97he.js → chunk-0gpem3pk.js} +46 -45
- package/dist/{chunk-0mej3p7q.js → chunk-0txtpamh.js} +14 -14
- package/dist/{chunk-4m9df5ef.js → chunk-0v89r445.js} +17 -21
- package/dist/chunk-0vp3wfab.js +12 -0
- package/dist/{chunk-268jd0rc.js → chunk-1486qzk5.js} +6 -4
- package/dist/chunk-1efrnkxx.js +468 -0
- package/dist/chunk-1gaw18rz.js +93 -0
- package/dist/{chunk-69r3hm9b.js → chunk-1hqb50ne.js} +13 -19
- package/dist/chunk-1hqvvvrt.js +96 -0
- package/dist/{chunk-qjyg1dv7.js → chunk-1hx5g6qy.js} +6 -10
- package/dist/{chunk-3g1vqhyx.js → chunk-1kmwf4vn.js} +17 -21
- package/dist/{chunk-naybw0p0.js → chunk-1nhnn2rg.js} +8 -8
- package/dist/{chunk-jjh7m5sg.js → chunk-1nvcmzj1.js} +66 -77
- package/dist/{chunk-2f21meep.js → chunk-1v01c96r.js} +1 -1
- package/dist/{chunk-7n51wk9k.js → chunk-1vp22nex.js} +2 -2
- package/dist/{chunk-jcwkgtbp.js → chunk-1yfc1d48.js} +52 -90
- package/dist/{chunk-83e71kz6.js → chunk-2072dpbx.js} +2 -2
- package/dist/{chunk-7rnqsng2.js → chunk-22mfb6bp.js} +19 -19
- package/dist/{chunk-d7886r6a.js → chunk-26wtxbdc.js} +7774 -7774
- package/dist/{chunk-x94btg29.js → chunk-2m32xn94.js} +17 -21
- package/dist/{chunk-mw1kpeg9.js → chunk-2nrarbza.js} +1909 -1377
- package/dist/chunk-2vbash3m.js +331 -0
- package/dist/{chunk-c11swzas.js → chunk-2vteceqh.js} +5 -5
- package/dist/{chunk-3zxswxtg.js → chunk-2y8x7xt7.js} +2 -2
- package/dist/{chunk-s7q42kp2.js → chunk-2yxqz99n.js} +9 -9
- package/dist/{chunk-qyqpb15f.js → chunk-35nft36d.js} +205 -261
- package/dist/{chunk-88xc4d7f.js → chunk-35z2vxep.js} +49 -48
- package/dist/{chunk-15m49c67.js → chunk-3e28fvn0.js} +2 -2
- package/dist/{chunk-2xvc97x4.js → chunk-3e4r5pmc.js} +3 -3
- package/dist/{chunk-a3ws4gae.js → chunk-3fn3ysvs.js} +47 -46
- package/dist/{chunk-4hv90qcz.js → chunk-3mgywd32.js} +1 -1
- package/dist/{chunk-pwqm47kn.js → chunk-3npsy4c4.js} +46 -45
- package/dist/{chunk-xz655xxa.js → chunk-3pzwd6qq.js} +2 -2
- package/dist/{chunk-70eey1nh.js → chunk-40s88wdg.js} +2 -2
- package/dist/{chunk-w0gmf6bv.js → chunk-42a0nyrq.js} +47 -46
- package/dist/{chunk-jvmybb06.js → chunk-44t1xk05.js} +46 -45
- package/dist/{chunk-0awwmrwr.js → chunk-4ayjwyqj.js} +2 -2
- package/dist/{chunk-a4npwxvb.js → chunk-4myad919.js} +46 -45
- package/dist/{chunk-8g747a8x.js → chunk-4pbx3g7s.js} +1 -1
- package/dist/chunk-4vtvwg7e.js +99 -0
- package/dist/{chunk-qcnhb4cd.js → chunk-54wn2jdr.js} +3 -3
- package/dist/{chunk-1nk93fqz.js → chunk-5cxjxxx8.js} +2 -7
- package/dist/chunk-5m3m7hr5.js +108 -0
- package/dist/{chunk-a3wczqrp.js → chunk-5mrc0ps5.js} +37 -41
- package/dist/{chunk-zmra45az.js → chunk-5tw3gj5z.js} +47 -46
- package/dist/{chunk-87e209aj.js → chunk-5zcygjb2.js} +46 -45
- package/dist/{chunk-mk1y74w7.js → chunk-65q3hqkw.js} +17 -21
- package/dist/{chunk-vajwapkf.js → chunk-67wms97m.js} +17 -23
- package/dist/chunk-6cfcqjty.js +441 -0
- package/dist/{chunk-rc9x0raa.js → chunk-6hs0cptm.js} +56 -55
- package/dist/{chunk-bmbq6nt1.js → chunk-6wzg2hpc.js} +2 -2
- package/dist/chunk-72qa16xm.js +91 -0
- package/dist/chunk-7cdy4aj6.js +150 -0
- package/dist/chunk-7cje7scj.js +1534 -0
- package/dist/{chunk-e7h4qxgw.js → chunk-7etkb4pr.js} +4 -4
- package/dist/{chunk-1ax1znzj.js → chunk-7hrmxpha.js} +6 -6
- package/dist/{chunk-wha6v7za.js → chunk-7krg0dkt.js} +2 -2
- package/dist/{chunk-vvsbvz2b.js → chunk-7skyagc2.js} +2 -2
- package/dist/{chunk-hzknr99c.js → chunk-83b2frat.js} +4 -4
- package/dist/{chunk-qvd3hbqs.js → chunk-84cdy41j.js} +5 -5
- package/dist/{chunk-bxcfz5gy.js → chunk-87xg6yb4.js} +1 -1
- package/dist/{chunk-nrtksr2p.js → chunk-8b2y3x7a.js} +1 -1
- package/dist/{chunk-c9dmpdss.js → chunk-8ckwc9k8.js} +46 -45
- package/dist/{chunk-67a4147x.js → chunk-8jy18nx9.js} +1 -1
- package/dist/{chunk-f2hbn5rk.js → chunk-93vwm44t.js} +100420 -57118
- package/dist/{chunk-cfgha78n.js → chunk-9957ffjc.js} +2 -2
- package/dist/{chunk-cdj51xbj.js → chunk-9byfzaeq.js} +46 -45
- package/dist/chunk-9ewnsd7f.js +31 -0
- package/dist/{chunk-xwg327ys.js → chunk-9w114071.js} +6 -6
- package/dist/chunk-9wf3fc4t.js +29 -0
- package/dist/chunk-9z9teq7p.js +87 -0
- package/dist/{chunk-6p4cyhb3.js → chunk-a6d2q415.js} +2 -2
- package/dist/{chunk-jgzxmtpf.js → chunk-ay5fvc2r.js} +52 -52
- package/dist/{chunk-1ybvj5df.js → chunk-ayx9aq2k.js} +47 -46
- package/dist/{chunk-23fkapww.js → chunk-azv68vk1.js} +2 -2
- package/dist/chunk-b547q41s.js +92 -0
- package/dist/{chunk-jgjqa49s.js → chunk-b56smerd.js} +3 -3
- package/dist/{chunk-enkdxqas.js → chunk-b5asw4tj.js} +6 -6
- package/dist/{chunk-nk82j7r2.js → chunk-b6prbsae.js} +7 -7
- package/dist/{chunk-ya40p6vj.js → chunk-b89ese8r.js} +46 -45
- package/dist/{chunk-byb2mn1c.js → chunk-be77bcs8.js} +118 -450
- package/dist/{chunk-m46xyqr6.js → chunk-bf03a1w7.js} +48 -47
- package/dist/{chunk-dmqeqxfz.js → chunk-bjdknxqn.js} +46 -45
- package/dist/{chunk-m87bhhqv.js → chunk-bzatg35k.js} +1 -1
- package/dist/{chunk-8ybw2s0h.js → chunk-c4d52460.js} +4 -4
- package/dist/{chunk-6g5qbbxk.js → chunk-c5zkrd7r.js} +47 -46
- package/dist/{chunk-4140c8xy.js → chunk-c6hsz5ey.js} +20 -24
- package/dist/{chunk-wqvr37xp.js → chunk-cay13mxk.js} +15 -31
- package/dist/{chunk-s3hsqf80.js → chunk-cexw1jmv.js} +30 -81
- package/dist/{chunk-cvm2tmwg.js → chunk-ckh4f9ry.js} +20 -24
- package/dist/{chunk-qn8z4r79.js → chunk-cr1dv2js.js} +50 -48
- package/dist/{chunk-88cekjja.js → chunk-d8z7pyrb.js} +47 -46
- package/dist/chunk-dexkgxt4.js +211 -0
- package/dist/{chunk-xxw9a0bq.js → chunk-dhwr4fz4.js} +2 -2
- package/dist/{chunk-0ym2z0c7.js → chunk-dj7d67ya.js} +1 -1
- package/dist/chunk-djfq8ws0.js +124 -0
- package/dist/{chunk-x2pvw7xw.js → chunk-dmyedkpw.js} +8 -8
- package/dist/{chunk-v0bykh19.js → chunk-dngfdsm9.js} +108 -102
- package/dist/{chunk-8nfn89nz.js → chunk-dt3epnwj.js} +9 -9
- package/dist/{chunk-4r50c14n.js → chunk-dz6zxh89.js} +46 -45
- package/dist/{chunk-jh965sa0.js → chunk-e7ag583m.js} +47 -46
- package/dist/{chunk-th4y838y.js → chunk-ec6ga5ey.js} +51 -50
- package/dist/{chunk-4g0nj78p.js → chunk-ecbh4n6q.js} +46 -45
- package/dist/{chunk-ydcsbj4t.js → chunk-ecv9kbtk.js} +11 -9
- package/dist/{chunk-nvwwtq1w.js → chunk-ecvy1ng2.js} +49 -48
- package/dist/{chunk-s4zb3f1b.js → chunk-ef2m4xyz.js} +46 -45
- package/dist/{chunk-psnsve7m.js → chunk-etbb3dss.js} +49 -48
- package/dist/{chunk-jgpmpgx6.js → chunk-etdt1xz3.js} +1 -1
- package/dist/{chunk-jxfp3g9b.js → chunk-ev7h351p.js} +4 -4
- package/dist/{chunk-njxgct8f.js → chunk-ey0n4emm.js} +46 -45
- package/dist/{chunk-af868wet.js → chunk-f4tdn7yr.js} +46 -45
- package/dist/{chunk-bd5sqj86.js → chunk-f4v7t54y.js} +11 -11
- package/dist/{chunk-8ywngxqt.js → chunk-fesvrjhd.js} +10 -10
- package/dist/{chunk-j4m8fd76.js → chunk-frm7mphm.js} +7 -11
- package/dist/{chunk-kek5v6ef.js → chunk-frwznxnf.js} +3 -3
- package/dist/{chunk-030rqd3a.js → chunk-ftsdm7y7.js} +54 -53
- package/dist/{chunk-vdcm8hz6.js → chunk-g597bz1j.js} +47 -46
- package/dist/chunk-g5pe8dew.js +25 -0
- package/dist/{chunk-tvzr9c8a.js → chunk-g78fetxa.js} +46 -45
- package/dist/{chunk-ga86yjm1.js → chunk-gdwdqewd.js} +3 -3
- package/dist/{chunk-dvcwahst.js → chunk-ghwvqhx9.js} +51 -50
- package/dist/chunk-gkn3jgqn.js +123 -0
- package/dist/{chunk-23q4jpn2.js → chunk-grqhgr2b.js} +3 -3
- package/dist/chunk-grqkx44z.js +90 -0
- package/dist/{chunk-21jsjcfa.js → chunk-gzj94jgg.js} +46 -45
- package/dist/{chunk-g5pgham9.js → chunk-h3vyya5n.js} +20 -14
- package/dist/{chunk-15edybe0.js → chunk-h4xfadhf.js} +1 -1
- package/dist/chunk-h61d4awv.js +95 -0
- package/dist/{chunk-w05jpkkr.js → chunk-hae34yd0.js} +5 -9
- package/dist/{chunk-rtmh0v4c.js → chunk-hb1gr101.js} +6 -6
- package/dist/{chunk-5a5w0ygx.js → chunk-hg45r671.js} +2 -2
- package/dist/{chunk-d9yghsfg.js → chunk-hg6fwhj1.js} +1 -1
- package/dist/{chunk-1cq2vrzq.js → chunk-hgmhngje.js} +4 -4
- package/dist/{chunk-vvjgdzhn.js → chunk-hparkfvt.js} +55 -51
- package/dist/{chunk-ahrhwpm9.js → chunk-hqjdgc6c.js} +2 -2
- package/dist/{chunk-37p5p94r.js → chunk-hrhp26d7.js} +55 -54
- package/dist/{chunk-xrpstt41.js → chunk-hzbr9543.js} +4 -4
- package/dist/{chunk-1dwvgrfc.js → chunk-j0gke393.js} +46 -45
- package/dist/{chunk-yyf72f78.js → chunk-j35mw64g.js} +4 -2
- package/dist/{chunk-425w66ka.js → chunk-j99ms5ep.js} +4 -4
- package/dist/{chunk-dtgh4te6.js → chunk-jgvmjwnx.js} +46 -45
- package/dist/{chunk-87scz097.js → chunk-jj4zs4gr.js} +46 -45
- package/dist/{chunk-am3qcgzp.js → chunk-jjz3hs34.js} +56 -55
- package/dist/{chunk-1a6ez1mg.js → chunk-jksf0ax9.js} +51 -49
- package/dist/{chunk-gdhz1652.js → chunk-jqfrz5g9.js} +27 -30
- package/dist/{chunk-q7jnesv8.js → chunk-jsj3fx0g.js} +5 -5
- package/dist/{chunk-vawgyev5.js → chunk-jtgyzqbq.js} +3 -3
- package/dist/{chunk-xfkfh5sd.js → chunk-jwpp2bq2.js} +1808 -1643
- package/dist/{chunk-zq6ezxh2.js → chunk-jwwpfq76.js} +49 -45
- package/dist/{chunk-qq5d2s0d.js → chunk-jxp2j9t5.js} +46 -45
- package/dist/{chunk-zctfbr1v.js → chunk-k7cw1a8a.js} +1 -1
- package/dist/chunk-k8jpbz31.js +62 -0
- package/dist/{chunk-tdbz9gbm.js → chunk-kjqyhxz7.js} +6 -6
- package/dist/{chunk-yc23zxmj.js → chunk-kxrrtr3p.js} +1 -1
- package/dist/chunk-m70n19dz.js +93 -0
- package/dist/{chunk-4nspekjp.js → chunk-mcws22k3.js} +1 -28
- package/dist/{chunk-a1bf2kh4.js → chunk-mewywsar.js} +46 -45
- package/dist/{chunk-k7g9gcr9.js → chunk-mmhkcj7c.js} +64 -58
- package/dist/{chunk-rm2vtv77.js → chunk-msxggy37.js} +22 -25
- package/dist/{chunk-s1tg295x.js → chunk-njw0haha.js} +10 -8
- package/dist/{chunk-5rv9c8yd.js → chunk-nrjtxhyr.js} +1 -1
- package/dist/{chunk-nqn45znr.js → chunk-ns7x6xam.js} +9 -9
- package/dist/{chunk-jaaxk89e.js → chunk-nsc89h0n.js} +2 -22
- package/dist/{chunk-z19sd3bt.js → chunk-p4196wzm.js} +5 -5
- package/dist/{chunk-1dgdjrm1.js → chunk-p791ydbm.js} +4 -4
- package/dist/{chunk-1zhy5cbc.js → chunk-p9ny0p2a.js} +13 -13
- package/dist/{chunk-phd1qfpc.js → chunk-pd2vy8hx.js} +5 -5
- package/dist/{chunk-gnj7tyj6.js → chunk-pddf0719.js} +49 -48
- package/dist/{chunk-6t5zvnrg.js → chunk-pfarypfq.js} +48 -46
- package/dist/{chunk-w4yn8cq7.js → chunk-psm26hv7.js} +8 -8
- package/dist/{chunk-hwn8vetn.js → chunk-pwpk3gm6.js} +10 -10
- package/dist/{chunk-va8drjmv.js → chunk-q14wrksq.js} +48 -47
- package/dist/{chunk-twqzmqsn.js → chunk-q4f1g9y6.js} +31 -27
- package/dist/{chunk-23jzrwsw.js → chunk-q6tdxy8v.js} +5 -5
- package/dist/chunk-q8hxwh48.js +445 -0
- package/dist/{chunk-eenq3avg.js → chunk-qcrpqjya.js} +1 -1
- package/dist/{chunk-e7efcp3k.js → chunk-qctsv1d7.js} +257 -2857
- package/dist/{chunk-ck0ap688.js → chunk-qkczt8cr.js} +4 -4
- package/dist/{chunk-2fxpd35d.js → chunk-qkp4ygnk.js} +2 -2
- package/dist/{chunk-c3d2cnz5.js → chunk-qqs58ywv.js} +7 -7
- package/dist/{chunk-qdnxk7d7.js → chunk-qxjhw1dt.js} +29 -30
- package/dist/{chunk-rkg741k3.js → chunk-qz0xdht6.js} +14 -14
- package/dist/chunk-r3ehjkj5.js +123 -0
- package/dist/{chunk-wbbykfdd.js → chunk-r5nd93kc.js} +1 -1
- package/dist/{chunk-yzcjz0gg.js → chunk-r6nnp8mj.js} +46 -45
- package/dist/{chunk-bm5rc541.js → chunk-r7684mmh.js} +5 -5
- package/dist/chunk-ratnrv9v.js +517 -0
- package/dist/{chunk-nx7c354z.js → chunk-rfbbcx5s.js} +46 -45
- package/dist/{chunk-z9n0183s.js → chunk-rfq9kmsy.js} +9 -9
- package/dist/{chunk-qsc98gbe.js → chunk-rhvn1rqs.js} +2 -2
- package/dist/{chunk-gvrjgq1n.js → chunk-rjq5nf1c.js} +16 -20
- package/dist/{chunk-xp61y5ba.js → chunk-rkv8bdtr.js} +2 -2
- package/dist/{chunk-tff58196.js → chunk-rmpaj37q.js} +48 -47
- package/dist/{chunk-k1crm94z.js → chunk-rn1s097c.js} +46 -45
- package/dist/{chunk-c42pqnxx.js → chunk-rnxpvm3m.js} +1 -1
- package/dist/{chunk-k0v0cz71.js → chunk-rpsqtvkx.js} +46 -45
- package/dist/{chunk-t5vbqd9d.js → chunk-rx4mcfg1.js} +55 -54
- package/dist/{chunk-30smv00b.js → chunk-rygxwjtc.js} +47 -46
- package/dist/{chunk-jpc9zwsk.js → chunk-rz94yg8c.js} +3 -3
- package/dist/{chunk-0m9w9esf.js → chunk-s19b0bc7.js} +46 -45
- package/dist/{chunk-wayfjcwt.js → chunk-sdfvr9ps.js} +4 -4
- package/dist/{chunk-fkhs3myp.js → chunk-sh2v9ywv.js} +5 -3
- package/dist/{chunk-1avzakfd.js → chunk-sjpqw47t.js} +3 -3
- package/dist/{chunk-7mqab3z7.js → chunk-skp5w8bq.js} +1 -1
- package/dist/{chunk-76j2e9vy.js → chunk-snxp8mxj.js} +2 -2
- package/dist/{chunk-vsqwd13w.js → chunk-ssb4wba6.js} +17 -19
- package/dist/{chunk-kva79cra.js → chunk-szzff973.js} +7 -5
- package/dist/{chunk-st73prx0.js → chunk-t1pygy19.js} +47 -46
- package/dist/{chunk-q1ah9nbq.js → chunk-t1s91wrk.js} +1 -1
- package/dist/{chunk-3skj4gfg.js → chunk-t3gmfcy7.js} +47 -46
- package/dist/{chunk-xw8pjerk.js → chunk-t9eeyrkn.js} +48 -47
- package/dist/{chunk-0jtbeesf.js → chunk-tf859h88.js} +16 -20
- package/dist/{chunk-denyma1s.js → chunk-thenr6b3.js} +14 -12
- package/dist/{chunk-234668cb.js → chunk-thmtkfgj.js} +5 -5
- package/dist/chunk-tj7v47cp.js +20 -0
- package/dist/{chunk-12k745vf.js → chunk-tpk67mjc.js} +3 -3
- package/dist/chunk-trvc6jh7.js +92 -0
- package/dist/{chunk-9v13f3gm.js → chunk-ttyfhx12.js} +524 -195
- package/dist/{chunk-q87kegxh.js → chunk-txgbs4hp.js} +49 -48
- package/dist/{chunk-25bwa70y.js → chunk-ty1cyqr7.js} +49 -48
- package/dist/{chunk-r6kaak61.js → chunk-v0tgjdx0.js} +16 -20
- package/dist/chunk-v3s93bzd.js +34 -0
- package/dist/{chunk-4cp6193g.js → chunk-v4t6dyyh.js} +2 -2
- package/dist/{chunk-fape0yfp.js → chunk-v4wba09w.js} +46 -45
- package/dist/{chunk-h02gcdx5.js → chunk-v5g8nf5h.js} +8 -8
- package/dist/{chunk-jtztm8f5.js → chunk-v6hbqcmr.js} +44 -43
- package/dist/{chunk-21gmrwhs.js → chunk-vajsk9ya.js} +17 -21
- package/dist/{chunk-8hpq2659.js → chunk-vbtm9g57.js} +1 -1
- package/dist/{chunk-q7e0106d.js → chunk-vk3nb2xe.js} +51 -56
- package/dist/{chunk-ad3v6mzw.js → chunk-vmbht6ec.js} +12 -12
- package/dist/{chunk-as5rvw4n.js → chunk-vmp5rk8q.js} +17 -21
- package/dist/{chunk-1x0y4426.js → chunk-vtmxgm1m.js} +4 -4
- package/dist/{chunk-pb92bj1h.js → chunk-vw5jzpcm.js} +6 -6
- package/dist/{chunk-5cem2v7n.js → chunk-vyz3v0qx.js} +5 -5
- package/dist/{chunk-hxzt3r84.js → chunk-w3782jck.js} +51 -50
- package/dist/{chunk-1vnd9s2j.js → chunk-w3gnkyfc.js} +57 -66
- package/dist/chunk-w6mcmmt5.js +1457 -0
- package/dist/chunk-wa0xgm6m.js +988 -0
- package/dist/{chunk-vrjbc8ap.js → chunk-wa8yn2p0.js} +1 -1
- package/dist/{chunk-hya4c599.js → chunk-wg47eg7y.js} +46 -45
- package/dist/{chunk-y7we499r.js → chunk-wgd4n1q7.js} +8 -8
- package/dist/{chunk-0g5cy3wj.js → chunk-wgk9sxk7.js} +4 -4
- package/dist/{chunk-wr3pd88n.js → chunk-wkt2q02c.js} +40 -9
- package/dist/{chunk-gbte7d7h.js → chunk-wm1zm5xj.js} +4 -2
- package/dist/{chunk-3hwa20vg.js → chunk-wtpgjmjd.js} +49 -46
- package/dist/{chunk-dbwmzvfj.js → chunk-wxkrq9eb.js} +46 -45
- package/dist/{chunk-d00mfc1e.js → chunk-x2bnzvd6.js} +46 -45
- package/dist/{chunk-2xbyb015.js → chunk-x3jthbjq.js} +47 -46
- package/dist/chunk-x7fdwq3d.js +33 -0
- package/dist/{chunk-zhk465tg.js → chunk-xcrzgyce.js} +46 -45
- package/dist/{chunk-chsyvavm.js → chunk-xeb6075z.js} +1 -1
- package/dist/{chunk-6ksdp40n.js → chunk-xffb3dsw.js} +1 -1
- package/dist/{chunk-2j3v2dgk.js → chunk-xgbd6ec5.js} +47 -46
- package/dist/{chunk-n7pnyq43.js → chunk-xhfmdq1y.js} +16 -0
- package/dist/{chunk-2v4x8kaq.js → chunk-xhn4ptjn.js} +51 -50
- package/dist/{chunk-w1sv7j01.js → chunk-xs7zsmzk.js} +46 -45
- package/dist/chunk-xswyz2es.js +118 -0
- package/dist/{chunk-ky39hkg1.js → chunk-xtdm6ejq.js} +9 -7
- package/dist/{chunk-hh3k5s1s.js → chunk-xvk90wpt.js} +3 -3
- package/dist/{chunk-5awgsvrw.js → chunk-xw99fqv1.js} +14 -6
- package/dist/{chunk-xnv6kb39.js → chunk-y32em34x.js} +22 -23
- package/dist/chunk-y5wfy524.js +94 -0
- package/dist/{chunk-fk8crdnk.js → chunk-ya9dxex0.js} +48 -46
- package/dist/{chunk-97wgdsab.js → chunk-z16txqz0.js} +3 -3
- package/dist/{chunk-yvtzznds.js → chunk-z6wm96eh.js} +2 -2
- package/dist/{chunk-nqrc7pc4.js → chunk-zcgprbyy.js} +29 -27
- package/dist/chunk-zqbnw3n2.js +197 -0
- package/dist/{chunk-d6rypdxt.js → chunk-zxywawr7.js} +1 -1
- package/dist/{chunk-jj5wj46b.js → chunk-zyjkg76f.js} +7 -7
- package/dist/cli.js +8 -8
- package/dist/gateway/index.js +326 -0
- package/dist/gateway/worker.js +482241 -0
- package/package.json +1 -1
- package/dist/chunk-11cz07kz.js +0 -93
- package/dist/chunk-1pbtp2z2.js +0 -92
- package/dist/chunk-25y2dtzf.js +0 -91
- package/dist/chunk-3hyj0zpy.js +0 -95
- package/dist/chunk-4kqjjakw.js +0 -73
- package/dist/chunk-4zwqbg7s.js +0 -87
- package/dist/chunk-5be33wja.js +0 -120
- package/dist/chunk-70mgxhkz.js +0 -369
- package/dist/chunk-7gmk09cq.js +0 -116
- package/dist/chunk-8dprcdra.js +0 -92
- package/dist/chunk-8xwx1xtg.js +0 -120
- package/dist/chunk-a579wjd2.js +0 -436
- package/dist/chunk-axqk3mxk.js +0 -116
- package/dist/chunk-c0ckmxr1.js +0 -86
- package/dist/chunk-c6t24y8q.js +0 -94
- package/dist/chunk-cfv996bs.js +0 -22
- package/dist/chunk-e5t5eefc.js +0 -62
- package/dist/chunk-eyph0250.js +0 -88
- package/dist/chunk-f825x57v.js +0 -91
- package/dist/chunk-h9xx5bj6.js +0 -91
- package/dist/chunk-j1dg659r.js +0 -89
- package/dist/chunk-jk8seqkk.js +0 -90
- package/dist/chunk-jzg4nddc.js +0 -92
- package/dist/chunk-k5vy0s3c.js +0 -93
- package/dist/chunk-ke820fjw.js +0 -91
- package/dist/chunk-kyzd4p8z.js +0 -111
- package/dist/chunk-njrt3tac.js +0 -640
- package/dist/chunk-pavb6a7w.js +0 -516
- package/dist/chunk-q268gpa0.js +0 -145
- package/dist/chunk-qvh1w3t7.js +0 -157
- package/dist/chunk-qy1es4jj.js +0 -95
- package/dist/chunk-qz2x630m.js +0 -49145
- package/dist/chunk-tw48evtr.js +0 -40
- package/dist/chunk-w0gfctyc.js +0 -117
- package/dist/chunk-y0fhjxef.js +0 -276
- package/dist/chunk-y275vgmw.js +0 -654
- package/dist/chunk-zq7pmdas.js +0 -1003
|
@@ -0,0 +1,1457 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
acquireProcessLifetimeLock,
|
|
4
|
+
cleanupStaleLocks,
|
|
5
|
+
filterClaudeAliases,
|
|
6
|
+
getCurrentInstallationType,
|
|
7
|
+
getShellConfigPaths,
|
|
8
|
+
getShellType,
|
|
9
|
+
init_doctorDiagnostic,
|
|
10
|
+
init_localInstaller,
|
|
11
|
+
init_pidLock,
|
|
12
|
+
init_shellConfig,
|
|
13
|
+
isLockActive,
|
|
14
|
+
isPidBasedLockingEnabled,
|
|
15
|
+
readFileLines,
|
|
16
|
+
readLockContent,
|
|
17
|
+
withLock,
|
|
18
|
+
writeFileLines
|
|
19
|
+
} from "./chunk-wa0xgm6m.js";
|
|
20
|
+
import {
|
|
21
|
+
getUserBinDir,
|
|
22
|
+
getXDGCacheHome,
|
|
23
|
+
getXDGDataHome,
|
|
24
|
+
getXDGStateHome,
|
|
25
|
+
init_xdg
|
|
26
|
+
} from "./chunk-x7fdwq3d.js";
|
|
27
|
+
import {
|
|
28
|
+
envDynamic,
|
|
29
|
+
init_envDynamic
|
|
30
|
+
} from "./chunk-93vwm44t.js";
|
|
31
|
+
import {
|
|
32
|
+
gt,
|
|
33
|
+
gte,
|
|
34
|
+
init_semver
|
|
35
|
+
} from "./chunk-ps49ymvj.js";
|
|
36
|
+
import {
|
|
37
|
+
getGlobalConfig,
|
|
38
|
+
init_config,
|
|
39
|
+
saveGlobalConfig
|
|
40
|
+
} from "./chunk-qctsv1d7.js";
|
|
41
|
+
import {
|
|
42
|
+
check,
|
|
43
|
+
init_lockfile,
|
|
44
|
+
lock
|
|
45
|
+
} from "./chunk-6nsd9606.js";
|
|
46
|
+
import {
|
|
47
|
+
init_sleep,
|
|
48
|
+
sleep
|
|
49
|
+
} from "./chunk-8g5pe1gr.js";
|
|
50
|
+
import {
|
|
51
|
+
env,
|
|
52
|
+
init_env
|
|
53
|
+
} from "./chunk-cexw1jmv.js";
|
|
54
|
+
import {
|
|
55
|
+
init_analytics,
|
|
56
|
+
logEvent
|
|
57
|
+
} from "./chunk-x8d2ehd7.js";
|
|
58
|
+
import {
|
|
59
|
+
execFileNoThrowWithCwd,
|
|
60
|
+
init_execFileNoThrow
|
|
61
|
+
} from "./chunk-40s88wdg.js";
|
|
62
|
+
import {
|
|
63
|
+
init_log,
|
|
64
|
+
logError
|
|
65
|
+
} from "./chunk-5cxjxxx8.js";
|
|
66
|
+
import {
|
|
67
|
+
errorMessage,
|
|
68
|
+
getErrnoCode,
|
|
69
|
+
getFsImplementation,
|
|
70
|
+
init_cleanupRegistry,
|
|
71
|
+
init_debug,
|
|
72
|
+
init_errors,
|
|
73
|
+
init_fsOperations,
|
|
74
|
+
init_slowOperations,
|
|
75
|
+
isENOENT,
|
|
76
|
+
jsonStringify,
|
|
77
|
+
logForDebugging,
|
|
78
|
+
registerCleanup,
|
|
79
|
+
toError,
|
|
80
|
+
writeFileSync_DEPRECATED
|
|
81
|
+
} from "./chunk-pd2vy8hx.js";
|
|
82
|
+
import {
|
|
83
|
+
init_envUtils,
|
|
84
|
+
isEnvTruthy
|
|
85
|
+
} from "./chunk-nsc89h0n.js";
|
|
86
|
+
import {
|
|
87
|
+
axios_default,
|
|
88
|
+
init_axios
|
|
89
|
+
} from "./chunk-55raexh7.js";
|
|
90
|
+
import {
|
|
91
|
+
__esm
|
|
92
|
+
} from "./chunk-qp2qdcda.js";
|
|
93
|
+
|
|
94
|
+
// src/utils/nativeInstaller/download.ts
|
|
95
|
+
import { createHash } from "crypto";
|
|
96
|
+
import { chmod, writeFile } from "fs/promises";
|
|
97
|
+
import { join } from "path";
|
|
98
|
+
async function getLatestVersionFromArtifactory(tag = "latest") {
|
|
99
|
+
const startTime = Date.now();
|
|
100
|
+
const { stdout, code, stderr } = await execFileNoThrowWithCwd("npm", [
|
|
101
|
+
"view",
|
|
102
|
+
`${""}@${tag}`,
|
|
103
|
+
"version",
|
|
104
|
+
"--prefer-online",
|
|
105
|
+
"--registry",
|
|
106
|
+
ARTIFACTORY_REGISTRY_URL
|
|
107
|
+
], {
|
|
108
|
+
timeout: 30000,
|
|
109
|
+
preserveOutputOnError: true
|
|
110
|
+
});
|
|
111
|
+
const latencyMs = Date.now() - startTime;
|
|
112
|
+
if (code !== 0) {
|
|
113
|
+
logEvent("tengu_version_check_failure", {
|
|
114
|
+
latency_ms: latencyMs,
|
|
115
|
+
source_npm: true,
|
|
116
|
+
exit_code: code
|
|
117
|
+
});
|
|
118
|
+
const error = new Error(`npm view failed with code ${code}: ${stderr}`);
|
|
119
|
+
logError(error);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
logEvent("tengu_version_check_success", {
|
|
123
|
+
latency_ms: latencyMs,
|
|
124
|
+
source_npm: true
|
|
125
|
+
});
|
|
126
|
+
logForDebugging(`npm view ${""}@${tag} version: ${stdout}`);
|
|
127
|
+
const latestVersion = stdout.trim();
|
|
128
|
+
return latestVersion;
|
|
129
|
+
}
|
|
130
|
+
async function getLatestVersionFromBinaryRepo(channel = "latest", baseUrl, authConfig) {
|
|
131
|
+
const startTime = Date.now();
|
|
132
|
+
try {
|
|
133
|
+
const response = await axios_default.get(`${baseUrl}/${channel}`, {
|
|
134
|
+
timeout: 30000,
|
|
135
|
+
responseType: "text",
|
|
136
|
+
...authConfig
|
|
137
|
+
});
|
|
138
|
+
const latencyMs = Date.now() - startTime;
|
|
139
|
+
logEvent("tengu_version_check_success", {
|
|
140
|
+
latency_ms: latencyMs
|
|
141
|
+
});
|
|
142
|
+
return response.data.trim();
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const latencyMs = Date.now() - startTime;
|
|
145
|
+
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
146
|
+
let httpStatus;
|
|
147
|
+
if (axios_default.isAxiosError(error) && error.response) {
|
|
148
|
+
httpStatus = error.response.status;
|
|
149
|
+
}
|
|
150
|
+
logEvent("tengu_version_check_failure", {
|
|
151
|
+
latency_ms: latencyMs,
|
|
152
|
+
http_status: httpStatus,
|
|
153
|
+
is_timeout: errorMessage2.includes("timeout")
|
|
154
|
+
});
|
|
155
|
+
const fetchError = new Error(`Failed to fetch version from ${baseUrl}/${channel}: ${errorMessage2}`);
|
|
156
|
+
logError(fetchError);
|
|
157
|
+
throw fetchError;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function getLatestVersion(channelOrVersion) {
|
|
161
|
+
if (/^v?\d+\.\d+\.\d+(-\S+)?$/.test(channelOrVersion)) {
|
|
162
|
+
const normalized = channelOrVersion.startsWith("v") ? channelOrVersion.slice(1) : channelOrVersion;
|
|
163
|
+
if (/^99\.99\./.test(normalized) && true) {
|
|
164
|
+
throw new Error(`Version ${normalized} is not available for installation. Use 'stable' or 'latest'.`);
|
|
165
|
+
}
|
|
166
|
+
return normalized;
|
|
167
|
+
}
|
|
168
|
+
const channel = channelOrVersion;
|
|
169
|
+
if (channel !== "stable" && channel !== "latest") {
|
|
170
|
+
throw new Error(`Invalid channel: ${channelOrVersion}. Use 'stable' or 'latest'`);
|
|
171
|
+
}
|
|
172
|
+
if (process.env.USER_TYPE === "ant") {
|
|
173
|
+
const npmTag = channel === "stable" ? "stable" : "latest";
|
|
174
|
+
return getLatestVersionFromArtifactory(npmTag);
|
|
175
|
+
}
|
|
176
|
+
return getLatestVersionFromBinaryRepo(channel, GCS_BUCKET_URL);
|
|
177
|
+
}
|
|
178
|
+
async function downloadVersionFromArtifactory(version, stagingPath) {
|
|
179
|
+
const fs = getFsImplementation();
|
|
180
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
181
|
+
const platform = getPlatform();
|
|
182
|
+
const platformPackageName = `${""}-${platform}`;
|
|
183
|
+
logForDebugging(`Fetching integrity hash for ${platformPackageName}@${version}`);
|
|
184
|
+
const {
|
|
185
|
+
stdout: integrityOutput,
|
|
186
|
+
code,
|
|
187
|
+
stderr
|
|
188
|
+
} = await execFileNoThrowWithCwd("npm", [
|
|
189
|
+
"view",
|
|
190
|
+
`${platformPackageName}@${version}`,
|
|
191
|
+
"dist.integrity",
|
|
192
|
+
"--registry",
|
|
193
|
+
ARTIFACTORY_REGISTRY_URL
|
|
194
|
+
], {
|
|
195
|
+
timeout: 30000,
|
|
196
|
+
preserveOutputOnError: true
|
|
197
|
+
});
|
|
198
|
+
if (code !== 0) {
|
|
199
|
+
throw new Error(`npm view integrity failed with code ${code}: ${stderr}`);
|
|
200
|
+
}
|
|
201
|
+
const integrity = integrityOutput.trim();
|
|
202
|
+
if (!integrity) {
|
|
203
|
+
throw new Error(`Failed to fetch integrity hash for ${platformPackageName}@${version}`);
|
|
204
|
+
}
|
|
205
|
+
logForDebugging(`Got integrity hash for ${platform}: ${integrity}`);
|
|
206
|
+
await fs.mkdir(stagingPath);
|
|
207
|
+
const packageJson = {
|
|
208
|
+
name: "claude-native-installer",
|
|
209
|
+
version: "0.0.1",
|
|
210
|
+
dependencies: {
|
|
211
|
+
[""]: version
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const packageLock = {
|
|
215
|
+
name: "claude-native-installer",
|
|
216
|
+
version: "0.0.1",
|
|
217
|
+
lockfileVersion: 3,
|
|
218
|
+
requires: true,
|
|
219
|
+
packages: {
|
|
220
|
+
"": {
|
|
221
|
+
name: "claude-native-installer",
|
|
222
|
+
version: "0.0.1",
|
|
223
|
+
dependencies: {
|
|
224
|
+
[""]: version
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
[`node_modules/${""}`]: {
|
|
228
|
+
version,
|
|
229
|
+
optionalDependencies: {
|
|
230
|
+
[platformPackageName]: version
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
[`node_modules/${platformPackageName}`]: {
|
|
234
|
+
version,
|
|
235
|
+
integrity
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
writeFileSync_DEPRECATED(join(stagingPath, "package.json"), jsonStringify(packageJson, null, 2), { encoding: "utf8", flush: true });
|
|
240
|
+
writeFileSync_DEPRECATED(join(stagingPath, "package-lock.json"), jsonStringify(packageLock, null, 2), { encoding: "utf8", flush: true });
|
|
241
|
+
const result = await execFileNoThrowWithCwd("npm", ["ci", "--prefer-online", "--registry", ARTIFACTORY_REGISTRY_URL], {
|
|
242
|
+
timeout: 60000,
|
|
243
|
+
preserveOutputOnError: true,
|
|
244
|
+
cwd: stagingPath
|
|
245
|
+
});
|
|
246
|
+
if (result.code !== 0) {
|
|
247
|
+
throw new Error(`npm ci failed with code ${result.code}: ${result.stderr}`);
|
|
248
|
+
}
|
|
249
|
+
logForDebugging(`Successfully downloaded and verified ${""}@${version}`);
|
|
250
|
+
}
|
|
251
|
+
function getStallTimeoutMs() {
|
|
252
|
+
return Number(process.env.CLAUDE_CODE_STALL_TIMEOUT_MS_FOR_TESTING) || DEFAULT_STALL_TIMEOUT_MS;
|
|
253
|
+
}
|
|
254
|
+
async function downloadAndVerifyBinary(binaryUrl, expectedChecksum, binaryPath, requestConfig = {}) {
|
|
255
|
+
let lastError;
|
|
256
|
+
for (let attempt = 1;attempt <= MAX_DOWNLOAD_RETRIES; attempt++) {
|
|
257
|
+
const controller = new AbortController;
|
|
258
|
+
let stallTimer;
|
|
259
|
+
const clearStallTimer = () => {
|
|
260
|
+
if (stallTimer) {
|
|
261
|
+
clearTimeout(stallTimer);
|
|
262
|
+
stallTimer = undefined;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const resetStallTimer = () => {
|
|
266
|
+
clearStallTimer();
|
|
267
|
+
stallTimer = setTimeout((c) => c.abort(), getStallTimeoutMs(), controller);
|
|
268
|
+
};
|
|
269
|
+
try {
|
|
270
|
+
resetStallTimer();
|
|
271
|
+
const response = await axios_default.get(binaryUrl, {
|
|
272
|
+
timeout: 5 * 60000,
|
|
273
|
+
responseType: "arraybuffer",
|
|
274
|
+
signal: controller.signal,
|
|
275
|
+
onDownloadProgress: () => {
|
|
276
|
+
resetStallTimer();
|
|
277
|
+
},
|
|
278
|
+
...requestConfig
|
|
279
|
+
});
|
|
280
|
+
clearStallTimer();
|
|
281
|
+
const hash = createHash("sha256");
|
|
282
|
+
hash.update(response.data);
|
|
283
|
+
const actualChecksum = hash.digest("hex");
|
|
284
|
+
if (actualChecksum !== expectedChecksum) {
|
|
285
|
+
throw new Error(`Checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`);
|
|
286
|
+
}
|
|
287
|
+
await writeFile(binaryPath, Buffer.from(response.data));
|
|
288
|
+
await chmod(binaryPath, 493);
|
|
289
|
+
return;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
clearStallTimer();
|
|
292
|
+
const isStallTimeout = axios_default.isCancel(error);
|
|
293
|
+
if (isStallTimeout) {
|
|
294
|
+
lastError = new StallTimeoutError;
|
|
295
|
+
} else {
|
|
296
|
+
lastError = toError(error);
|
|
297
|
+
}
|
|
298
|
+
if (isStallTimeout && attempt < MAX_DOWNLOAD_RETRIES) {
|
|
299
|
+
logForDebugging(`Download stalled on attempt ${attempt}/${MAX_DOWNLOAD_RETRIES}, retrying...`);
|
|
300
|
+
await sleep(1000);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
throw lastError;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
throw lastError ?? new Error("Download failed after all retries");
|
|
307
|
+
}
|
|
308
|
+
async function downloadVersionFromBinaryRepo(version, stagingPath, baseUrl, authConfig) {
|
|
309
|
+
const fs = getFsImplementation();
|
|
310
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
311
|
+
const platform = getPlatform();
|
|
312
|
+
const startTime = Date.now();
|
|
313
|
+
logEvent("tengu_binary_download_attempt", {});
|
|
314
|
+
let manifest;
|
|
315
|
+
try {
|
|
316
|
+
const manifestResponse = await axios_default.get(`${baseUrl}/${version}/manifest.json`, {
|
|
317
|
+
timeout: 1e4,
|
|
318
|
+
responseType: "json",
|
|
319
|
+
...authConfig
|
|
320
|
+
});
|
|
321
|
+
manifest = manifestResponse.data;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
const latencyMs = Date.now() - startTime;
|
|
324
|
+
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
325
|
+
let httpStatus;
|
|
326
|
+
if (axios_default.isAxiosError(error) && error.response) {
|
|
327
|
+
httpStatus = error.response.status;
|
|
328
|
+
}
|
|
329
|
+
logEvent("tengu_binary_manifest_fetch_failure", {
|
|
330
|
+
latency_ms: latencyMs,
|
|
331
|
+
http_status: httpStatus,
|
|
332
|
+
is_timeout: errorMessage2.includes("timeout")
|
|
333
|
+
});
|
|
334
|
+
logError(new Error(`Failed to fetch manifest from ${baseUrl}/${version}/manifest.json: ${errorMessage2}`));
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
const platformInfo = manifest.platforms[platform];
|
|
338
|
+
if (!platformInfo) {
|
|
339
|
+
logEvent("tengu_binary_platform_not_found", {});
|
|
340
|
+
throw new Error(`Platform ${platform} not found in manifest for version ${version}`);
|
|
341
|
+
}
|
|
342
|
+
const expectedChecksum = platformInfo.checksum;
|
|
343
|
+
const binaryName = getBinaryName(platform);
|
|
344
|
+
const binaryUrl = `${baseUrl}/${version}/${platform}/${binaryName}`;
|
|
345
|
+
await fs.mkdir(stagingPath);
|
|
346
|
+
const binaryPath = join(stagingPath, binaryName);
|
|
347
|
+
try {
|
|
348
|
+
await downloadAndVerifyBinary(binaryUrl, expectedChecksum, binaryPath, authConfig || {});
|
|
349
|
+
const latencyMs = Date.now() - startTime;
|
|
350
|
+
logEvent("tengu_binary_download_success", {
|
|
351
|
+
latency_ms: latencyMs
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
const latencyMs = Date.now() - startTime;
|
|
355
|
+
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
356
|
+
let httpStatus;
|
|
357
|
+
if (axios_default.isAxiosError(error) && error.response) {
|
|
358
|
+
httpStatus = error.response.status;
|
|
359
|
+
}
|
|
360
|
+
logEvent("tengu_binary_download_failure", {
|
|
361
|
+
latency_ms: latencyMs,
|
|
362
|
+
http_status: httpStatus,
|
|
363
|
+
is_timeout: errorMessage2.includes("timeout"),
|
|
364
|
+
is_checksum_mismatch: errorMessage2.includes("Checksum mismatch")
|
|
365
|
+
});
|
|
366
|
+
logError(new Error(`Failed to download binary from ${binaryUrl}: ${errorMessage2}`));
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async function downloadVersion(version, stagingPath) {
|
|
371
|
+
if (false) {}
|
|
372
|
+
if (process.env.USER_TYPE === "ant") {
|
|
373
|
+
await downloadVersionFromArtifactory(version, stagingPath);
|
|
374
|
+
return "npm";
|
|
375
|
+
}
|
|
376
|
+
await downloadVersionFromBinaryRepo(version, stagingPath, GCS_BUCKET_URL);
|
|
377
|
+
return "binary";
|
|
378
|
+
}
|
|
379
|
+
var GCS_BUCKET_URL = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases", ARTIFACTORY_REGISTRY_URL = "https://artifactory.infra.ant.dev/artifactory/api/npm/npm-all/", DEFAULT_STALL_TIMEOUT_MS = 60000, MAX_DOWNLOAD_RETRIES = 3, StallTimeoutError;
|
|
380
|
+
var init_download = __esm(() => {
|
|
381
|
+
init_axios();
|
|
382
|
+
init_analytics();
|
|
383
|
+
init_debug();
|
|
384
|
+
init_errors();
|
|
385
|
+
init_execFileNoThrow();
|
|
386
|
+
init_fsOperations();
|
|
387
|
+
init_log();
|
|
388
|
+
init_sleep();
|
|
389
|
+
init_slowOperations();
|
|
390
|
+
init_installer();
|
|
391
|
+
StallTimeoutError = class StallTimeoutError extends Error {
|
|
392
|
+
constructor() {
|
|
393
|
+
super("Download stalled: no data received for 60 seconds");
|
|
394
|
+
this.name = "StallTimeoutError";
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// src/utils/nativeInstaller/installer.ts
|
|
400
|
+
import { constants as fsConstants } from "fs";
|
|
401
|
+
import {
|
|
402
|
+
access,
|
|
403
|
+
chmod as chmod2,
|
|
404
|
+
copyFile,
|
|
405
|
+
lstat,
|
|
406
|
+
mkdir,
|
|
407
|
+
readdir,
|
|
408
|
+
readlink,
|
|
409
|
+
realpath,
|
|
410
|
+
rename,
|
|
411
|
+
rm,
|
|
412
|
+
rmdir,
|
|
413
|
+
stat,
|
|
414
|
+
symlink,
|
|
415
|
+
unlink,
|
|
416
|
+
writeFile as writeFile2
|
|
417
|
+
} from "fs/promises";
|
|
418
|
+
import { homedir } from "os";
|
|
419
|
+
import { basename, delimiter, dirname, join as join2, resolve } from "path";
|
|
420
|
+
function getPlatform() {
|
|
421
|
+
const os = env.platform;
|
|
422
|
+
const arch = process.arch === "x64" ? "x64" : process.arch === "arm64" ? "arm64" : null;
|
|
423
|
+
if (!arch) {
|
|
424
|
+
const error = new Error(`Unsupported architecture: ${process.arch}`);
|
|
425
|
+
logForDebugging(`Native installer does not support architecture: ${process.arch}`, { level: "error" });
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
if (os === "linux" && envDynamic.isMuslEnvironment()) {
|
|
429
|
+
return `linux-${arch}-musl`;
|
|
430
|
+
}
|
|
431
|
+
return `${os}-${arch}`;
|
|
432
|
+
}
|
|
433
|
+
function getBinaryName(platform) {
|
|
434
|
+
return platform.startsWith("win32") ? "claude.exe" : "claude";
|
|
435
|
+
}
|
|
436
|
+
function getBaseDirectories() {
|
|
437
|
+
const platform = getPlatform();
|
|
438
|
+
const executableName = getBinaryName(platform);
|
|
439
|
+
return {
|
|
440
|
+
versions: join2(getXDGDataHome(), "claude", "versions"),
|
|
441
|
+
staging: join2(getXDGCacheHome(), "claude", "staging"),
|
|
442
|
+
locks: join2(getXDGStateHome(), "claude", "locks"),
|
|
443
|
+
executable: join2(getUserBinDir(), executableName)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
async function isPossibleClaudeBinary(filePath) {
|
|
447
|
+
try {
|
|
448
|
+
const stats = await stat(filePath);
|
|
449
|
+
if (!stats.isFile() || stats.size === 0) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
await access(filePath, fsConstants.X_OK);
|
|
453
|
+
return true;
|
|
454
|
+
} catch {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async function getVersionPaths(version) {
|
|
459
|
+
const dirs = getBaseDirectories();
|
|
460
|
+
const dirsToCreate = [dirs.versions, dirs.staging, dirs.locks];
|
|
461
|
+
await Promise.all(dirsToCreate.map((dir) => mkdir(dir, { recursive: true })));
|
|
462
|
+
const executableParentDir = dirname(dirs.executable);
|
|
463
|
+
await mkdir(executableParentDir, { recursive: true });
|
|
464
|
+
const installPath = join2(dirs.versions, version);
|
|
465
|
+
try {
|
|
466
|
+
await stat(installPath);
|
|
467
|
+
} catch {
|
|
468
|
+
await writeFile2(installPath, "", { encoding: "utf8" });
|
|
469
|
+
}
|
|
470
|
+
return {
|
|
471
|
+
stagingPath: join2(dirs.staging, version),
|
|
472
|
+
installPath
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
async function tryWithVersionLock(versionFilePath, callback, retries = 0) {
|
|
476
|
+
const dirs = getBaseDirectories();
|
|
477
|
+
const lockfilePath = getLockFilePathFromVersionPath(dirs, versionFilePath);
|
|
478
|
+
await mkdir(dirs.locks, { recursive: true });
|
|
479
|
+
if (isPidBasedLockingEnabled()) {
|
|
480
|
+
let attempts = 0;
|
|
481
|
+
const maxAttempts = retries + 1;
|
|
482
|
+
const minTimeout = retries > 0 ? 1000 : 100;
|
|
483
|
+
const maxTimeout = retries > 0 ? 5000 : 500;
|
|
484
|
+
while (attempts < maxAttempts) {
|
|
485
|
+
const success = await withLock(versionFilePath, lockfilePath, async () => {
|
|
486
|
+
try {
|
|
487
|
+
await callback();
|
|
488
|
+
} catch (error) {
|
|
489
|
+
logError(error);
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
if (success) {
|
|
494
|
+
logEvent("tengu_version_lock_acquired", {
|
|
495
|
+
is_pid_based: true,
|
|
496
|
+
is_lifetime_lock: false,
|
|
497
|
+
attempts: attempts + 1
|
|
498
|
+
});
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
attempts++;
|
|
502
|
+
if (attempts < maxAttempts) {
|
|
503
|
+
const timeout = Math.min(minTimeout * Math.pow(2, attempts - 1), maxTimeout);
|
|
504
|
+
await sleep(timeout);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
logEvent("tengu_version_lock_failed", {
|
|
508
|
+
is_pid_based: true,
|
|
509
|
+
is_lifetime_lock: false,
|
|
510
|
+
attempts: maxAttempts
|
|
511
|
+
});
|
|
512
|
+
logLockAcquisitionError(versionFilePath, new Error("Lock held by another process"));
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
let release = null;
|
|
516
|
+
try {
|
|
517
|
+
try {
|
|
518
|
+
release = await lock(versionFilePath, {
|
|
519
|
+
stale: LOCK_STALE_MS,
|
|
520
|
+
retries: {
|
|
521
|
+
retries,
|
|
522
|
+
minTimeout: retries > 0 ? 1000 : 100,
|
|
523
|
+
maxTimeout: retries > 0 ? 5000 : 500
|
|
524
|
+
},
|
|
525
|
+
lockfilePath,
|
|
526
|
+
onCompromised: (err) => {
|
|
527
|
+
logForDebugging(`NON-FATAL: Version lock was compromised during operation: ${err.message}`, { level: "info" });
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
} catch (lockError) {
|
|
531
|
+
logEvent("tengu_version_lock_failed", {
|
|
532
|
+
is_pid_based: false,
|
|
533
|
+
is_lifetime_lock: false
|
|
534
|
+
});
|
|
535
|
+
logLockAcquisitionError(versionFilePath, lockError);
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
await callback();
|
|
540
|
+
logEvent("tengu_version_lock_acquired", {
|
|
541
|
+
is_pid_based: false,
|
|
542
|
+
is_lifetime_lock: false
|
|
543
|
+
});
|
|
544
|
+
return true;
|
|
545
|
+
} catch (error) {
|
|
546
|
+
logError(error);
|
|
547
|
+
throw error;
|
|
548
|
+
}
|
|
549
|
+
} finally {
|
|
550
|
+
if (release) {
|
|
551
|
+
await release();
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async function atomicMoveToInstallPath(stagedBinaryPath, installPath) {
|
|
556
|
+
await mkdir(dirname(installPath), { recursive: true });
|
|
557
|
+
const tempInstallPath = `${installPath}.tmp.${process.pid}.${Date.now()}`;
|
|
558
|
+
try {
|
|
559
|
+
await copyFile(stagedBinaryPath, tempInstallPath);
|
|
560
|
+
await chmod2(tempInstallPath, 493);
|
|
561
|
+
await rename(tempInstallPath, installPath);
|
|
562
|
+
logForDebugging(`Atomically installed binary to ${installPath}`);
|
|
563
|
+
} catch (error) {
|
|
564
|
+
try {
|
|
565
|
+
await unlink(tempInstallPath);
|
|
566
|
+
} catch {}
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function installVersionFromPackage(stagingPath, installPath) {
|
|
571
|
+
try {
|
|
572
|
+
const nodeModulesDir = join2(stagingPath, "node_modules", "@anthropic-ai");
|
|
573
|
+
const entries = await readdir(nodeModulesDir);
|
|
574
|
+
const nativePackage = entries.find((entry) => entry.startsWith("claude-cli-native-"));
|
|
575
|
+
if (!nativePackage) {
|
|
576
|
+
logEvent("tengu_native_install_package_failure", {
|
|
577
|
+
stage_find_package: true,
|
|
578
|
+
error_package_not_found: true
|
|
579
|
+
});
|
|
580
|
+
const error = new Error("Could not find platform-specific native package");
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
583
|
+
const stagedBinaryPath = join2(nodeModulesDir, nativePackage, "cli");
|
|
584
|
+
try {
|
|
585
|
+
await stat(stagedBinaryPath);
|
|
586
|
+
} catch {
|
|
587
|
+
logEvent("tengu_native_install_package_failure", {
|
|
588
|
+
stage_binary_exists: true,
|
|
589
|
+
error_binary_not_found: true
|
|
590
|
+
});
|
|
591
|
+
const error = new Error("Native binary not found in staged package");
|
|
592
|
+
throw error;
|
|
593
|
+
}
|
|
594
|
+
await atomicMoveToInstallPath(stagedBinaryPath, installPath);
|
|
595
|
+
await rm(stagingPath, { recursive: true, force: true });
|
|
596
|
+
logEvent("tengu_native_install_package_success", {});
|
|
597
|
+
} catch (error) {
|
|
598
|
+
const msg = errorMessage(error);
|
|
599
|
+
if (!msg.includes("Could not find platform-specific") && !msg.includes("Native binary not found")) {
|
|
600
|
+
logEvent("tengu_native_install_package_failure", {
|
|
601
|
+
stage_atomic_move: true,
|
|
602
|
+
error_move_failed: true
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
logError(toError(error));
|
|
606
|
+
throw error;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
async function installVersionFromBinary(stagingPath, installPath) {
|
|
610
|
+
try {
|
|
611
|
+
const platform = getPlatform();
|
|
612
|
+
const binaryName = getBinaryName(platform);
|
|
613
|
+
const stagedBinaryPath = join2(stagingPath, binaryName);
|
|
614
|
+
try {
|
|
615
|
+
await stat(stagedBinaryPath);
|
|
616
|
+
} catch {
|
|
617
|
+
logEvent("tengu_native_install_binary_failure", {
|
|
618
|
+
stage_binary_exists: true,
|
|
619
|
+
error_binary_not_found: true
|
|
620
|
+
});
|
|
621
|
+
const error = new Error("Staged binary not found");
|
|
622
|
+
throw error;
|
|
623
|
+
}
|
|
624
|
+
await atomicMoveToInstallPath(stagedBinaryPath, installPath);
|
|
625
|
+
await rm(stagingPath, { recursive: true, force: true });
|
|
626
|
+
logEvent("tengu_native_install_binary_success", {});
|
|
627
|
+
} catch (error) {
|
|
628
|
+
if (!errorMessage(error).includes("Staged binary not found")) {
|
|
629
|
+
logEvent("tengu_native_install_binary_failure", {
|
|
630
|
+
stage_atomic_move: true,
|
|
631
|
+
error_move_failed: true
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
logError(toError(error));
|
|
635
|
+
throw error;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
async function installVersion(stagingPath, installPath, downloadType) {
|
|
639
|
+
if (downloadType === "npm") {
|
|
640
|
+
await installVersionFromPackage(stagingPath, installPath);
|
|
641
|
+
} else {
|
|
642
|
+
await installVersionFromBinary(stagingPath, installPath);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
async function performVersionUpdate(version, forceReinstall) {
|
|
646
|
+
const { stagingPath: baseStagingPath, installPath } = await getVersionPaths(version);
|
|
647
|
+
const { executable: executablePath } = getBaseDirectories();
|
|
648
|
+
const stagingPath = isEnvTruthy(process.env.ENABLE_LOCKLESS_UPDATES) ? `${baseStagingPath}.${process.pid}.${Date.now()}` : baseStagingPath;
|
|
649
|
+
const needsInstall = !await versionIsAvailable(version) || forceReinstall;
|
|
650
|
+
if (needsInstall) {
|
|
651
|
+
logForDebugging(forceReinstall ? `Force reinstalling native installer version ${version}` : `Downloading native installer version ${version}`);
|
|
652
|
+
const downloadType = await downloadVersion(version, stagingPath);
|
|
653
|
+
await installVersion(stagingPath, installPath, downloadType);
|
|
654
|
+
} else {
|
|
655
|
+
logForDebugging(`Version ${version} already installed, updating symlink`);
|
|
656
|
+
}
|
|
657
|
+
await removeDirectoryIfEmpty(executablePath);
|
|
658
|
+
await updateSymlink(executablePath, installPath);
|
|
659
|
+
if (!await isPossibleClaudeBinary(executablePath)) {
|
|
660
|
+
let installPathExists = false;
|
|
661
|
+
try {
|
|
662
|
+
await stat(installPath);
|
|
663
|
+
installPathExists = true;
|
|
664
|
+
} catch {}
|
|
665
|
+
throw new Error(`Failed to create executable at ${executablePath}. ` + `Source file exists: ${installPathExists}. ` + `Check write permissions to ${executablePath}.`);
|
|
666
|
+
}
|
|
667
|
+
return needsInstall;
|
|
668
|
+
}
|
|
669
|
+
async function versionIsAvailable(version) {
|
|
670
|
+
const { installPath } = await getVersionPaths(version);
|
|
671
|
+
return isPossibleClaudeBinary(installPath);
|
|
672
|
+
}
|
|
673
|
+
async function updateLatest(channelOrVersion, forceReinstall = false) {
|
|
674
|
+
const startTime = Date.now();
|
|
675
|
+
let version = await getLatestVersion(channelOrVersion);
|
|
676
|
+
const { executable: executablePath } = getBaseDirectories();
|
|
677
|
+
logForDebugging(`Checking for native installer update to version ${version}`);
|
|
678
|
+
if (!forceReinstall) {
|
|
679
|
+
const maxVersion = await getMaxVersion();
|
|
680
|
+
if (maxVersion && gt(version, maxVersion)) {
|
|
681
|
+
logForDebugging(`Native installer: maxVersion ${maxVersion} is set, capping update from ${version} to ${maxVersion}`);
|
|
682
|
+
if (gte("2.1.888", maxVersion)) {
|
|
683
|
+
logForDebugging(`Native installer: current version ${"2.1.888"} is already at or above maxVersion ${maxVersion}, skipping update`);
|
|
684
|
+
logEvent("tengu_native_update_skipped_max_version", {
|
|
685
|
+
latency_ms: Date.now() - startTime,
|
|
686
|
+
max_version: maxVersion,
|
|
687
|
+
available_version: version
|
|
688
|
+
});
|
|
689
|
+
return { success: true, latestVersion: version };
|
|
690
|
+
}
|
|
691
|
+
version = maxVersion;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if (!forceReinstall && version === "2.1.888" && await versionIsAvailable(version) && await isPossibleClaudeBinary(executablePath)) {
|
|
695
|
+
logForDebugging(`Found ${version} at ${executablePath}, skipping install`);
|
|
696
|
+
logEvent("tengu_native_update_complete", {
|
|
697
|
+
latency_ms: Date.now() - startTime,
|
|
698
|
+
was_new_install: false,
|
|
699
|
+
was_force_reinstall: false,
|
|
700
|
+
was_already_running: true
|
|
701
|
+
});
|
|
702
|
+
return { success: true, latestVersion: version };
|
|
703
|
+
}
|
|
704
|
+
if (!forceReinstall && shouldSkipVersion(version)) {
|
|
705
|
+
logEvent("tengu_native_update_skipped_minimum_version", {
|
|
706
|
+
latency_ms: Date.now() - startTime,
|
|
707
|
+
target_version: version
|
|
708
|
+
});
|
|
709
|
+
return { success: true, latestVersion: version };
|
|
710
|
+
}
|
|
711
|
+
let wasNewInstall = false;
|
|
712
|
+
let latencyMs;
|
|
713
|
+
if (isEnvTruthy(process.env.ENABLE_LOCKLESS_UPDATES)) {
|
|
714
|
+
wasNewInstall = await performVersionUpdate(version, forceReinstall);
|
|
715
|
+
latencyMs = Date.now() - startTime;
|
|
716
|
+
} else {
|
|
717
|
+
const { installPath } = await getVersionPaths(version);
|
|
718
|
+
if (forceReinstall) {
|
|
719
|
+
await forceRemoveLock(installPath);
|
|
720
|
+
}
|
|
721
|
+
const lockAcquired = await tryWithVersionLock(installPath, async () => {
|
|
722
|
+
wasNewInstall = await performVersionUpdate(version, forceReinstall);
|
|
723
|
+
}, 3);
|
|
724
|
+
latencyMs = Date.now() - startTime;
|
|
725
|
+
if (!lockAcquired) {
|
|
726
|
+
const dirs = getBaseDirectories();
|
|
727
|
+
let lockHolderPid;
|
|
728
|
+
if (isPidBasedLockingEnabled()) {
|
|
729
|
+
const lockfilePath = getLockFilePathFromVersionPath(dirs, installPath);
|
|
730
|
+
if (isLockActive(lockfilePath)) {
|
|
731
|
+
lockHolderPid = readLockContent(lockfilePath)?.pid;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
logEvent("tengu_native_update_lock_failed", {
|
|
735
|
+
latency_ms: latencyMs,
|
|
736
|
+
lock_holder_pid: lockHolderPid
|
|
737
|
+
});
|
|
738
|
+
return {
|
|
739
|
+
success: false,
|
|
740
|
+
latestVersion: version,
|
|
741
|
+
lockFailed: true,
|
|
742
|
+
lockHolderPid
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
logEvent("tengu_native_update_complete", {
|
|
747
|
+
latency_ms: latencyMs,
|
|
748
|
+
was_new_install: wasNewInstall,
|
|
749
|
+
was_force_reinstall: forceReinstall
|
|
750
|
+
});
|
|
751
|
+
logForDebugging(`Successfully updated to version ${version}`);
|
|
752
|
+
return { success: true, latestVersion: version };
|
|
753
|
+
}
|
|
754
|
+
async function removeDirectoryIfEmpty(path) {
|
|
755
|
+
try {
|
|
756
|
+
await rmdir(path);
|
|
757
|
+
logForDebugging(`Removed empty directory at ${path}`);
|
|
758
|
+
} catch (error) {
|
|
759
|
+
const code = getErrnoCode(error);
|
|
760
|
+
if (code !== "ENOTDIR" && code !== "ENOENT" && code !== "ENOTEMPTY") {
|
|
761
|
+
logForDebugging(`Could not remove directory at ${path}: ${error}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
async function updateSymlink(symlinkPath, targetPath) {
|
|
766
|
+
const platform = getPlatform();
|
|
767
|
+
const isWindows = platform.startsWith("win32");
|
|
768
|
+
if (isWindows) {
|
|
769
|
+
try {
|
|
770
|
+
const parentDir2 = dirname(symlinkPath);
|
|
771
|
+
await mkdir(parentDir2, { recursive: true });
|
|
772
|
+
let existingStats;
|
|
773
|
+
try {
|
|
774
|
+
existingStats = await stat(symlinkPath);
|
|
775
|
+
} catch {}
|
|
776
|
+
if (existingStats) {
|
|
777
|
+
try {
|
|
778
|
+
const targetStats = await stat(targetPath);
|
|
779
|
+
if (existingStats.size === targetStats.size) {
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
} catch {}
|
|
783
|
+
const oldFileName = `${symlinkPath}.old.${Date.now()}`;
|
|
784
|
+
await rename(symlinkPath, oldFileName);
|
|
785
|
+
try {
|
|
786
|
+
await copyFile(targetPath, symlinkPath);
|
|
787
|
+
try {
|
|
788
|
+
await unlink(oldFileName);
|
|
789
|
+
} catch {}
|
|
790
|
+
} catch (copyError) {
|
|
791
|
+
try {
|
|
792
|
+
await rename(oldFileName, symlinkPath);
|
|
793
|
+
} catch (restoreError) {
|
|
794
|
+
const errorWithCause = new Error(`Failed to restore old executable: ${restoreError}`, { cause: copyError });
|
|
795
|
+
logError(errorWithCause);
|
|
796
|
+
throw errorWithCause;
|
|
797
|
+
}
|
|
798
|
+
throw copyError;
|
|
799
|
+
}
|
|
800
|
+
} else {
|
|
801
|
+
try {
|
|
802
|
+
await copyFile(targetPath, symlinkPath);
|
|
803
|
+
} catch (e) {
|
|
804
|
+
if (isENOENT(e)) {
|
|
805
|
+
throw new Error(`Source file does not exist: ${targetPath}`);
|
|
806
|
+
}
|
|
807
|
+
throw e;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return true;
|
|
811
|
+
} catch (error) {
|
|
812
|
+
logError(new Error(`Failed to copy executable from ${targetPath} to ${symlinkPath}: ${error}`));
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
const parentDir = dirname(symlinkPath);
|
|
817
|
+
try {
|
|
818
|
+
await mkdir(parentDir, { recursive: true });
|
|
819
|
+
logForDebugging(`Created directory ${parentDir} for symlink`);
|
|
820
|
+
} catch (mkdirError) {
|
|
821
|
+
logError(new Error(`Failed to create directory ${parentDir}: ${mkdirError}`));
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
try {
|
|
825
|
+
let symlinkExists = false;
|
|
826
|
+
try {
|
|
827
|
+
await stat(symlinkPath);
|
|
828
|
+
symlinkExists = true;
|
|
829
|
+
} catch {}
|
|
830
|
+
if (symlinkExists) {
|
|
831
|
+
try {
|
|
832
|
+
const currentTarget = await readlink(symlinkPath);
|
|
833
|
+
const resolvedCurrentTarget = resolve(dirname(symlinkPath), currentTarget);
|
|
834
|
+
const resolvedTargetPath = resolve(targetPath);
|
|
835
|
+
if (resolvedCurrentTarget === resolvedTargetPath) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
} catch {}
|
|
839
|
+
await unlink(symlinkPath);
|
|
840
|
+
}
|
|
841
|
+
} catch (error) {
|
|
842
|
+
logError(new Error(`Failed to check/remove existing symlink: ${error}`));
|
|
843
|
+
}
|
|
844
|
+
const tempSymlink = `${symlinkPath}.tmp.${process.pid}.${Date.now()}`;
|
|
845
|
+
try {
|
|
846
|
+
await symlink(targetPath, tempSymlink);
|
|
847
|
+
await rename(tempSymlink, symlinkPath);
|
|
848
|
+
logForDebugging(`Atomically updated symlink ${symlinkPath} -> ${targetPath}`);
|
|
849
|
+
return true;
|
|
850
|
+
} catch (error) {
|
|
851
|
+
try {
|
|
852
|
+
await unlink(tempSymlink);
|
|
853
|
+
} catch {}
|
|
854
|
+
logError(new Error(`Failed to create symlink from ${symlinkPath} to ${targetPath}: ${error}`));
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
async function checkInstall(force = false) {
|
|
859
|
+
if (isEnvTruthy(process.env.DISABLE_INSTALLATION_CHECKS)) {
|
|
860
|
+
return [];
|
|
861
|
+
}
|
|
862
|
+
const installationType = await getCurrentInstallationType();
|
|
863
|
+
if (installationType === "development") {
|
|
864
|
+
return [];
|
|
865
|
+
}
|
|
866
|
+
const config = getGlobalConfig();
|
|
867
|
+
const shouldCheckNative = force || installationType === "native" || config.installMethod === "native";
|
|
868
|
+
if (!shouldCheckNative) {
|
|
869
|
+
return [];
|
|
870
|
+
}
|
|
871
|
+
const dirs = getBaseDirectories();
|
|
872
|
+
const messages = [];
|
|
873
|
+
const localBinDir = dirname(dirs.executable);
|
|
874
|
+
const resolvedLocalBinPath = resolve(localBinDir);
|
|
875
|
+
const platform = getPlatform();
|
|
876
|
+
const isWindows = platform.startsWith("win32");
|
|
877
|
+
try {
|
|
878
|
+
await access(localBinDir);
|
|
879
|
+
} catch {
|
|
880
|
+
messages.push({
|
|
881
|
+
message: `installMethod is native, but directory ${localBinDir} does not exist`,
|
|
882
|
+
userActionRequired: true,
|
|
883
|
+
type: "error"
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
if (isWindows) {
|
|
887
|
+
if (!await isPossibleClaudeBinary(dirs.executable)) {
|
|
888
|
+
messages.push({
|
|
889
|
+
message: `installMethod is native, but claude command is missing or invalid at ${dirs.executable}`,
|
|
890
|
+
userActionRequired: true,
|
|
891
|
+
type: "error"
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
} else {
|
|
895
|
+
try {
|
|
896
|
+
const target = await readlink(dirs.executable);
|
|
897
|
+
const absoluteTarget = resolve(dirname(dirs.executable), target);
|
|
898
|
+
if (!await isPossibleClaudeBinary(absoluteTarget)) {
|
|
899
|
+
messages.push({
|
|
900
|
+
message: `Claude symlink points to missing or invalid binary: ${target}`,
|
|
901
|
+
userActionRequired: true,
|
|
902
|
+
type: "error"
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
} catch (e) {
|
|
906
|
+
if (isENOENT(e)) {
|
|
907
|
+
messages.push({
|
|
908
|
+
message: `installMethod is native, but claude command not found at ${dirs.executable}`,
|
|
909
|
+
userActionRequired: true,
|
|
910
|
+
type: "error"
|
|
911
|
+
});
|
|
912
|
+
} else {
|
|
913
|
+
if (!await isPossibleClaudeBinary(dirs.executable)) {
|
|
914
|
+
messages.push({
|
|
915
|
+
message: `${dirs.executable} exists but is not a valid Claude binary`,
|
|
916
|
+
userActionRequired: true,
|
|
917
|
+
type: "error"
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const isInCurrentPath = (process.env.PATH || "").split(delimiter).some((entry) => {
|
|
924
|
+
try {
|
|
925
|
+
const resolvedEntry = resolve(entry);
|
|
926
|
+
if (isWindows) {
|
|
927
|
+
return resolvedEntry.toLowerCase() === resolvedLocalBinPath.toLowerCase();
|
|
928
|
+
}
|
|
929
|
+
return resolvedEntry === resolvedLocalBinPath;
|
|
930
|
+
} catch {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
if (!isInCurrentPath) {
|
|
935
|
+
if (isWindows) {
|
|
936
|
+
const windowsBinPath = localBinDir.replace(/\//g, "\\");
|
|
937
|
+
messages.push({
|
|
938
|
+
message: `Native installation exists but ${windowsBinPath} is not in your PATH. Add it by opening: System Properties \u2192 Environment Variables \u2192 Edit User PATH \u2192 New \u2192 Add the path above. Then restart your terminal.`,
|
|
939
|
+
userActionRequired: true,
|
|
940
|
+
type: "path"
|
|
941
|
+
});
|
|
942
|
+
} else {
|
|
943
|
+
const shellType = getShellType();
|
|
944
|
+
const configPaths = getShellConfigPaths();
|
|
945
|
+
const configFile = configPaths[shellType];
|
|
946
|
+
const displayPath = configFile ? configFile.replace(homedir(), "~") : "your shell config file";
|
|
947
|
+
messages.push({
|
|
948
|
+
message: `Native installation exists but ~/.local/bin is not in your PATH. Run:
|
|
949
|
+
|
|
950
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ${displayPath} && source ${displayPath}`,
|
|
951
|
+
userActionRequired: true,
|
|
952
|
+
type: "path"
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return messages;
|
|
957
|
+
}
|
|
958
|
+
function installLatest(channelOrVersion, forceReinstall = false) {
|
|
959
|
+
if (forceReinstall) {
|
|
960
|
+
return installLatestImpl(channelOrVersion, forceReinstall);
|
|
961
|
+
}
|
|
962
|
+
if (inFlightInstall) {
|
|
963
|
+
logForDebugging("installLatest: joining in-flight call");
|
|
964
|
+
return inFlightInstall;
|
|
965
|
+
}
|
|
966
|
+
const promise = installLatestImpl(channelOrVersion, forceReinstall);
|
|
967
|
+
inFlightInstall = promise;
|
|
968
|
+
const clear = () => {
|
|
969
|
+
inFlightInstall = null;
|
|
970
|
+
};
|
|
971
|
+
promise.then(clear, clear);
|
|
972
|
+
return promise;
|
|
973
|
+
}
|
|
974
|
+
async function installLatestImpl(channelOrVersion, forceReinstall = false) {
|
|
975
|
+
const updateResult = await updateLatest(channelOrVersion, forceReinstall);
|
|
976
|
+
if (!updateResult.success) {
|
|
977
|
+
return {
|
|
978
|
+
latestVersion: null,
|
|
979
|
+
wasUpdated: false,
|
|
980
|
+
lockFailed: updateResult.lockFailed,
|
|
981
|
+
lockHolderPid: updateResult.lockHolderPid
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
const config = getGlobalConfig();
|
|
985
|
+
if (config.installMethod !== "native") {
|
|
986
|
+
saveGlobalConfig((current) => ({
|
|
987
|
+
...current,
|
|
988
|
+
installMethod: "native",
|
|
989
|
+
autoUpdates: false,
|
|
990
|
+
autoUpdatesProtectedForNative: true
|
|
991
|
+
}));
|
|
992
|
+
logForDebugging('Native installer: Set installMethod to "native" and disabled legacy auto-updater for protection');
|
|
993
|
+
}
|
|
994
|
+
cleanupOldVersions();
|
|
995
|
+
return {
|
|
996
|
+
latestVersion: updateResult.latestVersion,
|
|
997
|
+
wasUpdated: updateResult.success,
|
|
998
|
+
lockFailed: false
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
async function getVersionFromSymlink(symlinkPath) {
|
|
1002
|
+
try {
|
|
1003
|
+
const target = await readlink(symlinkPath);
|
|
1004
|
+
const absoluteTarget = resolve(dirname(symlinkPath), target);
|
|
1005
|
+
if (await isPossibleClaudeBinary(absoluteTarget)) {
|
|
1006
|
+
return absoluteTarget;
|
|
1007
|
+
}
|
|
1008
|
+
} catch {}
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
function getLockFilePathFromVersionPath(dirs, versionPath) {
|
|
1012
|
+
const versionName = basename(versionPath);
|
|
1013
|
+
return join2(dirs.locks, `${versionName}.lock`);
|
|
1014
|
+
}
|
|
1015
|
+
async function lockCurrentVersion() {
|
|
1016
|
+
const dirs = getBaseDirectories();
|
|
1017
|
+
if (!process.execPath.includes(dirs.versions)) {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const versionPath = resolve(process.execPath);
|
|
1021
|
+
try {
|
|
1022
|
+
const lockfilePath = getLockFilePathFromVersionPath(dirs, versionPath);
|
|
1023
|
+
await mkdir(dirs.locks, { recursive: true });
|
|
1024
|
+
if (isPidBasedLockingEnabled()) {
|
|
1025
|
+
const acquired = await acquireProcessLifetimeLock(versionPath, lockfilePath);
|
|
1026
|
+
if (!acquired) {
|
|
1027
|
+
logEvent("tengu_version_lock_failed", {
|
|
1028
|
+
is_pid_based: true,
|
|
1029
|
+
is_lifetime_lock: true
|
|
1030
|
+
});
|
|
1031
|
+
logLockAcquisitionError(versionPath, new Error("Lock already held by another process"));
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
logEvent("tengu_version_lock_acquired", {
|
|
1035
|
+
is_pid_based: true,
|
|
1036
|
+
is_lifetime_lock: true
|
|
1037
|
+
});
|
|
1038
|
+
logForDebugging(`Acquired PID lock on running version: ${versionPath}`);
|
|
1039
|
+
} else {
|
|
1040
|
+
let release;
|
|
1041
|
+
try {
|
|
1042
|
+
release = await lock(versionPath, {
|
|
1043
|
+
stale: LOCK_STALE_MS,
|
|
1044
|
+
retries: 0,
|
|
1045
|
+
lockfilePath,
|
|
1046
|
+
onCompromised: (err) => {
|
|
1047
|
+
logForDebugging(`NON-FATAL: Lock on running version was compromised: ${err.message}`, { level: "info" });
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
logEvent("tengu_version_lock_acquired", {
|
|
1051
|
+
is_pid_based: false,
|
|
1052
|
+
is_lifetime_lock: true
|
|
1053
|
+
});
|
|
1054
|
+
logForDebugging(`Acquired mtime-based lock on running version: ${versionPath}`);
|
|
1055
|
+
registerCleanup(async () => {
|
|
1056
|
+
try {
|
|
1057
|
+
await release?.();
|
|
1058
|
+
} catch {}
|
|
1059
|
+
});
|
|
1060
|
+
} catch (lockError) {
|
|
1061
|
+
if (isENOENT(lockError)) {
|
|
1062
|
+
logForDebugging(`Cannot lock current version - file does not exist: ${versionPath}`, { level: "info" });
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
logEvent("tengu_version_lock_failed", {
|
|
1066
|
+
is_pid_based: false,
|
|
1067
|
+
is_lifetime_lock: true
|
|
1068
|
+
});
|
|
1069
|
+
logLockAcquisitionError(versionPath, lockError);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
if (isENOENT(error)) {
|
|
1075
|
+
logForDebugging(`Cannot lock current version - file does not exist: ${versionPath}`, { level: "info" });
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
logForDebugging(`NON-FATAL: Failed to lock current version during execution ${errorMessage(error)}`, { level: "info" });
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
function logLockAcquisitionError(versionPath, lockError) {
|
|
1082
|
+
logError(new Error(`NON-FATAL: Lock acquisition failed for ${versionPath} (expected in multi-process scenarios)`, { cause: lockError }));
|
|
1083
|
+
}
|
|
1084
|
+
async function forceRemoveLock(versionFilePath) {
|
|
1085
|
+
const dirs = getBaseDirectories();
|
|
1086
|
+
const lockfilePath = getLockFilePathFromVersionPath(dirs, versionFilePath);
|
|
1087
|
+
try {
|
|
1088
|
+
await unlink(lockfilePath);
|
|
1089
|
+
logForDebugging(`Force-removed lock file at ${lockfilePath}`);
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
logForDebugging(`Failed to force-remove lock file: ${errorMessage(error)}`);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
async function cleanupOldVersions() {
|
|
1095
|
+
await Promise.resolve();
|
|
1096
|
+
const dirs = getBaseDirectories();
|
|
1097
|
+
const oneHourAgo = Date.now() - 3600000;
|
|
1098
|
+
if (getPlatform().startsWith("win32")) {
|
|
1099
|
+
const executableDir = dirname(dirs.executable);
|
|
1100
|
+
try {
|
|
1101
|
+
const files = await readdir(executableDir);
|
|
1102
|
+
let cleanedCount = 0;
|
|
1103
|
+
for (const file of files) {
|
|
1104
|
+
if (!/^claude\.exe\.old\.\d+$/.test(file))
|
|
1105
|
+
continue;
|
|
1106
|
+
try {
|
|
1107
|
+
await unlink(join2(executableDir, file));
|
|
1108
|
+
cleanedCount++;
|
|
1109
|
+
} catch {}
|
|
1110
|
+
}
|
|
1111
|
+
if (cleanedCount > 0) {
|
|
1112
|
+
logForDebugging(`Cleaned up ${cleanedCount} old Windows executables on startup`);
|
|
1113
|
+
}
|
|
1114
|
+
} catch (error) {
|
|
1115
|
+
if (!isENOENT(error)) {
|
|
1116
|
+
logForDebugging(`Failed to clean up old Windows executables: ${error}`);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
try {
|
|
1121
|
+
const stagingEntries = await readdir(dirs.staging);
|
|
1122
|
+
let stagingCleanedCount = 0;
|
|
1123
|
+
for (const entry of stagingEntries) {
|
|
1124
|
+
const stagingPath = join2(dirs.staging, entry);
|
|
1125
|
+
try {
|
|
1126
|
+
const stats = await stat(stagingPath);
|
|
1127
|
+
if (stats.mtime.getTime() < oneHourAgo) {
|
|
1128
|
+
await rm(stagingPath, { recursive: true, force: true });
|
|
1129
|
+
stagingCleanedCount++;
|
|
1130
|
+
logForDebugging(`Cleaned up old staging directory: ${entry}`);
|
|
1131
|
+
}
|
|
1132
|
+
} catch {}
|
|
1133
|
+
}
|
|
1134
|
+
if (stagingCleanedCount > 0) {
|
|
1135
|
+
logForDebugging(`Cleaned up ${stagingCleanedCount} orphaned staging directories`);
|
|
1136
|
+
logEvent("tengu_native_staging_cleanup", {
|
|
1137
|
+
cleaned_count: stagingCleanedCount
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
if (!isENOENT(error)) {
|
|
1142
|
+
logForDebugging(`Failed to clean up staging directories: ${error}`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (isPidBasedLockingEnabled()) {
|
|
1146
|
+
const staleLocksCleaned = cleanupStaleLocks(dirs.locks);
|
|
1147
|
+
if (staleLocksCleaned > 0) {
|
|
1148
|
+
logForDebugging(`Cleaned up ${staleLocksCleaned} stale version locks`);
|
|
1149
|
+
logEvent("tengu_native_stale_locks_cleanup", {
|
|
1150
|
+
cleaned_count: staleLocksCleaned
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
let versionEntries;
|
|
1155
|
+
try {
|
|
1156
|
+
versionEntries = await readdir(dirs.versions);
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
if (!isENOENT(error)) {
|
|
1159
|
+
logForDebugging(`Failed to readdir versions directory: ${error}`);
|
|
1160
|
+
}
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
const versionFiles = [];
|
|
1164
|
+
let tempFilesCleanedCount = 0;
|
|
1165
|
+
for (const entry of versionEntries) {
|
|
1166
|
+
const entryPath = join2(dirs.versions, entry);
|
|
1167
|
+
if (/\.tmp\.\d+\.\d+$/.test(entry)) {
|
|
1168
|
+
try {
|
|
1169
|
+
const stats = await stat(entryPath);
|
|
1170
|
+
if (stats.mtime.getTime() < oneHourAgo) {
|
|
1171
|
+
await unlink(entryPath);
|
|
1172
|
+
tempFilesCleanedCount++;
|
|
1173
|
+
logForDebugging(`Cleaned up orphaned temp install file: ${entry}`);
|
|
1174
|
+
}
|
|
1175
|
+
} catch {}
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
try {
|
|
1179
|
+
const stats = await stat(entryPath);
|
|
1180
|
+
if (!stats.isFile())
|
|
1181
|
+
continue;
|
|
1182
|
+
if (process.platform !== "win32" && stats.size > 0 && (stats.mode & 73) === 0) {
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
versionFiles.push({
|
|
1186
|
+
name: entry,
|
|
1187
|
+
path: entryPath,
|
|
1188
|
+
resolvedPath: resolve(entryPath),
|
|
1189
|
+
mtime: stats.mtime
|
|
1190
|
+
});
|
|
1191
|
+
} catch {}
|
|
1192
|
+
}
|
|
1193
|
+
if (tempFilesCleanedCount > 0) {
|
|
1194
|
+
logForDebugging(`Cleaned up ${tempFilesCleanedCount} orphaned temp install files`);
|
|
1195
|
+
logEvent("tengu_native_temp_files_cleanup", {
|
|
1196
|
+
cleaned_count: tempFilesCleanedCount
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
if (versionFiles.length === 0) {
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
try {
|
|
1203
|
+
const currentBinaryPath = process.execPath;
|
|
1204
|
+
const protectedVersions = new Set;
|
|
1205
|
+
if (currentBinaryPath && currentBinaryPath.includes(dirs.versions)) {
|
|
1206
|
+
protectedVersions.add(resolve(currentBinaryPath));
|
|
1207
|
+
}
|
|
1208
|
+
const currentSymlinkVersion = await getVersionFromSymlink(dirs.executable);
|
|
1209
|
+
if (currentSymlinkVersion) {
|
|
1210
|
+
protectedVersions.add(currentSymlinkVersion);
|
|
1211
|
+
}
|
|
1212
|
+
for (const v of versionFiles) {
|
|
1213
|
+
if (protectedVersions.has(v.resolvedPath))
|
|
1214
|
+
continue;
|
|
1215
|
+
const lockFilePath = getLockFilePathFromVersionPath(dirs, v.resolvedPath);
|
|
1216
|
+
let hasActiveLock = false;
|
|
1217
|
+
if (isPidBasedLockingEnabled()) {
|
|
1218
|
+
hasActiveLock = isLockActive(lockFilePath);
|
|
1219
|
+
} else {
|
|
1220
|
+
try {
|
|
1221
|
+
hasActiveLock = await check(v.resolvedPath, {
|
|
1222
|
+
stale: LOCK_STALE_MS,
|
|
1223
|
+
lockfilePath: lockFilePath
|
|
1224
|
+
});
|
|
1225
|
+
} catch {
|
|
1226
|
+
hasActiveLock = false;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
if (hasActiveLock) {
|
|
1230
|
+
protectedVersions.add(v.resolvedPath);
|
|
1231
|
+
logForDebugging(`Protecting locked version from cleanup: ${v.name}`);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
const eligibleVersions = versionFiles.filter((v) => !protectedVersions.has(v.resolvedPath)).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
1235
|
+
const versionsToDelete = eligibleVersions.slice(VERSION_RETENTION_COUNT);
|
|
1236
|
+
if (versionsToDelete.length === 0) {
|
|
1237
|
+
logEvent("tengu_native_version_cleanup", {
|
|
1238
|
+
total_count: versionFiles.length,
|
|
1239
|
+
deleted_count: 0,
|
|
1240
|
+
protected_count: protectedVersions.size,
|
|
1241
|
+
retained_count: VERSION_RETENTION_COUNT,
|
|
1242
|
+
lock_failed_count: 0,
|
|
1243
|
+
error_count: 0
|
|
1244
|
+
});
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
let deletedCount = 0;
|
|
1248
|
+
let lockFailedCount = 0;
|
|
1249
|
+
let errorCount = 0;
|
|
1250
|
+
await Promise.all(versionsToDelete.map(async (version) => {
|
|
1251
|
+
try {
|
|
1252
|
+
const deleted = await tryWithVersionLock(version.path, async () => {
|
|
1253
|
+
await unlink(version.path);
|
|
1254
|
+
});
|
|
1255
|
+
if (deleted) {
|
|
1256
|
+
deletedCount++;
|
|
1257
|
+
} else {
|
|
1258
|
+
lockFailedCount++;
|
|
1259
|
+
logForDebugging(`Skipping deletion of ${version.name} - locked by another process`);
|
|
1260
|
+
}
|
|
1261
|
+
} catch (error) {
|
|
1262
|
+
errorCount++;
|
|
1263
|
+
logError(new Error(`Failed to delete version ${version.name}: ${error}`));
|
|
1264
|
+
}
|
|
1265
|
+
}));
|
|
1266
|
+
logEvent("tengu_native_version_cleanup", {
|
|
1267
|
+
total_count: versionFiles.length,
|
|
1268
|
+
deleted_count: deletedCount,
|
|
1269
|
+
protected_count: protectedVersions.size,
|
|
1270
|
+
retained_count: VERSION_RETENTION_COUNT,
|
|
1271
|
+
lock_failed_count: lockFailedCount,
|
|
1272
|
+
error_count: errorCount
|
|
1273
|
+
});
|
|
1274
|
+
} catch (error) {
|
|
1275
|
+
if (!isENOENT(error)) {
|
|
1276
|
+
logError(new Error(`Version cleanup failed: ${error}`));
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
async function cleanupShellAliases() {
|
|
1281
|
+
const messages = [];
|
|
1282
|
+
const configMap = getShellConfigPaths();
|
|
1283
|
+
for (const [shellType, configFile] of Object.entries(configMap)) {
|
|
1284
|
+
try {
|
|
1285
|
+
const lines = await readFileLines(configFile);
|
|
1286
|
+
if (!lines)
|
|
1287
|
+
continue;
|
|
1288
|
+
const { filtered, hadAlias } = filterClaudeAliases(lines);
|
|
1289
|
+
if (hadAlias) {
|
|
1290
|
+
await writeFileLines(configFile, filtered);
|
|
1291
|
+
messages.push({
|
|
1292
|
+
message: `Removed claude alias from ${configFile}. Run: unalias claude`,
|
|
1293
|
+
userActionRequired: true,
|
|
1294
|
+
type: "alias"
|
|
1295
|
+
});
|
|
1296
|
+
logForDebugging(`Cleaned up claude alias from ${shellType} config`);
|
|
1297
|
+
}
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
logError(error);
|
|
1300
|
+
messages.push({
|
|
1301
|
+
message: `Failed to clean up ${configFile}: ${error}`,
|
|
1302
|
+
userActionRequired: false,
|
|
1303
|
+
type: "error"
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
return messages;
|
|
1308
|
+
}
|
|
1309
|
+
async function manualRemoveNpmPackage(packageName) {
|
|
1310
|
+
try {
|
|
1311
|
+
const prefixResult = await execFileNoThrowWithCwd("npm", [
|
|
1312
|
+
"config",
|
|
1313
|
+
"get",
|
|
1314
|
+
"prefix"
|
|
1315
|
+
]);
|
|
1316
|
+
if (prefixResult.code !== 0 || !prefixResult.stdout) {
|
|
1317
|
+
return {
|
|
1318
|
+
success: false,
|
|
1319
|
+
error: "Failed to get npm global prefix"
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
const globalPrefix = prefixResult.stdout.trim();
|
|
1323
|
+
let manuallyRemoved = false;
|
|
1324
|
+
async function tryRemove(filePath, description) {
|
|
1325
|
+
try {
|
|
1326
|
+
await unlink(filePath);
|
|
1327
|
+
logForDebugging(`Manually removed ${description}: ${filePath}`);
|
|
1328
|
+
return true;
|
|
1329
|
+
} catch {
|
|
1330
|
+
return false;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
if (getPlatform().startsWith("win32")) {
|
|
1334
|
+
const binCmd = join2(globalPrefix, "claude.cmd");
|
|
1335
|
+
const binPs1 = join2(globalPrefix, "claude.ps1");
|
|
1336
|
+
const binExe = join2(globalPrefix, "claude");
|
|
1337
|
+
if (await tryRemove(binCmd, "bin script")) {
|
|
1338
|
+
manuallyRemoved = true;
|
|
1339
|
+
}
|
|
1340
|
+
if (await tryRemove(binPs1, "PowerShell script")) {
|
|
1341
|
+
manuallyRemoved = true;
|
|
1342
|
+
}
|
|
1343
|
+
if (await tryRemove(binExe, "bin executable")) {
|
|
1344
|
+
manuallyRemoved = true;
|
|
1345
|
+
}
|
|
1346
|
+
} else {
|
|
1347
|
+
const binSymlink = join2(globalPrefix, "bin", "claude");
|
|
1348
|
+
if (await tryRemove(binSymlink, "bin symlink")) {
|
|
1349
|
+
manuallyRemoved = true;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
if (manuallyRemoved) {
|
|
1353
|
+
logForDebugging(`Successfully removed ${packageName} manually`);
|
|
1354
|
+
const nodeModulesPath = getPlatform().startsWith("win32") ? join2(globalPrefix, "node_modules", packageName) : join2(globalPrefix, "lib", "node_modules", packageName);
|
|
1355
|
+
return {
|
|
1356
|
+
success: true,
|
|
1357
|
+
warning: `${packageName} executables removed, but node_modules directory was left intact for safety. You may manually delete it later at: ${nodeModulesPath}`
|
|
1358
|
+
};
|
|
1359
|
+
} else {
|
|
1360
|
+
return { success: false };
|
|
1361
|
+
}
|
|
1362
|
+
} catch (manualError) {
|
|
1363
|
+
logForDebugging(`Manual removal failed: ${manualError}`, {
|
|
1364
|
+
level: "error"
|
|
1365
|
+
});
|
|
1366
|
+
return {
|
|
1367
|
+
success: false,
|
|
1368
|
+
error: `Manual removal failed: ${manualError}`
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
async function attemptNpmUninstall(packageName) {
|
|
1373
|
+
const { code, stderr } = await execFileNoThrowWithCwd("npm", ["uninstall", "-g", packageName], { cwd: process.cwd() });
|
|
1374
|
+
if (code === 0) {
|
|
1375
|
+
logForDebugging(`Removed global npm installation of ${packageName}`);
|
|
1376
|
+
return { success: true };
|
|
1377
|
+
} else if (stderr && !stderr.includes("npm ERR! code E404")) {
|
|
1378
|
+
if (stderr.includes("npm error code ENOTEMPTY")) {
|
|
1379
|
+
logForDebugging(`Failed to uninstall global npm package ${packageName}: ${stderr}`, { level: "error" });
|
|
1380
|
+
logForDebugging(`Attempting manual removal due to ENOTEMPTY error`);
|
|
1381
|
+
const manualResult = await manualRemoveNpmPackage(packageName);
|
|
1382
|
+
if (manualResult.success) {
|
|
1383
|
+
return { success: true, warning: manualResult.warning };
|
|
1384
|
+
} else if (manualResult.error) {
|
|
1385
|
+
return {
|
|
1386
|
+
success: false,
|
|
1387
|
+
error: `Failed to remove global npm installation of ${packageName}: ${stderr}. Manual removal also failed: ${manualResult.error}`
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
logForDebugging(`Failed to uninstall global npm package ${packageName}: ${stderr}`, { level: "error" });
|
|
1392
|
+
return {
|
|
1393
|
+
success: false,
|
|
1394
|
+
error: `Failed to remove global npm installation of ${packageName}: ${stderr}`
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
return { success: false };
|
|
1398
|
+
}
|
|
1399
|
+
async function cleanupNpmInstallations() {
|
|
1400
|
+
const errors = [];
|
|
1401
|
+
const warnings = [];
|
|
1402
|
+
let removed = 0;
|
|
1403
|
+
const codePackageResult = await attemptNpmUninstall("@anthropic-ai/claude-code");
|
|
1404
|
+
if (codePackageResult.success) {
|
|
1405
|
+
removed++;
|
|
1406
|
+
if (codePackageResult.warning) {
|
|
1407
|
+
warnings.push(codePackageResult.warning);
|
|
1408
|
+
}
|
|
1409
|
+
} else if (codePackageResult.error) {
|
|
1410
|
+
errors.push(codePackageResult.error);
|
|
1411
|
+
}
|
|
1412
|
+
if ("") {}
|
|
1413
|
+
const localInstallDir = join2(homedir(), ".claude", "local");
|
|
1414
|
+
try {
|
|
1415
|
+
await rm(localInstallDir, { recursive: true });
|
|
1416
|
+
removed++;
|
|
1417
|
+
logForDebugging(`Removed local installation at ${localInstallDir}`);
|
|
1418
|
+
} catch (error) {
|
|
1419
|
+
if (!isENOENT(error)) {
|
|
1420
|
+
errors.push(`Failed to remove ${localInstallDir}: ${error}`);
|
|
1421
|
+
logForDebugging(`Failed to remove local installation: ${error}`, {
|
|
1422
|
+
level: "error"
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return { removed, errors, warnings };
|
|
1427
|
+
}
|
|
1428
|
+
var getMaxVersion = async () => null, shouldSkipVersion = (_version) => false, VERSION_RETENTION_COUNT = 2, LOCK_STALE_MS, inFlightInstall = null;
|
|
1429
|
+
var init_installer = __esm(() => {
|
|
1430
|
+
init_analytics();
|
|
1431
|
+
init_cleanupRegistry();
|
|
1432
|
+
init_config();
|
|
1433
|
+
init_debug();
|
|
1434
|
+
init_doctorDiagnostic();
|
|
1435
|
+
init_env();
|
|
1436
|
+
init_envDynamic();
|
|
1437
|
+
init_envUtils();
|
|
1438
|
+
init_errors();
|
|
1439
|
+
init_execFileNoThrow();
|
|
1440
|
+
init_localInstaller();
|
|
1441
|
+
init_lockfile();
|
|
1442
|
+
init_log();
|
|
1443
|
+
init_semver();
|
|
1444
|
+
init_shellConfig();
|
|
1445
|
+
init_sleep();
|
|
1446
|
+
init_xdg();
|
|
1447
|
+
init_download();
|
|
1448
|
+
init_pidLock();
|
|
1449
|
+
LOCK_STALE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
1450
|
+
});
|
|
1451
|
+
|
|
1452
|
+
// src/utils/nativeInstaller/index.ts
|
|
1453
|
+
var init_nativeInstaller = __esm(() => {
|
|
1454
|
+
init_installer();
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
export { checkInstall, installLatest, lockCurrentVersion, cleanupOldVersions, cleanupShellAliases, cleanupNpmInstallations, init_nativeInstaller };
|