@redscope-ai/redscope 1.0.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/README.md +224 -0
- package/dist/chunk-090920rk.js +288 -0
- package/dist/chunk-0afb2r78.js +141 -0
- package/dist/chunk-0d4ekx1g.js +73 -0
- package/dist/chunk-0g6nwbhq.js +15 -0
- package/dist/chunk-0qj905nt.js +18 -0
- package/dist/chunk-0s5btnn1.js +186 -0
- package/dist/chunk-0s8fars0.js +91 -0
- package/dist/chunk-10ev3dvh.js +312 -0
- package/dist/chunk-10k5jfc5.js +1295 -0
- package/dist/chunk-12tspwqa.js +240 -0
- package/dist/chunk-13qesvnw.js +17 -0
- package/dist/chunk-143eh1e0.js +121 -0
- package/dist/chunk-14p6wvsq.js +39 -0
- package/dist/chunk-19f3zb1m.js +342 -0
- package/dist/chunk-1a5cep8h.js +145 -0
- package/dist/chunk-1abw9kkn.js +34 -0
- package/dist/chunk-1aer7c78.js +118 -0
- package/dist/chunk-1dazz4g6.js +154 -0
- package/dist/chunk-1fcf4ty1.js +142 -0
- package/dist/chunk-1gnxhyf8.js +62 -0
- package/dist/chunk-1he3944e.js +8124 -0
- package/dist/chunk-1jpayz7y.js +952 -0
- package/dist/chunk-1qd6f6vk.js +269 -0
- package/dist/chunk-1v0kpe62.js +2547 -0
- package/dist/chunk-1w20m7gw.js +445 -0
- package/dist/chunk-1y7kp51j.js +72 -0
- package/dist/chunk-1ycb5sxt.js +247 -0
- package/dist/chunk-1zbwhcbt.js +1124 -0
- package/dist/chunk-20psem54.js +116 -0
- package/dist/chunk-23h69r5b.js +30 -0
- package/dist/chunk-23x86ptv.js +473 -0
- package/dist/chunk-24fyv3jz.js +378 -0
- package/dist/chunk-24kv69g3.js +97 -0
- package/dist/chunk-2azx8zsc.js +125 -0
- package/dist/chunk-2d1gwzz9.js +524 -0
- package/dist/chunk-2g0ytd9d.js +29058 -0
- package/dist/chunk-2hfp9kat.js +21 -0
- package/dist/chunk-2j875eq6.js +37 -0
- package/dist/chunk-2kcgxnvp.js +39 -0
- package/dist/chunk-2kz09j2s.js +23 -0
- package/dist/chunk-2mwnwp0n.js +17 -0
- package/dist/chunk-2p1cqhcn.js +921 -0
- package/dist/chunk-2p369q9z.js +61 -0
- package/dist/chunk-2rf6asgf.js +151 -0
- package/dist/chunk-2vr7mqx1.js +384 -0
- package/dist/chunk-2xcg933e.js +205 -0
- package/dist/chunk-2ypwckbz.js +40310 -0
- package/dist/chunk-30wnahyg.js +626 -0
- package/dist/chunk-326zehp8.js +204 -0
- package/dist/chunk-32s6jzgw.js +183 -0
- package/dist/chunk-35yzt1a7.js +202 -0
- package/dist/chunk-38frkej6.js +62 -0
- package/dist/chunk-3abaq08g.js +34 -0
- package/dist/chunk-3h59ttr5.js +32 -0
- package/dist/chunk-3nk9q8dr.js +154 -0
- package/dist/chunk-3prrxevm.js +224 -0
- package/dist/chunk-3tv8p9xw.js +127 -0
- package/dist/chunk-3txyekes.js +19 -0
- package/dist/chunk-3vfxjn7g.js +19 -0
- package/dist/chunk-3w9sye8h.js +81 -0
- package/dist/chunk-3y69j7y8.js +24 -0
- package/dist/chunk-3zwjpkjh.js +1603 -0
- package/dist/chunk-40t1d75v.js +3442 -0
- package/dist/chunk-470kmby4.js +318 -0
- package/dist/chunk-47jc141z.js +335 -0
- package/dist/chunk-48rz50ct.js +868 -0
- package/dist/chunk-49wv03ts.js +232 -0
- package/dist/chunk-4a189mn2.js +103 -0
- package/dist/chunk-4c4fmh7a.js +15 -0
- package/dist/chunk-4ct8dsj5.js +49 -0
- package/dist/chunk-4kqt1pm1.js +100 -0
- package/dist/chunk-4ng0xy0e.js +802 -0
- package/dist/chunk-4spgkgr3.js +43 -0
- package/dist/chunk-4tjdwtyy.js +19 -0
- package/dist/chunk-4tr60273.js +370 -0
- package/dist/chunk-4vnaeng5.js +29 -0
- package/dist/chunk-4wbqpeaw.js +871 -0
- package/dist/chunk-4wgkv3fv.js +1140 -0
- package/dist/chunk-4yjskjb6.js +40 -0
- package/dist/chunk-50m3a23z.js +35 -0
- package/dist/chunk-511f79az.js +182 -0
- package/dist/chunk-51sgztvv.js +161 -0
- package/dist/chunk-563fcpv1.js +290 -0
- package/dist/chunk-564cnq6v.js +735 -0
- package/dist/chunk-569r8cxc.js +31 -0
- package/dist/chunk-570x55d4.js +12 -0
- package/dist/chunk-571556cm.js +80 -0
- package/dist/chunk-59t4c56e.js +63 -0
- package/dist/chunk-5axjhkma.js +36 -0
- package/dist/chunk-5b188q5e.js +157 -0
- package/dist/chunk-5dmn1865.js +439 -0
- package/dist/chunk-5ks4829r.js +267 -0
- package/dist/chunk-5mmhfbxb.js +1078 -0
- package/dist/chunk-5rdt14hy.js +742 -0
- package/dist/chunk-5ssryexj.js +121 -0
- package/dist/chunk-5v95pnq4.js +15 -0
- package/dist/chunk-5xvjt2t9.js +68 -0
- package/dist/chunk-5zyq6t1q.js +118 -0
- package/dist/chunk-60fkafk2.js +15 -0
- package/dist/chunk-62fjkf5q.js +46 -0
- package/dist/chunk-64gazrrb.js +8067 -0
- package/dist/chunk-65tq2yjx.js +126 -0
- package/dist/chunk-65zbgg1n.js +14 -0
- package/dist/chunk-66v8mty3.js +264 -0
- package/dist/chunk-6acx5heq.js +292 -0
- package/dist/chunk-6hr7742d.js +61 -0
- package/dist/chunk-6hygvrhn.js +143 -0
- package/dist/chunk-6kjh280m.js +128 -0
- package/dist/chunk-6s0q1s5r.js +66 -0
- package/dist/chunk-6x35ffpx.js +690 -0
- package/dist/chunk-71jfy1hh.js +570 -0
- package/dist/chunk-71sdcaq6.js +15 -0
- package/dist/chunk-754qdxs5.js +92 -0
- package/dist/chunk-79v5bkj4.js +1176 -0
- package/dist/chunk-7br0w7j5.js +151 -0
- package/dist/chunk-7cjgrzz1.js +298 -0
- package/dist/chunk-7d41ks0y.js +133 -0
- package/dist/chunk-7f40pmtr.js +71 -0
- package/dist/chunk-7g15x8hm.js +131 -0
- package/dist/chunk-7gtnzdet.js +120 -0
- package/dist/chunk-7h0z4aqx.js +702 -0
- package/dist/chunk-7h7e5a7d.js +25 -0
- package/dist/chunk-7m2cznwr.js +40 -0
- package/dist/chunk-7nvday0n.js +252 -0
- package/dist/chunk-7qey87th.js +145 -0
- package/dist/chunk-7qx3xhv3.js +9076 -0
- package/dist/chunk-7tfdhkpy.js +61 -0
- package/dist/chunk-80m511j6.js +121 -0
- package/dist/chunk-80ysxfe9.js +784 -0
- package/dist/chunk-8375zk8t.js +17200 -0
- package/dist/chunk-85bpkyy9.js +412 -0
- package/dist/chunk-85tcn547.js +876 -0
- package/dist/chunk-85vqgbc8.js +13 -0
- package/dist/chunk-86626jb4.js +49 -0
- package/dist/chunk-87ms17f6.js +444 -0
- package/dist/chunk-87mz239c.js +118 -0
- package/dist/chunk-89vdzt4e.js +254 -0
- package/dist/chunk-89z3e99z.js +159 -0
- package/dist/chunk-8cwrz1dd.js +1806 -0
- package/dist/chunk-8gv2pjby.js +21 -0
- package/dist/chunk-8hdevr3s.js +140 -0
- package/dist/chunk-8hdsk6qc.js +710 -0
- package/dist/chunk-8kct9arg.js +724 -0
- package/dist/chunk-8kf8h7xf.js +23 -0
- package/dist/chunk-8qed8ymj.js +605 -0
- package/dist/chunk-8sdgr592.js +101 -0
- package/dist/chunk-8we9w8pw.js +111 -0
- package/dist/chunk-8xnm5637.js +72 -0
- package/dist/chunk-8y3q0eqy.js +67 -0
- package/dist/chunk-8yvsnrkr.js +3449 -0
- package/dist/chunk-8zz4z1q3.js +42 -0
- package/dist/chunk-90eyff3k.js +119 -0
- package/dist/chunk-92bjkrf2.js +121 -0
- package/dist/chunk-92zrc7c6.js +327 -0
- package/dist/chunk-935nrvdb.js +13 -0
- package/dist/chunk-94pfyv6a.js +48 -0
- package/dist/chunk-9568p8se.js +115 -0
- package/dist/chunk-96km1ywr.js +37 -0
- package/dist/chunk-980bg4w4.js +163 -0
- package/dist/chunk-9a9g5hbj.js +205 -0
- package/dist/chunk-9cm4725d.js +4395 -0
- package/dist/chunk-9ds3vzq8.js +847 -0
- package/dist/chunk-9ffc9n60.js +618 -0
- package/dist/chunk-9fstrwv2.js +184 -0
- package/dist/chunk-9gt0g0qe.js +153 -0
- package/dist/chunk-9h9k5vz3.js +2761 -0
- package/dist/chunk-9he8bmhy.js +17 -0
- package/dist/chunk-9hn8e6h1.js +12 -0
- package/dist/chunk-9j0n3g8e.js +179 -0
- package/dist/chunk-9j6pa3ft.js +251 -0
- package/dist/chunk-9jpg9dn7.js +122 -0
- package/dist/chunk-9mycnwj5.js +46 -0
- package/dist/chunk-9npy2c17.js +517 -0
- package/dist/chunk-9p6sec8n.js +34 -0
- package/dist/chunk-9pnym83h.js +4584 -0
- package/dist/chunk-9skwrnd2.js +25 -0
- package/dist/chunk-9tsfaqr8.js +459 -0
- package/dist/chunk-9tsw3cqv.js +5924 -0
- package/dist/chunk-9w6ckyk4.js +49 -0
- package/dist/chunk-a15bwzv6.js +147 -0
- package/dist/chunk-a9t6cp69.js +28 -0
- package/dist/chunk-ad2yk19p.js +102 -0
- package/dist/chunk-ad4cw4nw.js +336 -0
- package/dist/chunk-ad69fbsk.js +347 -0
- package/dist/chunk-ae76ded0.js +30 -0
- package/dist/chunk-aeysytks.js +216 -0
- package/dist/chunk-ag81m9bq.js +61 -0
- package/dist/chunk-ahx7gp6r.js +4448 -0
- package/dist/chunk-aj4tk4tk.js +23 -0
- package/dist/chunk-an82t9jc.js +104 -0
- package/dist/chunk-apg95qd7.js +1393 -0
- package/dist/chunk-aq5n2adz.js +27 -0
- package/dist/chunk-aw4s3a99.js +208 -0
- package/dist/chunk-awgdfggg.js +14 -0
- package/dist/chunk-ayymxgn1.js +164 -0
- package/dist/chunk-azbab59e.js +637 -0
- package/dist/chunk-azdxq2a3.js +293 -0
- package/dist/chunk-b0tjx3k1.js +523 -0
- package/dist/chunk-b5pp4g2g.js +371 -0
- package/dist/chunk-b5zm8dt6.js +26 -0
- package/dist/chunk-bcnye5a0.js +109 -0
- package/dist/chunk-beqz3k49.js +190 -0
- package/dist/chunk-bf906wpw.js +147 -0
- package/dist/chunk-bgan4cpf.js +13 -0
- package/dist/chunk-bhzp13h7.js +1178 -0
- package/dist/chunk-bk403kpw.js +142 -0
- package/dist/chunk-bmq4c135.js +489 -0
- package/dist/chunk-bprbeda7.js +35 -0
- package/dist/chunk-bst7czdd.js +888 -0
- package/dist/chunk-bths4xgn.js +111 -0
- package/dist/chunk-btjn3qby.js +13 -0
- package/dist/chunk-bwb1vxnt.js +120 -0
- package/dist/chunk-bxa6tw4m.js +643 -0
- package/dist/chunk-bxfjr8qb.js +27 -0
- package/dist/chunk-bxpzhrej.js +73 -0
- package/dist/chunk-bzyzrq0k.js +51 -0
- package/dist/chunk-c0k7b0jw.js +4265 -0
- package/dist/chunk-c17f0h2s.js +16 -0
- package/dist/chunk-c1yc761e.js +6748 -0
- package/dist/chunk-c5g9shkw.js +298 -0
- package/dist/chunk-c696122m.js +69 -0
- package/dist/chunk-c92b3yxx.js +109 -0
- package/dist/chunk-c9aqz56y.js +143 -0
- package/dist/chunk-cba7c5w3.js +345 -0
- package/dist/chunk-cbcxbbe6.js +6543 -0
- package/dist/chunk-cdfjb87h.js +11 -0
- package/dist/chunk-ce8zjt1y.js +136 -0
- package/dist/chunk-cep7e37k.js +22740 -0
- package/dist/chunk-chs5qm8d.js +258 -0
- package/dist/chunk-ckydq33g.js +144 -0
- package/dist/chunk-cnge6wpj.js +514 -0
- package/dist/chunk-cpnsvqf1.js +13 -0
- package/dist/chunk-cqqebkv4.js +32 -0
- package/dist/chunk-cvqpp7dk.js +627 -0
- package/dist/chunk-cwc33j40.js +65 -0
- package/dist/chunk-cypvrq2a.js +155 -0
- package/dist/chunk-d1ha0swn.js +475 -0
- package/dist/chunk-d2an0138.js +35 -0
- package/dist/chunk-d2tt72ck.js +343 -0
- package/dist/chunk-d6wvcqrw.js +9507 -0
- package/dist/chunk-d7ys2kka.js +991 -0
- package/dist/chunk-dbts5q5p.js +122 -0
- package/dist/chunk-dct29ggs.js +295 -0
- package/dist/chunk-de0qnnf7.js +1059 -0
- package/dist/chunk-dep72ce4.js +513 -0
- package/dist/chunk-dgpvgy8x.js +47 -0
- package/dist/chunk-dhhd7dtc.js +20 -0
- package/dist/chunk-dhzpmxv6.js +594 -0
- package/dist/chunk-djes4da7.js +413 -0
- package/dist/chunk-dnhv3vx7.js +166 -0
- package/dist/chunk-dqtvafan.js +2365 -0
- package/dist/chunk-dr4a3tcp.js +60 -0
- package/dist/chunk-dz2xk9kb.js +100 -0
- package/dist/chunk-dz7nc6rf.js +15 -0
- package/dist/chunk-e3abfxpy.js +1486 -0
- package/dist/chunk-e3cq9z89.js +85 -0
- package/dist/chunk-e3j7m7k2.js +642 -0
- package/dist/chunk-e4dsy4g1.js +9951 -0
- package/dist/chunk-e5592pnn.js +197 -0
- package/dist/chunk-e55hdegh.js +129 -0
- package/dist/chunk-e5r5r04e.js +1030 -0
- package/dist/chunk-e60zztbt.js +442 -0
- package/dist/chunk-e7qq6vn0.js +372 -0
- package/dist/chunk-e9aat7xw.js +80 -0
- package/dist/chunk-e9d5v3zs.js +143 -0
- package/dist/chunk-eax32zk4.js +87 -0
- package/dist/chunk-ebfwmbx1.js +117 -0
- package/dist/chunk-ec71pb8t.js +971 -0
- package/dist/chunk-eemjb825.js +17252 -0
- package/dist/chunk-ees8xdhd.js +256 -0
- package/dist/chunk-eewg66y1.js +112 -0
- package/dist/chunk-eg22v12d.js +266 -0
- package/dist/chunk-enzzk67f.js +313 -0
- package/dist/chunk-eskhp70f.js +117 -0
- package/dist/chunk-ewx6z4g8.js +55 -0
- package/dist/chunk-eyvx461k.js +76 -0
- package/dist/chunk-eztq2b5f.js +94 -0
- package/dist/chunk-f0ffwzdd.js +321 -0
- package/dist/chunk-f80n68mf.js +119 -0
- package/dist/chunk-fae2hjxp.js +99 -0
- package/dist/chunk-fbtfp370.js +60 -0
- package/dist/chunk-fc6ndtgf.js +94 -0
- package/dist/chunk-fdwabr8p.js +13870 -0
- package/dist/chunk-fejeqe61.js +785 -0
- package/dist/chunk-fh0d6mvk.js +168 -0
- package/dist/chunk-fh19zcaf.js +304 -0
- package/dist/chunk-fh8bd39r.js +186 -0
- package/dist/chunk-fj2ebbpn.js +33 -0
- package/dist/chunk-fjn632v7.js +194 -0
- package/dist/chunk-fncpkzs5.js +1389 -0
- package/dist/chunk-fpd1gpt8.js +332 -0
- package/dist/chunk-fq9snrnh.js +295 -0
- package/dist/chunk-fqcfzg3j.js +207 -0
- package/dist/chunk-ftt3vqj2.js +1919 -0
- package/dist/chunk-g06pm4n9.js +395 -0
- package/dist/chunk-g4m5pf4g.js +8 -0
- package/dist/chunk-g72h52y6.js +36 -0
- package/dist/chunk-g79ej71s.js +1627 -0
- package/dist/chunk-g7fwk59d.js +19 -0
- package/dist/chunk-g9jnkrtm.js +663 -0
- package/dist/chunk-g9vg5d7t.js +38 -0
- package/dist/chunk-ga1jkyqy.js +1636 -0
- package/dist/chunk-gaaap2nk.js +676 -0
- package/dist/chunk-gc6erq5q.js +483 -0
- package/dist/chunk-gjrcmf0a.js +752 -0
- package/dist/chunk-gmdy2w3z.js +238999 -0
- package/dist/chunk-gsz4yrrk.js +81 -0
- package/dist/chunk-gy47rjy8.js +3830 -0
- package/dist/chunk-h12a4f4x.js +11 -0
- package/dist/chunk-h1yratmg.js +725 -0
- package/dist/chunk-h9y0jnsy.js +155 -0
- package/dist/chunk-hbhs3mwy.js +133 -0
- package/dist/chunk-hbs8cmb4.js +8 -0
- package/dist/chunk-hdk0t1ht.js +940 -0
- package/dist/chunk-hef8dx4s.js +178 -0
- package/dist/chunk-hgsca8mt.js +381 -0
- package/dist/chunk-hhsxm2yr.js +67 -0
- package/dist/chunk-hj5tzzpd.js +39 -0
- package/dist/chunk-hjxqmtg5.js +94 -0
- package/dist/chunk-hn4w9pkj.js +68 -0
- package/dist/chunk-hnprkjgp.js +25 -0
- package/dist/chunk-hq3n5ex7.js +183 -0
- package/dist/chunk-hqjspfma.js +158 -0
- package/dist/chunk-hqxp6b72.js +1198 -0
- package/dist/chunk-hs6nrmq6.js +94 -0
- package/dist/chunk-hwba5xdc.js +267 -0
- package/dist/chunk-hy566ev3.js +430 -0
- package/dist/chunk-hzmzwte2.js +153 -0
- package/dist/chunk-hzxzvzw8.js +274 -0
- package/dist/chunk-j139fzgs.js +114 -0
- package/dist/chunk-j1mep9ck.js +62 -0
- package/dist/chunk-j3xveeg4.js +273 -0
- package/dist/chunk-j5y1s11j.js +100 -0
- package/dist/chunk-j9475b46.js +26 -0
- package/dist/chunk-j9rgqs8m.js +1192 -0
- package/dist/chunk-jccjaddz.js +74 -0
- package/dist/chunk-jdkwfy9e.js +35 -0
- package/dist/chunk-jdqp0r4h.js +6157 -0
- package/dist/chunk-jdzk4zwn.js +587 -0
- package/dist/chunk-jfafmkte.js +49 -0
- package/dist/chunk-jg3r989b.js +16 -0
- package/dist/chunk-jhtccjc9.js +54 -0
- package/dist/chunk-jj2ff1pr.js +688 -0
- package/dist/chunk-jmv7k0jn.js +37 -0
- package/dist/chunk-jmxzmwpw.js +65 -0
- package/dist/chunk-jnjxdqyr.js +353 -0
- package/dist/chunk-jsbbez9j.js +138 -0
- package/dist/chunk-jvpt2dc0.js +424 -0
- package/dist/chunk-jwd7cka0.js +34 -0
- package/dist/chunk-jy5er3st.js +15 -0
- package/dist/chunk-jyby79z5.js +121 -0
- package/dist/chunk-jzyr6j5n.js +332 -0
- package/dist/chunk-k49xc781.js +63 -0
- package/dist/chunk-k7dt2g4a.js +41 -0
- package/dist/chunk-k7hexw3v.js +969 -0
- package/dist/chunk-k7wwkraa.js +117 -0
- package/dist/chunk-kb3758f7.js +51 -0
- package/dist/chunk-kc67kt75.js +3119 -0
- package/dist/chunk-kdhmfxmh.js +3149 -0
- package/dist/chunk-kejdd6zc.js +51 -0
- package/dist/chunk-kekrjeem.js +402 -0
- package/dist/chunk-kez5r0zz.js +280 -0
- package/dist/chunk-kfsvcs5t.js +75 -0
- package/dist/chunk-khtvffc4.js +285 -0
- package/dist/chunk-kkz4w1tv.js +64 -0
- package/dist/chunk-kmywng0j.js +272 -0
- package/dist/chunk-kq6vcpdr.js +224 -0
- package/dist/chunk-kqzdszcc.js +37 -0
- package/dist/chunk-ktxpp02w.js +435 -0
- package/dist/chunk-kwcvhbtz.js +26 -0
- package/dist/chunk-kx0cm9qr.js +128 -0
- package/dist/chunk-kxcmqz10.js +120 -0
- package/dist/chunk-kxwava1g.js +14 -0
- package/dist/chunk-kywtr3jg.js +825 -0
- package/dist/chunk-kzwg923p.js +8 -0
- package/dist/chunk-m1eq3sgv.js +255 -0
- package/dist/chunk-m21h5zb4.js +119 -0
- package/dist/chunk-m2c3bjv1.js +111 -0
- package/dist/chunk-m41e19ms.js +42 -0
- package/dist/chunk-m7ka36ex.js +97 -0
- package/dist/chunk-m81w8tbm.js +259 -0
- package/dist/chunk-m95ggkax.js +281 -0
- package/dist/chunk-manx26xa.js +145 -0
- package/dist/chunk-mdxh3pk2.js +298 -0
- package/dist/chunk-mhbfkcja.js +311 -0
- package/dist/chunk-mjnr5erm.js +173 -0
- package/dist/chunk-mngvnmwp.js +135 -0
- package/dist/chunk-mvfqanv5.js +63 -0
- package/dist/chunk-mw1nesq1.js +140 -0
- package/dist/chunk-mx168925.js +661 -0
- package/dist/chunk-mxwvj18g.js +795 -0
- package/dist/chunk-my7r5mba.js +257 -0
- package/dist/chunk-myaa1kkf.js +17 -0
- package/dist/chunk-myypc3tn.js +46 -0
- package/dist/chunk-mzcnmnpq.js +3379 -0
- package/dist/chunk-mznav6d1.js +194 -0
- package/dist/chunk-n0qxskpr.js +24 -0
- package/dist/chunk-n6a6hgtp.js +394 -0
- package/dist/chunk-n6d5fgx0.js +254 -0
- package/dist/chunk-n6ym3n03.js +120 -0
- package/dist/chunk-n9g24mwe.js +104 -0
- package/dist/chunk-naamqdf9.js +185 -0
- package/dist/chunk-nb2jk7zj.js +15 -0
- package/dist/chunk-nbkbq9en.js +67 -0
- package/dist/chunk-ndttd6es.js +38 -0
- package/dist/chunk-nfygaaxg.js +133 -0
- package/dist/chunk-ngdzpszd.js +454 -0
- package/dist/chunk-nmfwksa4.js +1297 -0
- package/dist/chunk-nt837qt9.js +21 -0
- package/dist/chunk-nwc3v0vp.js +691 -0
- package/dist/chunk-nz8ha95p.js +3610 -0
- package/dist/chunk-nzxfj0gq.js +2007 -0
- package/dist/chunk-p0r8887g.js +6932 -0
- package/dist/chunk-p1seyqdm.js +120 -0
- package/dist/chunk-p425zbgw.js +726 -0
- package/dist/chunk-p7hamd2c.js +146 -0
- package/dist/chunk-pdvg91cg.js +32 -0
- package/dist/chunk-pecy49yr.js +14649 -0
- package/dist/chunk-pfxrg89f.js +547 -0
- package/dist/chunk-pfyw3155.js +2750 -0
- package/dist/chunk-pr8m11pm.js +1192 -0
- package/dist/chunk-ptxteaeh.js +1591 -0
- package/dist/chunk-pv164mac.js +394 -0
- package/dist/chunk-pxxhtxf5.js +10154 -0
- package/dist/chunk-q0e485mg.js +61 -0
- package/dist/chunk-q1vrhh0q.js +458 -0
- package/dist/chunk-q2h79ncs.js +370 -0
- package/dist/chunk-q3b4n194.js +56 -0
- package/dist/chunk-q44zc68f.js +4301 -0
- package/dist/chunk-q8gknbdx.js +352 -0
- package/dist/chunk-q8xk3kdj.js +11 -0
- package/dist/chunk-qak46xtp.js +119 -0
- package/dist/chunk-qfq7absv.js +95 -0
- package/dist/chunk-qfsn720k.js +151 -0
- package/dist/chunk-qg4811f6.js +228 -0
- package/dist/chunk-qgzn3qps.js +90 -0
- package/dist/chunk-qhaggqkt.js +113 -0
- package/dist/chunk-qjjp27z8.js +195 -0
- package/dist/chunk-qxp0nye6.js +34 -0
- package/dist/chunk-qy3nagaq.js +4957 -0
- package/dist/chunk-qz2meav1.js +1452 -0
- package/dist/chunk-r50hne7m.js +63 -0
- package/dist/chunk-r6m0vgnv.js +80 -0
- package/dist/chunk-r7yw38vf.js +22864 -0
- package/dist/chunk-r8xc618w.js +42 -0
- package/dist/chunk-r961r5kj.js +87 -0
- package/dist/chunk-r9b5xrh0.js +66 -0
- package/dist/chunk-rcn2pd6q.js +477 -0
- package/dist/chunk-rdeh8p3y.js +148 -0
- package/dist/chunk-rg9x1742.js +542 -0
- package/dist/chunk-rgyzsbs3.js +39 -0
- package/dist/chunk-rk2fsxtz.js +16 -0
- package/dist/chunk-rkchkwv9.js +40 -0
- package/dist/chunk-rp8whpb3.js +478 -0
- package/dist/chunk-rpkxdtgr.js +68 -0
- package/dist/chunk-rpmntgyh.js +394 -0
- package/dist/chunk-rpshz4dy.js +614 -0
- package/dist/chunk-rqd60ay5.js +133 -0
- package/dist/chunk-rrsjf2ea.js +229 -0
- package/dist/chunk-rtjk8c8e.js +173 -0
- package/dist/chunk-rw0y2wdf.js +1017 -0
- package/dist/chunk-rx5w7ess.js +663 -0
- package/dist/chunk-rx8t9d35.js +1947 -0
- package/dist/chunk-rxcazxgf.js +195 -0
- package/dist/chunk-rxg6q3bp.js +1413 -0
- package/dist/chunk-rxrb7xnd.js +71 -0
- package/dist/chunk-rxrzxff3.js +118 -0
- package/dist/chunk-ryqjc943.js +71 -0
- package/dist/chunk-rzk9k2rf.js +81 -0
- package/dist/chunk-s2qv0nht.js +119 -0
- package/dist/chunk-s3hafnk3.js +2285 -0
- package/dist/chunk-s4a496tt.js +226 -0
- package/dist/chunk-s4d1h3ka.js +35 -0
- package/dist/chunk-sm3k3ze4.js +16525 -0
- package/dist/chunk-sn0bja82.js +385 -0
- package/dist/chunk-sngjggw1.js +4227 -0
- package/dist/chunk-sq047n34.js +364 -0
- package/dist/chunk-sttwe2tw.js +8584 -0
- package/dist/chunk-sw8qx1r0.js +86 -0
- package/dist/chunk-swstah6a.js +240 -0
- package/dist/chunk-syrkr0mf.js +63 -0
- package/dist/chunk-sz206bd9.js +26 -0
- package/dist/chunk-t09669cj.js +333 -0
- package/dist/chunk-t5f8e30k.js +602 -0
- package/dist/chunk-t5m78mc8.js +432 -0
- package/dist/chunk-t5x1dqwn.js +143 -0
- package/dist/chunk-t877ea0w.js +168 -0
- package/dist/chunk-t91hb71c.js +17 -0
- package/dist/chunk-tb636bcf.js +942 -0
- package/dist/chunk-tb8sykbr.js +426 -0
- package/dist/chunk-tbdkekz3.js +125 -0
- package/dist/chunk-td2gsz7s.js +225 -0
- package/dist/chunk-tenvxbyh.js +20 -0
- package/dist/chunk-texg4qqt.js +317 -0
- package/dist/chunk-teymzz80.js +266 -0
- package/dist/chunk-tj26qpf7.js +153 -0
- package/dist/chunk-tk85ec4p.js +395 -0
- package/dist/chunk-tq205h01.js +164 -0
- package/dist/chunk-tqzddjzg.js +61 -0
- package/dist/chunk-trqrj23e.js +134 -0
- package/dist/chunk-tw1hfsxv.js +2477 -0
- package/dist/chunk-txxdfq83.js +122 -0
- package/dist/chunk-v0yhe582.js +31 -0
- package/dist/chunk-v14184xm.js +15 -0
- package/dist/chunk-v1h9z4hw.js +138 -0
- package/dist/chunk-v3ey5j7f.js +329 -0
- package/dist/chunk-v3nh1sfn.js +208 -0
- package/dist/chunk-v3x8tcc0.js +45 -0
- package/dist/chunk-v4nqnvqq.js +3984 -0
- package/dist/chunk-v4ypszbb.js +15 -0
- package/dist/chunk-v7wbqcx9.js +63 -0
- package/dist/chunk-v8r5fev3.js +341 -0
- package/dist/chunk-v9zg5kzx.js +2810 -0
- package/dist/chunk-va1wh5ss.js +24 -0
- package/dist/chunk-vbfswhht.js +42 -0
- package/dist/chunk-ve7x2tfq.js +124 -0
- package/dist/chunk-vfz8k89y.js +485 -0
- package/dist/chunk-vgm5k14x.js +35678 -0
- package/dist/chunk-vh9pej3c.js +247 -0
- package/dist/chunk-vjxqyt6f.js +3820 -0
- package/dist/chunk-vpb1xstn.js +178 -0
- package/dist/chunk-vqt79tj8.js +110 -0
- package/dist/chunk-vr0n9pv9.js +152 -0
- package/dist/chunk-vrejmja5.js +90 -0
- package/dist/chunk-vrxasmdw.js +449 -0
- package/dist/chunk-vrxb946v.js +125 -0
- package/dist/chunk-vv4kj0q8.js +98 -0
- package/dist/chunk-vvpfng7w.js +8 -0
- package/dist/chunk-vw6ybyew.js +2007 -0
- package/dist/chunk-vwenx8ke.js +17 -0
- package/dist/chunk-vwfa0s5a.js +155 -0
- package/dist/chunk-vx71j8xe.js +63 -0
- package/dist/chunk-vxbjzggp.js +43 -0
- package/dist/chunk-vxjxtz8w.js +440 -0
- package/dist/chunk-vy0c1bwp.js +9 -0
- package/dist/chunk-w3zczyse.js +14 -0
- package/dist/chunk-w4p5t920.js +655 -0
- package/dist/chunk-w68wc625.js +287 -0
- package/dist/chunk-w9ddp3yf.js +96 -0
- package/dist/chunk-wcggm5ja.js +125 -0
- package/dist/chunk-wgnyph3q.js +1306 -0
- package/dist/chunk-wjm5pc1e.js +134 -0
- package/dist/chunk-wnve0drm.js +131 -0
- package/dist/chunk-wp27ev2k.js +135 -0
- package/dist/chunk-wyvy8a4x.js +131 -0
- package/dist/chunk-x671y4dk.js +129 -0
- package/dist/chunk-xbj5keyy.js +22 -0
- package/dist/chunk-xf4fzms8.js +39 -0
- package/dist/chunk-xf59k3zg.js +65 -0
- package/dist/chunk-xgzc4w49.js +204 -0
- package/dist/chunk-xhj7g13b.js +2149 -0
- package/dist/chunk-xjp0cd00.js +56 -0
- package/dist/chunk-xkhnmhqs.js +74 -0
- package/dist/chunk-xkrkqx61.js +55 -0
- package/dist/chunk-xmpgmeb8.js +114 -0
- package/dist/chunk-xrw80zgd.js +4249 -0
- package/dist/chunk-xrzc96g0.js +202 -0
- package/dist/chunk-xt76sm44.js +318 -0
- package/dist/chunk-xwet3awb.js +20 -0
- package/dist/chunk-xyg1sk2w.js +78 -0
- package/dist/chunk-y0jpkqb0.js +180 -0
- package/dist/chunk-y1q7rt9n.js +102 -0
- package/dist/chunk-y67ntyek.js +258 -0
- package/dist/chunk-ybk37qp9.js +37 -0
- package/dist/chunk-yc1stfve.js +5386 -0
- package/dist/chunk-ychjpjef.js +62 -0
- package/dist/chunk-yez8fa9g.js +276 -0
- package/dist/chunk-ygm7xszr.js +90 -0
- package/dist/chunk-ym11azkj.js +37 -0
- package/dist/chunk-ympz2h15.js +578 -0
- package/dist/chunk-yqx3az3n.js +129 -0
- package/dist/chunk-yt3nfhcc.js +152 -0
- package/dist/chunk-yy8q0n8s.js +120 -0
- package/dist/chunk-yzb92zxv.js +8 -0
- package/dist/chunk-yzet6xyr.js +119 -0
- package/dist/chunk-yzm97qp1.js +226 -0
- package/dist/chunk-z0jgeax8.js +35 -0
- package/dist/chunk-z1r3z6w6.js +29 -0
- package/dist/chunk-z2dp53wn.js +17 -0
- package/dist/chunk-z79355gz.js +308 -0
- package/dist/chunk-z7e94hxz.js +251 -0
- package/dist/chunk-z8cqdcec.js +173 -0
- package/dist/chunk-z99tbg45.js +148 -0
- package/dist/chunk-z9nsjcht.js +37 -0
- package/dist/chunk-za3k6h2h.js +470 -0
- package/dist/chunk-zacynq5p.js +265 -0
- package/dist/chunk-zb0x40az.js +1785 -0
- package/dist/chunk-zbxtzycc.js +274 -0
- package/dist/chunk-zga50181.js +342 -0
- package/dist/chunk-zhb2pns1.js +44 -0
- package/dist/chunk-zkch6trx.js +231 -0
- package/dist/chunk-znf3z4qt.js +954 -0
- package/dist/chunk-zp8zwdgq.js +72 -0
- package/dist/chunk-ztjd8pyf.js +120 -0
- package/dist/chunk-ztmb7geg.js +173 -0
- package/dist/chunk-zvr4snzv.js +887 -0
- package/dist/chunk-zw62m6n3.js +34858 -0
- package/dist/chunk-zwwdebd0.js +65 -0
- package/dist/chunk-zxc6x9w8.js +340 -0
- package/dist/chunk-zy2e7sz0.js +8 -0
- package/dist/chunk-zzf074w3.js +196 -0
- package/dist/chunk-zzz0nwb5.js +310 -0
- package/dist/cli-bun.js +2 -0
- package/dist/cli-node.js +2 -0
- package/dist/cli.js +218 -0
- package/dist/vendor/audio-capture/arm64-darwin/audio-capture.node +0 -0
- package/dist/vendor/audio-capture/arm64-linux/audio-capture.node +0 -0
- package/dist/vendor/audio-capture/arm64-win32/audio-capture.node +0 -0
- package/dist/vendor/audio-capture/x64-darwin/audio-capture.node +0 -0
- package/dist/vendor/audio-capture/x64-linux/audio-capture.node +0 -0
- package/dist/vendor/audio-capture/x64-win32/audio-capture.node +0 -0
- package/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/package.json +243 -0
- package/scripts/chrome-mcp-bridge-resolver.mjs +43 -0
- package/scripts/chrome-mcp-env.mjs +19 -0
- package/scripts/postinstall.cjs +339 -0
- package/scripts/run-parallel.mjs +10 -0
- package/scripts/setup-chrome-mcp.mjs +69 -0
|
@@ -0,0 +1,1297 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
$toString,
|
|
4
|
+
init_server as init_server2
|
|
5
|
+
} from "./chunk-xrw80zgd.js";
|
|
6
|
+
import {
|
|
7
|
+
StdioServerTransport,
|
|
8
|
+
init_stdio
|
|
9
|
+
} from "./chunk-jccjaddz.js";
|
|
10
|
+
import"./chunk-vxbjzggp.js";
|
|
11
|
+
import {
|
|
12
|
+
CallToolRequestSchema,
|
|
13
|
+
ListToolsRequestSchema,
|
|
14
|
+
Server,
|
|
15
|
+
init_server,
|
|
16
|
+
init_types
|
|
17
|
+
} from "./chunk-7qx3xhv3.js";
|
|
18
|
+
import"./chunk-j9475b46.js";
|
|
19
|
+
import"./chunk-fdwabr8p.js";
|
|
20
|
+
import {
|
|
21
|
+
getPreferredUserConfigSubdir,
|
|
22
|
+
getUserConfigSubdirs,
|
|
23
|
+
init_redscopeCompat,
|
|
24
|
+
uniquePaths
|
|
25
|
+
} from "./chunk-s3hafnk3.js";
|
|
26
|
+
import"./chunk-kb3758f7.js";
|
|
27
|
+
import"./chunk-9h9k5vz3.js";
|
|
28
|
+
import"./chunk-xmpgmeb8.js";
|
|
29
|
+
import"./chunk-2kz09j2s.js";
|
|
30
|
+
import"./chunk-c0k7b0jw.js";
|
|
31
|
+
import"./chunk-hhsxm2yr.js";
|
|
32
|
+
|
|
33
|
+
// packages/weixin/src/types.ts
|
|
34
|
+
var MessageType = {
|
|
35
|
+
NONE: 0,
|
|
36
|
+
USER: 1,
|
|
37
|
+
BOT: 2
|
|
38
|
+
};
|
|
39
|
+
var MessageItemType = {
|
|
40
|
+
NONE: 0,
|
|
41
|
+
TEXT: 1,
|
|
42
|
+
IMAGE: 2,
|
|
43
|
+
VOICE: 3,
|
|
44
|
+
FILE: 4,
|
|
45
|
+
VIDEO: 5
|
|
46
|
+
};
|
|
47
|
+
var MessageState = {
|
|
48
|
+
NEW: 0,
|
|
49
|
+
GENERATING: 1,
|
|
50
|
+
FINISH: 2
|
|
51
|
+
};
|
|
52
|
+
var UploadMediaType = {
|
|
53
|
+
IMAGE: 1,
|
|
54
|
+
VIDEO: 2,
|
|
55
|
+
FILE: 3,
|
|
56
|
+
VOICE: 4
|
|
57
|
+
};
|
|
58
|
+
var TypingStatus = {
|
|
59
|
+
TYPING: 1,
|
|
60
|
+
CANCEL: 2
|
|
61
|
+
};
|
|
62
|
+
// packages/weixin/src/api.ts
|
|
63
|
+
import { randomBytes } from "crypto";
|
|
64
|
+
var CHANNEL_VERSION = "0.1.0";
|
|
65
|
+
function baseInfo() {
|
|
66
|
+
return { channel_version: CHANNEL_VERSION };
|
|
67
|
+
}
|
|
68
|
+
function randomUin() {
|
|
69
|
+
return randomBytes(4).toString("base64");
|
|
70
|
+
}
|
|
71
|
+
function buildHeaders(token) {
|
|
72
|
+
const headers = {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
"X-WECHAT-UIN": randomUin()
|
|
75
|
+
};
|
|
76
|
+
if (token) {
|
|
77
|
+
headers.AuthorizationType = "ilink_bot_token";
|
|
78
|
+
headers.Authorization = `Bearer ${token}`;
|
|
79
|
+
}
|
|
80
|
+
return headers;
|
|
81
|
+
}
|
|
82
|
+
async function post(baseUrl, path, body, token, timeoutMs = 40000, signal) {
|
|
83
|
+
const controller = new AbortController;
|
|
84
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
85
|
+
if (signal) {
|
|
86
|
+
signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(`${baseUrl}${path}`, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: buildHeaders(token),
|
|
92
|
+
body: JSON.stringify(body),
|
|
93
|
+
signal: controller.signal
|
|
94
|
+
});
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
97
|
+
}
|
|
98
|
+
return await response.json();
|
|
99
|
+
} finally {
|
|
100
|
+
clearTimeout(timeout);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function getUpdates(baseUrl, token, getUpdatesBuf, signal) {
|
|
104
|
+
const body = {
|
|
105
|
+
get_updates_buf: getUpdatesBuf,
|
|
106
|
+
base_info: baseInfo()
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
return await post(baseUrl, "/ilink/bot/getupdates", body, token, 40000, signal);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
112
|
+
return { ret: 0, msgs: [], get_updates_buf: getUpdatesBuf };
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function sendMessage(baseUrl, token, msg) {
|
|
118
|
+
const body = { msg, base_info: baseInfo() };
|
|
119
|
+
await post(baseUrl, "/ilink/bot/sendmessage", body, token);
|
|
120
|
+
}
|
|
121
|
+
async function getUploadUrl(baseUrl, token, params) {
|
|
122
|
+
return post(baseUrl, "/ilink/bot/getuploadurl", { ...params, base_info: baseInfo() }, token);
|
|
123
|
+
}
|
|
124
|
+
async function getConfig(baseUrl, token, userId, contextToken) {
|
|
125
|
+
return post(baseUrl, "/ilink/bot/getconfig", {
|
|
126
|
+
ilink_user_id: userId,
|
|
127
|
+
context_token: contextToken,
|
|
128
|
+
base_info: baseInfo()
|
|
129
|
+
}, token);
|
|
130
|
+
}
|
|
131
|
+
async function sendTyping(baseUrl, token, req) {
|
|
132
|
+
return post(baseUrl, "/ilink/bot/sendtyping", { ...req, base_info: baseInfo() }, token);
|
|
133
|
+
}
|
|
134
|
+
// packages/weixin/src/accounts.ts
|
|
135
|
+
init_redscopeCompat();
|
|
136
|
+
import {
|
|
137
|
+
chmodSync,
|
|
138
|
+
existsSync,
|
|
139
|
+
mkdirSync,
|
|
140
|
+
readFileSync,
|
|
141
|
+
unlinkSync,
|
|
142
|
+
writeFileSync
|
|
143
|
+
} from "fs";
|
|
144
|
+
import { join } from "path";
|
|
145
|
+
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
146
|
+
var CDN_BASE_URL = "https://novac2c.cdn.weixin.qq.com/c2c";
|
|
147
|
+
function getStateDir() {
|
|
148
|
+
const dir = process.env.WEIXIN_STATE_DIR || getPreferredUserConfigSubdir(join("channels", "weixin"));
|
|
149
|
+
if (!existsSync(dir)) {
|
|
150
|
+
mkdirSync(dir, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
return dir;
|
|
153
|
+
}
|
|
154
|
+
function getStateDirs() {
|
|
155
|
+
if (process.env.WEIXIN_STATE_DIR) {
|
|
156
|
+
return [process.env.WEIXIN_STATE_DIR];
|
|
157
|
+
}
|
|
158
|
+
return getUserConfigSubdirs(join("channels", "weixin"));
|
|
159
|
+
}
|
|
160
|
+
function getStateFilePaths(filename) {
|
|
161
|
+
return uniquePaths(getStateDirs().map((dir) => join(dir, filename)));
|
|
162
|
+
}
|
|
163
|
+
function getPreferredStateFilePath(filename) {
|
|
164
|
+
return join(getStateDir(), filename);
|
|
165
|
+
}
|
|
166
|
+
function loadAccount() {
|
|
167
|
+
for (const path of getStateFilePaths("account.json")) {
|
|
168
|
+
if (!existsSync(path))
|
|
169
|
+
continue;
|
|
170
|
+
try {
|
|
171
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
function saveAccount(data) {
|
|
179
|
+
const path = getPreferredStateFilePath("account.json");
|
|
180
|
+
writeFileSync(path, JSON.stringify(data, null, 2), "utf-8");
|
|
181
|
+
chmodSync(path, 384);
|
|
182
|
+
}
|
|
183
|
+
function clearAccount() {
|
|
184
|
+
for (const path of getStateFilePaths("account.json")) {
|
|
185
|
+
if (existsSync(path)) {
|
|
186
|
+
unlinkSync(path);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// packages/weixin/src/login.ts
|
|
191
|
+
init_server2();
|
|
192
|
+
async function renderQrCodeToTerminal(qrcodeUrl) {
|
|
193
|
+
const output = await $toString(qrcodeUrl, {
|
|
194
|
+
type: "terminal",
|
|
195
|
+
errorCorrectionLevel: "L",
|
|
196
|
+
small: true
|
|
197
|
+
});
|
|
198
|
+
process.stderr.write(`${output}
|
|
199
|
+
`);
|
|
200
|
+
}
|
|
201
|
+
async function startLogin(apiBaseUrl) {
|
|
202
|
+
const response = await fetch(`${apiBaseUrl}/ilink/bot/get_bot_qrcode?bot_type=3`);
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
throw new Error(`Failed to get QR code: HTTP ${response.status}`);
|
|
205
|
+
}
|
|
206
|
+
const data = await response.json();
|
|
207
|
+
if (!data.qrcode) {
|
|
208
|
+
throw new Error("No qrcode in response");
|
|
209
|
+
}
|
|
210
|
+
const qrcodeUrl = data.qrcode_img_content || "";
|
|
211
|
+
if (qrcodeUrl) {
|
|
212
|
+
await renderQrCodeToTerminal(qrcodeUrl);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
qrcodeUrl,
|
|
216
|
+
qrcodeId: data.qrcode,
|
|
217
|
+
message: "Scan the QR code with WeChat to connect."
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async function waitForLogin(params) {
|
|
221
|
+
const { qrcodeId, apiBaseUrl, timeoutMs = 480000, maxRetries = 3 } = params;
|
|
222
|
+
const deadline = Date.now() + timeoutMs;
|
|
223
|
+
let currentQrcodeId = qrcodeId;
|
|
224
|
+
let retryCount = 0;
|
|
225
|
+
while (Date.now() < deadline) {
|
|
226
|
+
try {
|
|
227
|
+
const controller = new AbortController;
|
|
228
|
+
const timeout = setTimeout(() => controller.abort(), 60000);
|
|
229
|
+
const response = await fetch(`${apiBaseUrl}/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(currentQrcodeId)}`, {
|
|
230
|
+
headers: { "iLink-App-ClientVersion": "1" },
|
|
231
|
+
signal: controller.signal
|
|
232
|
+
});
|
|
233
|
+
clearTimeout(timeout);
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
throw new Error(`HTTP ${response.status}`);
|
|
236
|
+
}
|
|
237
|
+
const data = await response.json();
|
|
238
|
+
switch (data.status) {
|
|
239
|
+
case "confirmed":
|
|
240
|
+
return {
|
|
241
|
+
connected: true,
|
|
242
|
+
token: data.bot_token,
|
|
243
|
+
accountId: data.ilink_bot_id,
|
|
244
|
+
baseUrl: data.baseurl,
|
|
245
|
+
userId: data.ilink_user_id,
|
|
246
|
+
message: "Connected to WeChat successfully!"
|
|
247
|
+
};
|
|
248
|
+
case "scaned":
|
|
249
|
+
process.stderr.write(`QR code scanned, waiting for confirmation...
|
|
250
|
+
`);
|
|
251
|
+
break;
|
|
252
|
+
case "expired": {
|
|
253
|
+
retryCount += 1;
|
|
254
|
+
if (retryCount >= maxRetries) {
|
|
255
|
+
return {
|
|
256
|
+
connected: false,
|
|
257
|
+
message: "QR code expired after maximum retries."
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
process.stderr.write(`QR code expired, refreshing...
|
|
261
|
+
`);
|
|
262
|
+
const refreshed = await startLogin(apiBaseUrl);
|
|
263
|
+
currentQrcodeId = refreshed.qrcodeId;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case "wait":
|
|
267
|
+
default:
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
277
|
+
}
|
|
278
|
+
return { connected: false, message: "Login timed out." };
|
|
279
|
+
}
|
|
280
|
+
// packages/weixin/src/pairing.ts
|
|
281
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
282
|
+
function configPath() {
|
|
283
|
+
return getPreferredStateFilePath("access.json");
|
|
284
|
+
}
|
|
285
|
+
function pendingPath() {
|
|
286
|
+
return getPreferredStateFilePath("pending-pairings.json");
|
|
287
|
+
}
|
|
288
|
+
function loadPending() {
|
|
289
|
+
for (const path of getStateFilePaths("pending-pairings.json")) {
|
|
290
|
+
if (!existsSync2(path))
|
|
291
|
+
continue;
|
|
292
|
+
try {
|
|
293
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
294
|
+
} catch {
|
|
295
|
+
return {};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return {};
|
|
299
|
+
}
|
|
300
|
+
function savePending(data) {
|
|
301
|
+
writeFileSync2(pendingPath(), JSON.stringify(data, null, 2), "utf-8");
|
|
302
|
+
}
|
|
303
|
+
function loadAccessConfig() {
|
|
304
|
+
for (const path of getStateFilePaths("access.json")) {
|
|
305
|
+
if (!existsSync2(path))
|
|
306
|
+
continue;
|
|
307
|
+
try {
|
|
308
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
309
|
+
} catch {
|
|
310
|
+
return { policy: "pairing", allowFrom: [] };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return { policy: "pairing", allowFrom: [] };
|
|
314
|
+
}
|
|
315
|
+
function saveAccessConfig(config) {
|
|
316
|
+
writeFileSync2(configPath(), JSON.stringify(config, null, 2), "utf-8");
|
|
317
|
+
}
|
|
318
|
+
function isAllowed(userId) {
|
|
319
|
+
const config = loadAccessConfig();
|
|
320
|
+
if (config.policy === "disabled")
|
|
321
|
+
return true;
|
|
322
|
+
return config.allowFrom.includes(userId);
|
|
323
|
+
}
|
|
324
|
+
function addPendingPairing(userId) {
|
|
325
|
+
const pending = loadPending();
|
|
326
|
+
const now = Date.now();
|
|
327
|
+
for (const code2 of Object.keys(pending)) {
|
|
328
|
+
if (pending[code2].expiresAt < now) {
|
|
329
|
+
delete pending[code2];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
for (const [code2, entry] of Object.entries(pending)) {
|
|
333
|
+
if (entry.userId === userId) {
|
|
334
|
+
savePending(pending);
|
|
335
|
+
return code2;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const code = String(Math.floor(1e5 + Math.random() * 900000));
|
|
339
|
+
pending[code] = { userId, expiresAt: now + 10 * 60 * 1000 };
|
|
340
|
+
savePending(pending);
|
|
341
|
+
return code;
|
|
342
|
+
}
|
|
343
|
+
function confirmPairing(code) {
|
|
344
|
+
const pending = loadPending();
|
|
345
|
+
const entry = pending[code];
|
|
346
|
+
if (!entry || entry.expiresAt < Date.now()) {
|
|
347
|
+
delete pending[code];
|
|
348
|
+
savePending(pending);
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
delete pending[code];
|
|
352
|
+
savePending(pending);
|
|
353
|
+
const config = loadAccessConfig();
|
|
354
|
+
if (!config.allowFrom.includes(entry.userId)) {
|
|
355
|
+
config.allowFrom.push(entry.userId);
|
|
356
|
+
saveAccessConfig(config);
|
|
357
|
+
}
|
|
358
|
+
return entry.userId;
|
|
359
|
+
}
|
|
360
|
+
// packages/weixin/src/media.ts
|
|
361
|
+
import {
|
|
362
|
+
createCipheriv,
|
|
363
|
+
createDecipheriv,
|
|
364
|
+
createHash,
|
|
365
|
+
randomBytes as randomBytes2
|
|
366
|
+
} from "crypto";
|
|
367
|
+
import {
|
|
368
|
+
existsSync as existsSync3,
|
|
369
|
+
mkdirSync as mkdirSync2,
|
|
370
|
+
readFileSync as readFileSync3,
|
|
371
|
+
writeFileSync as writeFileSync3
|
|
372
|
+
} from "fs";
|
|
373
|
+
import { tmpdir } from "os";
|
|
374
|
+
import { basename, extname, join as join2 } from "path";
|
|
375
|
+
function encryptAesEcb(plaintext, key) {
|
|
376
|
+
const cipher = createCipheriv("aes-128-ecb", key, null);
|
|
377
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
378
|
+
}
|
|
379
|
+
function decryptAesEcb(ciphertext, key) {
|
|
380
|
+
const decipher = createDecipheriv("aes-128-ecb", key, null);
|
|
381
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
382
|
+
}
|
|
383
|
+
function aesEcbPaddedSize(size) {
|
|
384
|
+
return size + (16 - size % 16);
|
|
385
|
+
}
|
|
386
|
+
function buildCdnDownloadUrl(encryptedQueryParam, cdnBaseUrl) {
|
|
387
|
+
return `${cdnBaseUrl}/download?encrypted_query_param=${encodeURIComponent(encryptedQueryParam)}`;
|
|
388
|
+
}
|
|
389
|
+
function buildCdnUploadUrl(cdnBaseUrl, uploadParam, filekey) {
|
|
390
|
+
return `${cdnBaseUrl}/upload?encrypted_query_param=${encodeURIComponent(uploadParam)}&filekey=${encodeURIComponent(filekey)}`;
|
|
391
|
+
}
|
|
392
|
+
function parseAesKey(aesKeyBase64) {
|
|
393
|
+
const decoded = Buffer.from(aesKeyBase64, "base64");
|
|
394
|
+
if (decoded.length === 16) {
|
|
395
|
+
return decoded;
|
|
396
|
+
}
|
|
397
|
+
if (decoded.length === 32 && /^[0-9a-fA-F]{32}$/.test(decoded.toString("ascii"))) {
|
|
398
|
+
return Buffer.from(decoded.toString("ascii"), "hex");
|
|
399
|
+
}
|
|
400
|
+
throw new Error(`Invalid aes_key: expected 16 raw bytes or 32 hex chars, got ${decoded.length} bytes`);
|
|
401
|
+
}
|
|
402
|
+
async function downloadAndDecrypt(params) {
|
|
403
|
+
const url = buildCdnDownloadUrl(params.encryptQueryParam, params.cdnBaseUrl);
|
|
404
|
+
const response = await fetch(url);
|
|
405
|
+
if (!response.ok) {
|
|
406
|
+
throw new Error(`CDN download failed: HTTP ${response.status}`);
|
|
407
|
+
}
|
|
408
|
+
const ciphertext = Buffer.from(await response.arrayBuffer());
|
|
409
|
+
return decryptAesEcb(ciphertext, parseAesKey(params.aesKey));
|
|
410
|
+
}
|
|
411
|
+
async function uploadFile(params) {
|
|
412
|
+
const plaintext = readFileSync3(params.filePath);
|
|
413
|
+
const rawSize = plaintext.length;
|
|
414
|
+
const rawMd5 = createHash("md5").update(plaintext).digest("hex");
|
|
415
|
+
const aesKey = randomBytes2(16);
|
|
416
|
+
const filekey = randomBytes2(16).toString("hex");
|
|
417
|
+
const ciphertext = encryptAesEcb(plaintext, aesKey);
|
|
418
|
+
const fileSize = ciphertext.length;
|
|
419
|
+
const uploadResp = await getUploadUrl(params.apiBaseUrl, params.token, {
|
|
420
|
+
filekey,
|
|
421
|
+
media_type: params.mediaType,
|
|
422
|
+
to_user_id: params.toUserId,
|
|
423
|
+
rawsize: rawSize,
|
|
424
|
+
rawfilemd5: rawMd5,
|
|
425
|
+
filesize: fileSize,
|
|
426
|
+
no_need_thumb: true,
|
|
427
|
+
aeskey: aesKey.toString("hex")
|
|
428
|
+
});
|
|
429
|
+
if (!uploadResp.upload_param) {
|
|
430
|
+
throw new Error("No upload_param in response");
|
|
431
|
+
}
|
|
432
|
+
const uploadUrl = buildCdnUploadUrl(params.cdnBaseUrl, uploadResp.upload_param, filekey);
|
|
433
|
+
const uploadResult = await fetch(uploadUrl, {
|
|
434
|
+
method: "POST",
|
|
435
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
436
|
+
body: new Uint8Array(ciphertext)
|
|
437
|
+
});
|
|
438
|
+
if (!uploadResult.ok) {
|
|
439
|
+
throw new Error(`CDN upload failed: HTTP ${uploadResult.status}`);
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
encryptQueryParam: uploadResult.headers.get("x-encrypted-param") || "",
|
|
443
|
+
aesKey: Buffer.from(aesKey.toString("hex")).toString("base64"),
|
|
444
|
+
fileSize,
|
|
445
|
+
rawSize,
|
|
446
|
+
fileName: basename(params.filePath)
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function guessMediaType(filePath) {
|
|
450
|
+
const ext = extname(filePath).toLowerCase();
|
|
451
|
+
const imageExts = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".heic"];
|
|
452
|
+
const videoExts = [".mp4", ".mov", ".avi", ".mkv", ".webm"];
|
|
453
|
+
if (imageExts.includes(ext))
|
|
454
|
+
return UploadMediaType.IMAGE;
|
|
455
|
+
if (videoExts.includes(ext))
|
|
456
|
+
return UploadMediaType.VIDEO;
|
|
457
|
+
return UploadMediaType.FILE;
|
|
458
|
+
}
|
|
459
|
+
async function downloadRemoteToTemp(url, destDir) {
|
|
460
|
+
const dir = destDir || join2(tmpdir(), "weixin-downloads");
|
|
461
|
+
if (!existsSync3(dir))
|
|
462
|
+
mkdirSync2(dir, { recursive: true });
|
|
463
|
+
const response = await fetch(url);
|
|
464
|
+
if (!response.ok)
|
|
465
|
+
throw new Error(`Download failed: HTTP ${response.status}`);
|
|
466
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
467
|
+
const urlPath = new URL(url).pathname;
|
|
468
|
+
const name = basename(urlPath) || `file_${Date.now()}`;
|
|
469
|
+
const dest = join2(dir, name);
|
|
470
|
+
writeFileSync3(dest, buffer);
|
|
471
|
+
return dest;
|
|
472
|
+
}
|
|
473
|
+
// packages/weixin/src/send.ts
|
|
474
|
+
import { randomUUID } from "crypto";
|
|
475
|
+
function stripCodeBlocks(text) {
|
|
476
|
+
let result = "";
|
|
477
|
+
let i = 0;
|
|
478
|
+
while (i < text.length) {
|
|
479
|
+
if (text.startsWith("```", i)) {
|
|
480
|
+
let j = i + 3;
|
|
481
|
+
while (j < text.length && text[j] !== `
|
|
482
|
+
`)
|
|
483
|
+
j++;
|
|
484
|
+
if (j < text.length)
|
|
485
|
+
j++;
|
|
486
|
+
const contentStart = j;
|
|
487
|
+
while (j < text.length) {
|
|
488
|
+
if (text.startsWith("```", j)) {
|
|
489
|
+
result += text.slice(contentStart, j);
|
|
490
|
+
j += 3;
|
|
491
|
+
while (j < text.length && text[j] !== `
|
|
492
|
+
`)
|
|
493
|
+
j++;
|
|
494
|
+
if (j < text.length)
|
|
495
|
+
j++;
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
j++;
|
|
499
|
+
}
|
|
500
|
+
if (j >= text.length && !text.startsWith("```", j - 3)) {
|
|
501
|
+
result += text.slice(i);
|
|
502
|
+
}
|
|
503
|
+
i = j;
|
|
504
|
+
} else {
|
|
505
|
+
result += text[i];
|
|
506
|
+
i++;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
511
|
+
function markdownToPlainText(text) {
|
|
512
|
+
return stripCodeBlocks(text).replace(/`([^`]+)`/g, "$1").replace(/\*\*\*(.+?)\*\*\*/g, "$1").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/___(.+?)___/g, "$1").replace(/__(.+?)__/g, "$1").replace(/_(.+?)_/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)").replace(/!\[([^\]]*)\]\([^)]+\)/g, "[$1]").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}$/gm, "---").replace(/^[\s]*[-*+]\s+/gm, "- ").replace(/^[\s]*(\d+)\.\s+/gm, "$1. ").replace(/\n{3,}/g, `
|
|
513
|
+
|
|
514
|
+
`).trim();
|
|
515
|
+
}
|
|
516
|
+
async function sendText(params) {
|
|
517
|
+
const clientId = randomUUID();
|
|
518
|
+
await sendMessage(params.baseUrl, params.token, {
|
|
519
|
+
to_user_id: params.to,
|
|
520
|
+
from_user_id: "",
|
|
521
|
+
client_id: clientId,
|
|
522
|
+
message_type: MessageType.BOT,
|
|
523
|
+
message_state: MessageState.FINISH,
|
|
524
|
+
context_token: params.contextToken,
|
|
525
|
+
item_list: [
|
|
526
|
+
{
|
|
527
|
+
type: MessageItemType.TEXT,
|
|
528
|
+
text_item: { text: markdownToPlainText(params.text) }
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
});
|
|
532
|
+
return { messageId: clientId };
|
|
533
|
+
}
|
|
534
|
+
async function sendItems(params) {
|
|
535
|
+
let lastClientId = "";
|
|
536
|
+
for (const item of params.items) {
|
|
537
|
+
lastClientId = randomUUID();
|
|
538
|
+
await sendMessage(params.baseUrl, params.token, {
|
|
539
|
+
to_user_id: params.to,
|
|
540
|
+
from_user_id: "",
|
|
541
|
+
client_id: lastClientId,
|
|
542
|
+
message_type: MessageType.BOT,
|
|
543
|
+
message_state: MessageState.FINISH,
|
|
544
|
+
context_token: params.contextToken,
|
|
545
|
+
item_list: [item]
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return lastClientId;
|
|
549
|
+
}
|
|
550
|
+
async function sendMediaFile(params) {
|
|
551
|
+
const mediaType = guessMediaType(params.filePath);
|
|
552
|
+
const uploaded = await uploadFile({
|
|
553
|
+
filePath: params.filePath,
|
|
554
|
+
toUserId: params.to,
|
|
555
|
+
mediaType,
|
|
556
|
+
apiBaseUrl: params.baseUrl,
|
|
557
|
+
token: params.token,
|
|
558
|
+
cdnBaseUrl: params.cdnBaseUrl
|
|
559
|
+
});
|
|
560
|
+
const cdnMedia = {
|
|
561
|
+
encrypt_query_param: uploaded.encryptQueryParam,
|
|
562
|
+
aes_key: uploaded.aesKey,
|
|
563
|
+
encrypt_type: 1
|
|
564
|
+
};
|
|
565
|
+
const items = [];
|
|
566
|
+
if (params.text) {
|
|
567
|
+
items.push({
|
|
568
|
+
type: MessageItemType.TEXT,
|
|
569
|
+
text_item: { text: markdownToPlainText(params.text) }
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
switch (mediaType) {
|
|
573
|
+
case 1:
|
|
574
|
+
items.push({
|
|
575
|
+
type: MessageItemType.IMAGE,
|
|
576
|
+
image_item: { media: cdnMedia, mid_size: uploaded.fileSize }
|
|
577
|
+
});
|
|
578
|
+
break;
|
|
579
|
+
case 2:
|
|
580
|
+
items.push({
|
|
581
|
+
type: MessageItemType.VIDEO,
|
|
582
|
+
video_item: { media: cdnMedia, video_size: uploaded.fileSize }
|
|
583
|
+
});
|
|
584
|
+
break;
|
|
585
|
+
default:
|
|
586
|
+
items.push({
|
|
587
|
+
type: MessageItemType.FILE,
|
|
588
|
+
file_item: {
|
|
589
|
+
media: cdnMedia,
|
|
590
|
+
file_name: uploaded.fileName,
|
|
591
|
+
len: String(uploaded.rawSize)
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
const messageId = await sendItems({
|
|
597
|
+
items,
|
|
598
|
+
to: params.to,
|
|
599
|
+
baseUrl: params.baseUrl,
|
|
600
|
+
token: params.token,
|
|
601
|
+
contextToken: params.contextToken
|
|
602
|
+
});
|
|
603
|
+
return { messageId };
|
|
604
|
+
}
|
|
605
|
+
// packages/weixin/src/monitor.ts
|
|
606
|
+
import {
|
|
607
|
+
existsSync as existsSync4,
|
|
608
|
+
mkdirSync as mkdirSync3,
|
|
609
|
+
readFileSync as readFileSync4,
|
|
610
|
+
writeFileSync as writeFileSync4
|
|
611
|
+
} from "fs";
|
|
612
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
613
|
+
import { basename as basename2, join as join3 } from "path";
|
|
614
|
+
|
|
615
|
+
// packages/weixin/src/permissions.ts
|
|
616
|
+
var PENDING_PERMISSION_TTL_MS = 15 * 60 * 1000;
|
|
617
|
+
var pendingPermissions = new Map;
|
|
618
|
+
var activePermissionChat = null;
|
|
619
|
+
function pruneExpiredPendingPermissions(now = Date.now()) {
|
|
620
|
+
for (const [requestId, entry] of pendingPermissions.entries()) {
|
|
621
|
+
if (entry.expiresAt <= now) {
|
|
622
|
+
pendingPermissions.delete(requestId);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function setActivePermissionChat(chatId, contextToken) {
|
|
627
|
+
activePermissionChat = { chatId, contextToken, updatedAt: Date.now() };
|
|
628
|
+
}
|
|
629
|
+
function getActivePermissionChat() {
|
|
630
|
+
return activePermissionChat;
|
|
631
|
+
}
|
|
632
|
+
function savePendingPermission(request, chatId, contextToken) {
|
|
633
|
+
pruneExpiredPendingPermissions();
|
|
634
|
+
const entry = {
|
|
635
|
+
...request,
|
|
636
|
+
chatId,
|
|
637
|
+
contextToken,
|
|
638
|
+
createdAt: Date.now(),
|
|
639
|
+
expiresAt: Date.now() + PENDING_PERMISSION_TTL_MS
|
|
640
|
+
};
|
|
641
|
+
pendingPermissions.set(request.request_id.toLowerCase(), entry);
|
|
642
|
+
return entry;
|
|
643
|
+
}
|
|
644
|
+
function consumePendingPermission(requestId, fromUserId) {
|
|
645
|
+
pruneExpiredPendingPermissions();
|
|
646
|
+
const key = requestId.toLowerCase();
|
|
647
|
+
const entry = pendingPermissions.get(key);
|
|
648
|
+
if (!entry)
|
|
649
|
+
return null;
|
|
650
|
+
if (entry.chatId !== fromUserId)
|
|
651
|
+
return null;
|
|
652
|
+
pendingPermissions.delete(key);
|
|
653
|
+
return entry;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// packages/weixin/src/monitor.ts
|
|
657
|
+
var PERMISSION_REPLY_RE = /^\s*(y|yes|n|no)\s+([a-km-z]{5})\s*$/i;
|
|
658
|
+
var contextTokens = new Map;
|
|
659
|
+
function getContextToken(userId) {
|
|
660
|
+
return contextTokens.get(userId);
|
|
661
|
+
}
|
|
662
|
+
function cursorPath() {
|
|
663
|
+
return join3(getStateDir(), "cursor.txt");
|
|
664
|
+
}
|
|
665
|
+
function loadCursor() {
|
|
666
|
+
const path = cursorPath();
|
|
667
|
+
if (existsSync4(path))
|
|
668
|
+
return readFileSync4(path, "utf-8").trim();
|
|
669
|
+
return "";
|
|
670
|
+
}
|
|
671
|
+
function saveCursor(cursor) {
|
|
672
|
+
writeFileSync4(cursorPath(), cursor, "utf-8");
|
|
673
|
+
}
|
|
674
|
+
async function downloadMedia(item, cdnBaseUrl) {
|
|
675
|
+
let encryptQueryParam;
|
|
676
|
+
let aesKey;
|
|
677
|
+
let ext = "";
|
|
678
|
+
let mediaType = "";
|
|
679
|
+
switch (item.type) {
|
|
680
|
+
case MessageItemType.IMAGE:
|
|
681
|
+
encryptQueryParam = item.image_item?.media?.encrypt_query_param;
|
|
682
|
+
aesKey = item.image_item?.aeskey ? Buffer.from(item.image_item.aeskey, "hex").toString("base64") : item.image_item?.media?.aes_key;
|
|
683
|
+
ext = ".jpg";
|
|
684
|
+
mediaType = "image";
|
|
685
|
+
break;
|
|
686
|
+
case MessageItemType.VOICE:
|
|
687
|
+
encryptQueryParam = item.voice_item?.media?.encrypt_query_param;
|
|
688
|
+
aesKey = item.voice_item?.media?.aes_key;
|
|
689
|
+
ext = ".silk";
|
|
690
|
+
mediaType = "voice";
|
|
691
|
+
break;
|
|
692
|
+
case MessageItemType.FILE:
|
|
693
|
+
encryptQueryParam = item.file_item?.media?.encrypt_query_param;
|
|
694
|
+
aesKey = item.file_item?.media?.aes_key;
|
|
695
|
+
ext = item.file_item?.file_name ? `.${item.file_item.file_name.split(".").pop()}` : "";
|
|
696
|
+
mediaType = "file";
|
|
697
|
+
break;
|
|
698
|
+
case MessageItemType.VIDEO:
|
|
699
|
+
encryptQueryParam = item.video_item?.media?.encrypt_query_param;
|
|
700
|
+
aesKey = item.video_item?.media?.aes_key;
|
|
701
|
+
ext = ".mp4";
|
|
702
|
+
mediaType = "video";
|
|
703
|
+
break;
|
|
704
|
+
default:
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
if (!encryptQueryParam || !aesKey)
|
|
708
|
+
return null;
|
|
709
|
+
try {
|
|
710
|
+
const data = await downloadAndDecrypt({
|
|
711
|
+
encryptQueryParam,
|
|
712
|
+
aesKey,
|
|
713
|
+
cdnBaseUrl
|
|
714
|
+
});
|
|
715
|
+
const dir = join3(tmpdir2(), "weixin-media");
|
|
716
|
+
if (!existsSync4(dir))
|
|
717
|
+
mkdirSync3(dir, { recursive: true });
|
|
718
|
+
const rawFileName = item.file_item?.file_name || `${Date.now()}${ext}`;
|
|
719
|
+
const fileName = basename2(rawFileName);
|
|
720
|
+
const filePath = join3(dir, fileName);
|
|
721
|
+
writeFileSync4(filePath, data);
|
|
722
|
+
return { path: filePath, type: mediaType };
|
|
723
|
+
} catch (error) {
|
|
724
|
+
process.stderr.write(`[weixin] Failed to download media: ${error}
|
|
725
|
+
`);
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
function extractPermissionReply(text) {
|
|
730
|
+
const match = text.match(PERMISSION_REPLY_RE);
|
|
731
|
+
if (!match)
|
|
732
|
+
return null;
|
|
733
|
+
const behavior = match[1]?.toLowerCase().startsWith("y") ? "allow" : "deny";
|
|
734
|
+
const requestId = match[2]?.toLowerCase();
|
|
735
|
+
if (!requestId)
|
|
736
|
+
return null;
|
|
737
|
+
return { requestId, behavior };
|
|
738
|
+
}
|
|
739
|
+
async function startPollLoop(params) {
|
|
740
|
+
const {
|
|
741
|
+
baseUrl,
|
|
742
|
+
cdnBaseUrl,
|
|
743
|
+
token,
|
|
744
|
+
onMessage,
|
|
745
|
+
onPermissionResponse,
|
|
746
|
+
abortSignal
|
|
747
|
+
} = params;
|
|
748
|
+
let cursor = loadCursor();
|
|
749
|
+
let consecutiveErrors = 0;
|
|
750
|
+
process.stderr.write(`[weixin] Starting message poll loop...
|
|
751
|
+
`);
|
|
752
|
+
while (!abortSignal.aborted) {
|
|
753
|
+
try {
|
|
754
|
+
const response = await getUpdates(baseUrl, token, cursor, abortSignal);
|
|
755
|
+
if (response.errcode === -14) {
|
|
756
|
+
process.stderr.write(`[weixin] Session expired (errcode -14). Pausing for 30s...
|
|
757
|
+
`);
|
|
758
|
+
await new Promise((resolve) => setTimeout(resolve, 30000));
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (response.ret !== 0 && response.ret !== undefined) {
|
|
762
|
+
throw new Error(`getUpdates error: ret=${response.ret} errcode=${response.errcode} ${response.errmsg}`);
|
|
763
|
+
}
|
|
764
|
+
consecutiveErrors = 0;
|
|
765
|
+
if (response.get_updates_buf) {
|
|
766
|
+
cursor = response.get_updates_buf;
|
|
767
|
+
saveCursor(cursor);
|
|
768
|
+
}
|
|
769
|
+
if (response.msgs && response.msgs.length > 0) {
|
|
770
|
+
for (const msg of response.msgs) {
|
|
771
|
+
await processMessage(msg, {
|
|
772
|
+
baseUrl,
|
|
773
|
+
cdnBaseUrl,
|
|
774
|
+
token,
|
|
775
|
+
onMessage,
|
|
776
|
+
onPermissionResponse
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
} catch (error) {
|
|
781
|
+
if (abortSignal.aborted)
|
|
782
|
+
break;
|
|
783
|
+
consecutiveErrors += 1;
|
|
784
|
+
process.stderr.write(`[weixin] Poll error (${consecutiveErrors}): ${error instanceof Error ? error.message : String(error)}
|
|
785
|
+
`);
|
|
786
|
+
if (consecutiveErrors >= 3) {
|
|
787
|
+
process.stderr.write(`[weixin] Too many consecutive errors, backing off 30s...
|
|
788
|
+
`);
|
|
789
|
+
await new Promise((resolve) => setTimeout(resolve, 30000));
|
|
790
|
+
consecutiveErrors = 0;
|
|
791
|
+
} else {
|
|
792
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
process.stderr.write(`[weixin] Poll loop stopped.
|
|
797
|
+
`);
|
|
798
|
+
}
|
|
799
|
+
async function processMessage(msg, ctx) {
|
|
800
|
+
if (msg.message_type !== MessageType.USER)
|
|
801
|
+
return;
|
|
802
|
+
const fromUserId = msg.from_user_id;
|
|
803
|
+
if (!fromUserId)
|
|
804
|
+
return;
|
|
805
|
+
if (msg.context_token) {
|
|
806
|
+
contextTokens.set(fromUserId, msg.context_token);
|
|
807
|
+
}
|
|
808
|
+
if (!isAllowed(fromUserId)) {
|
|
809
|
+
const code = addPendingPairing(fromUserId);
|
|
810
|
+
try {
|
|
811
|
+
await sendText({
|
|
812
|
+
to: fromUserId,
|
|
813
|
+
text: `Your pairing code is: ${code}
|
|
814
|
+
|
|
815
|
+
Ask the operator to confirm:
|
|
816
|
+
ccb weixin access pair ${code}`,
|
|
817
|
+
baseUrl: ctx.baseUrl,
|
|
818
|
+
token: ctx.token,
|
|
819
|
+
contextToken: msg.context_token || ""
|
|
820
|
+
});
|
|
821
|
+
} catch (error) {
|
|
822
|
+
process.stderr.write(`[weixin] Failed to send pairing code: ${error}
|
|
823
|
+
`);
|
|
824
|
+
}
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
setActivePermissionChat(fromUserId, msg.context_token);
|
|
828
|
+
let textContent = "";
|
|
829
|
+
let mediaPath;
|
|
830
|
+
let mediaType;
|
|
831
|
+
if (msg.item_list) {
|
|
832
|
+
for (const item of msg.item_list) {
|
|
833
|
+
if (item.type === MessageItemType.TEXT && item.text_item?.text) {
|
|
834
|
+
textContent += `${textContent ? `
|
|
835
|
+
` : ""}${item.text_item.text}`;
|
|
836
|
+
} else if (item.type === MessageItemType.IMAGE || item.type === MessageItemType.VOICE || item.type === MessageItemType.FILE || item.type === MessageItemType.VIDEO) {
|
|
837
|
+
const downloaded = await downloadMedia(item, ctx.cdnBaseUrl);
|
|
838
|
+
if (downloaded) {
|
|
839
|
+
mediaPath = downloaded.path;
|
|
840
|
+
mediaType = downloaded.type;
|
|
841
|
+
}
|
|
842
|
+
if (item.type === MessageItemType.VOICE && item.voice_item?.text) {
|
|
843
|
+
textContent += `${textContent ? `
|
|
844
|
+
` : ""}[Voice transcription]: ${item.voice_item.text}`;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
if (!textContent && !mediaPath)
|
|
850
|
+
return;
|
|
851
|
+
if (textContent && ctx.onPermissionResponse) {
|
|
852
|
+
const permissionReply = extractPermissionReply(textContent);
|
|
853
|
+
if (permissionReply) {
|
|
854
|
+
const pending = consumePendingPermission(permissionReply.requestId, fromUserId);
|
|
855
|
+
if (pending) {
|
|
856
|
+
await ctx.onPermissionResponse({
|
|
857
|
+
requestId: pending.request_id,
|
|
858
|
+
behavior: permissionReply.behavior,
|
|
859
|
+
fromUserId
|
|
860
|
+
});
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
await ctx.onMessage({
|
|
866
|
+
fromUserId,
|
|
867
|
+
messageId: String(msg.message_id || ""),
|
|
868
|
+
text: textContent || "(media attachment)",
|
|
869
|
+
attachmentPath: mediaPath,
|
|
870
|
+
attachmentType: mediaType
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
// packages/weixin/src/server.ts
|
|
874
|
+
init_server();
|
|
875
|
+
init_stdio();
|
|
876
|
+
init_types();
|
|
877
|
+
import { existsSync as existsSync5 } from "fs";
|
|
878
|
+
function formatPermissionRequestMessage(request) {
|
|
879
|
+
return [
|
|
880
|
+
"RedScope AI needs your approval.",
|
|
881
|
+
"",
|
|
882
|
+
`Tool: ${request.tool_name}`,
|
|
883
|
+
`Reason: ${request.description}`,
|
|
884
|
+
`Input: ${request.input_preview}`,
|
|
885
|
+
"",
|
|
886
|
+
`Reply with: yes ${request.request_id}`,
|
|
887
|
+
`Or deny with: no ${request.request_id}`
|
|
888
|
+
].join(`
|
|
889
|
+
`);
|
|
890
|
+
}
|
|
891
|
+
function createWeixinMcpServer(version) {
|
|
892
|
+
const server = new Server({ name: "weixin", version }, {
|
|
893
|
+
capabilities: {
|
|
894
|
+
experimental: {
|
|
895
|
+
"claude/channel": {},
|
|
896
|
+
"claude/channel/permission": {}
|
|
897
|
+
},
|
|
898
|
+
tools: {}
|
|
899
|
+
},
|
|
900
|
+
instructions: 'Messages from WeChat arrive as <channel source="plugin:weixin:weixin" chat_id="..." sender_id="...">. Reply using the reply tool with the chat_id from the channel tag. Use absolute paths for file attachments.'
|
|
901
|
+
});
|
|
902
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
903
|
+
tools: [
|
|
904
|
+
{
|
|
905
|
+
name: "reply",
|
|
906
|
+
description: "Reply to a WeChat message. Pass the chat_id from the channel tag.",
|
|
907
|
+
inputSchema: {
|
|
908
|
+
type: "object",
|
|
909
|
+
properties: {
|
|
910
|
+
chat_id: {
|
|
911
|
+
type: "string",
|
|
912
|
+
description: "The chat_id from the channel notification"
|
|
913
|
+
},
|
|
914
|
+
text: { type: "string", description: "The reply text" },
|
|
915
|
+
files: {
|
|
916
|
+
type: "array",
|
|
917
|
+
items: { type: "string" },
|
|
918
|
+
description: "Optional absolute file paths to attach"
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
required: ["chat_id", "text"]
|
|
922
|
+
}
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
name: "send_typing",
|
|
926
|
+
description: "Send a typing indicator to a WeChat user.",
|
|
927
|
+
inputSchema: {
|
|
928
|
+
type: "object",
|
|
929
|
+
properties: {
|
|
930
|
+
chat_id: { type: "string", description: "The chat_id (user ID)" }
|
|
931
|
+
},
|
|
932
|
+
required: ["chat_id"]
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
]
|
|
936
|
+
}));
|
|
937
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
938
|
+
const { name, arguments: args } = request.params;
|
|
939
|
+
const account = loadAccount();
|
|
940
|
+
if (!account) {
|
|
941
|
+
return {
|
|
942
|
+
content: [
|
|
943
|
+
{
|
|
944
|
+
type: "text",
|
|
945
|
+
text: "WeChat not connected. Run `redscope weixin login` first."
|
|
946
|
+
}
|
|
947
|
+
],
|
|
948
|
+
isError: true
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
const baseUrl = account.baseUrl || DEFAULT_BASE_URL;
|
|
952
|
+
const cdnBaseUrl = CDN_BASE_URL;
|
|
953
|
+
switch (name) {
|
|
954
|
+
case "reply": {
|
|
955
|
+
const chatId = typeof args?.chat_id === "string" ? args.chat_id : "";
|
|
956
|
+
const text = typeof args?.text === "string" ? args.text : "";
|
|
957
|
+
const files = Array.isArray(args?.files) ? args.files.filter((value) => typeof value === "string") : undefined;
|
|
958
|
+
if (!chatId || !text) {
|
|
959
|
+
return {
|
|
960
|
+
content: [
|
|
961
|
+
{ type: "text", text: "Missing chat_id or text parameter." }
|
|
962
|
+
],
|
|
963
|
+
isError: true
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
const contextToken = getContextToken(chatId) || "";
|
|
967
|
+
try {
|
|
968
|
+
if (files && files.length > 0) {
|
|
969
|
+
for (const [index, filePath] of files.entries()) {
|
|
970
|
+
if (!existsSync5(filePath)) {
|
|
971
|
+
return {
|
|
972
|
+
content: [
|
|
973
|
+
{ type: "text", text: `File not found: ${filePath}` }
|
|
974
|
+
],
|
|
975
|
+
isError: true
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
await sendMediaFile({
|
|
979
|
+
filePath,
|
|
980
|
+
to: chatId,
|
|
981
|
+
text: index === 0 ? text : "",
|
|
982
|
+
baseUrl,
|
|
983
|
+
token: account.token,
|
|
984
|
+
contextToken,
|
|
985
|
+
cdnBaseUrl
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
content: [{ type: "text", text: "Message sent with attachments." }]
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
await sendText({
|
|
993
|
+
to: chatId,
|
|
994
|
+
text,
|
|
995
|
+
baseUrl,
|
|
996
|
+
token: account.token,
|
|
997
|
+
contextToken
|
|
998
|
+
});
|
|
999
|
+
return { content: [{ type: "text", text: "Message sent." }] };
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
return {
|
|
1002
|
+
content: [{ type: "text", text: `Failed to send: ${error}` }],
|
|
1003
|
+
isError: true
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
case "send_typing": {
|
|
1008
|
+
const chatId = typeof args?.chat_id === "string" ? args.chat_id : "";
|
|
1009
|
+
if (!chatId) {
|
|
1010
|
+
return {
|
|
1011
|
+
content: [{ type: "text", text: "Missing chat_id parameter." }],
|
|
1012
|
+
isError: true
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
try {
|
|
1016
|
+
const contextToken = getContextToken(chatId);
|
|
1017
|
+
const config = await getConfig(baseUrl, account.token, chatId, contextToken);
|
|
1018
|
+
if (config.typing_ticket) {
|
|
1019
|
+
await sendTyping(baseUrl, account.token, {
|
|
1020
|
+
ilink_user_id: chatId,
|
|
1021
|
+
typing_ticket: config.typing_ticket,
|
|
1022
|
+
status: TypingStatus.TYPING
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
return {
|
|
1026
|
+
content: [{ type: "text", text: "Typing indicator sent." }]
|
|
1027
|
+
};
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
return {
|
|
1030
|
+
content: [{ type: "text", text: `Failed to send typing: ${error}` }],
|
|
1031
|
+
isError: true
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
default:
|
|
1036
|
+
return {
|
|
1037
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
1038
|
+
isError: true
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
return server;
|
|
1043
|
+
}
|
|
1044
|
+
async function runWeixinMcpServer(version, deps) {
|
|
1045
|
+
deps.enableConfigs();
|
|
1046
|
+
deps.initializeAnalyticsSink();
|
|
1047
|
+
const account = loadAccount();
|
|
1048
|
+
if (!account) {
|
|
1049
|
+
process.stderr.write("[weixin] No account configured. Run `redscope weixin login` to connect your WeChat account.\n");
|
|
1050
|
+
await Promise.all([deps.shutdown1PEventLogging(), deps.shutdownDatadog()]);
|
|
1051
|
+
process.exit(1);
|
|
1052
|
+
}
|
|
1053
|
+
const server = createWeixinMcpServer(version);
|
|
1054
|
+
const transport = new StdioServerTransport;
|
|
1055
|
+
deps.registerPermissionHandler(server, async (request) => {
|
|
1056
|
+
const targetChatId = request.channel_context?.chat_id;
|
|
1057
|
+
const targetChat = targetChatId ? {
|
|
1058
|
+
chatId: targetChatId,
|
|
1059
|
+
contextToken: getContextToken(targetChatId)
|
|
1060
|
+
} : getActivePermissionChat();
|
|
1061
|
+
if (!targetChat) {
|
|
1062
|
+
deps.logForDebugging(`[Weixin MCP] No active chat available for permission request ${request.request_id}`);
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
try {
|
|
1066
|
+
savePendingPermission(request, targetChat.chatId, targetChat.contextToken);
|
|
1067
|
+
await sendText({
|
|
1068
|
+
to: targetChat.chatId,
|
|
1069
|
+
text: formatPermissionRequestMessage(request),
|
|
1070
|
+
baseUrl,
|
|
1071
|
+
token: account.token,
|
|
1072
|
+
contextToken: targetChat.contextToken || ""
|
|
1073
|
+
});
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
process.stderr.write(`[weixin] Failed to relay permission request ${request.request_id}: ${error}
|
|
1076
|
+
`);
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
await server.connect(transport);
|
|
1080
|
+
const baseUrl = account.baseUrl || DEFAULT_BASE_URL;
|
|
1081
|
+
const controller = new AbortController;
|
|
1082
|
+
let exiting = false;
|
|
1083
|
+
const shutdownAndExit = async () => {
|
|
1084
|
+
if (exiting)
|
|
1085
|
+
return;
|
|
1086
|
+
exiting = true;
|
|
1087
|
+
if (!controller.signal.aborted) {
|
|
1088
|
+
controller.abort();
|
|
1089
|
+
}
|
|
1090
|
+
await Promise.all([deps.shutdown1PEventLogging(), deps.shutdownDatadog()]);
|
|
1091
|
+
process.exit(0);
|
|
1092
|
+
};
|
|
1093
|
+
process.stdin.on("end", () => void shutdownAndExit());
|
|
1094
|
+
process.stdin.on("error", () => void shutdownAndExit());
|
|
1095
|
+
process.on("SIGINT", () => void shutdownAndExit());
|
|
1096
|
+
process.on("SIGTERM", () => void shutdownAndExit());
|
|
1097
|
+
process.on("SIGHUP", () => void shutdownAndExit());
|
|
1098
|
+
const ppid = process.ppid;
|
|
1099
|
+
const parentCheck = setInterval(() => {
|
|
1100
|
+
try {
|
|
1101
|
+
process.kill(ppid, 0);
|
|
1102
|
+
} catch {
|
|
1103
|
+
process.stderr.write(`[weixin] Parent process exited, shutting down...
|
|
1104
|
+
`);
|
|
1105
|
+
clearInterval(parentCheck);
|
|
1106
|
+
shutdownAndExit();
|
|
1107
|
+
}
|
|
1108
|
+
}, 5000);
|
|
1109
|
+
deps.logForDebugging("[Weixin MCP] Starting poll loop");
|
|
1110
|
+
await startPollLoop({
|
|
1111
|
+
baseUrl,
|
|
1112
|
+
cdnBaseUrl: CDN_BASE_URL,
|
|
1113
|
+
token: account.token,
|
|
1114
|
+
onMessage: async (msg) => {
|
|
1115
|
+
await server.notification({
|
|
1116
|
+
method: "notifications/claude/channel",
|
|
1117
|
+
params: {
|
|
1118
|
+
content: msg.text,
|
|
1119
|
+
meta: {
|
|
1120
|
+
chat_id: msg.fromUserId,
|
|
1121
|
+
sender_id: msg.fromUserId,
|
|
1122
|
+
message_id: msg.messageId,
|
|
1123
|
+
...msg.attachmentPath && { attachment_path: msg.attachmentPath },
|
|
1124
|
+
...msg.attachmentType && { attachment_type: msg.attachmentType }
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
},
|
|
1129
|
+
onPermissionResponse: async (response) => {
|
|
1130
|
+
await server.notification({
|
|
1131
|
+
method: "notifications/claude/channel/permission",
|
|
1132
|
+
params: {
|
|
1133
|
+
request_id: response.requestId,
|
|
1134
|
+
behavior: response.behavior
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
},
|
|
1138
|
+
abortSignal: controller.signal
|
|
1139
|
+
});
|
|
1140
|
+
clearInterval(parentCheck);
|
|
1141
|
+
await shutdownAndExit();
|
|
1142
|
+
}
|
|
1143
|
+
// packages/weixin/src/cli.ts
|
|
1144
|
+
function printUsage() {
|
|
1145
|
+
process.stdout.write([
|
|
1146
|
+
"Usage:",
|
|
1147
|
+
" redscope weixin serve",
|
|
1148
|
+
" redscope weixin login",
|
|
1149
|
+
" redscope weixin login clear",
|
|
1150
|
+
" redscope weixin access pair <code>",
|
|
1151
|
+
"",
|
|
1152
|
+
"Session enablement:",
|
|
1153
|
+
" redscope --channels plugin:weixin@builtin"
|
|
1154
|
+
].join(`
|
|
1155
|
+
`) + `
|
|
1156
|
+
`);
|
|
1157
|
+
}
|
|
1158
|
+
async function runLogin(clear = false) {
|
|
1159
|
+
if (clear) {
|
|
1160
|
+
clearAccount();
|
|
1161
|
+
process.stdout.write(`WeChat account cleared.
|
|
1162
|
+
`);
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
const existing = loadAccount();
|
|
1166
|
+
if (existing) {
|
|
1167
|
+
process.stdout.write([
|
|
1168
|
+
"Already connected:",
|
|
1169
|
+
` User ID: ${existing.userId || "unknown"}`,
|
|
1170
|
+
` Connected since: ${existing.savedAt}`,
|
|
1171
|
+
"",
|
|
1172
|
+
"Run `redscope weixin login clear` to disconnect.",
|
|
1173
|
+
"Restart RedScope AI with:",
|
|
1174
|
+
" redscope --channels plugin:weixin@builtin"
|
|
1175
|
+
].join(`
|
|
1176
|
+
`) + `
|
|
1177
|
+
`);
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
process.stdout.write(`Starting WeChat QR login...
|
|
1181
|
+
|
|
1182
|
+
`);
|
|
1183
|
+
const qr = await startLogin(DEFAULT_BASE_URL);
|
|
1184
|
+
process.stdout.write(`
|
|
1185
|
+
Scan the QR code above with WeChat, or open this URL:
|
|
1186
|
+
${qr.qrcodeUrl || ""}
|
|
1187
|
+
|
|
1188
|
+
`);
|
|
1189
|
+
const result = await waitForLogin({
|
|
1190
|
+
qrcodeId: qr.qrcodeId,
|
|
1191
|
+
apiBaseUrl: DEFAULT_BASE_URL
|
|
1192
|
+
});
|
|
1193
|
+
if (!result.connected || !result.token) {
|
|
1194
|
+
process.stderr.write(`Login failed: ${result.message}
|
|
1195
|
+
`);
|
|
1196
|
+
process.exit(1);
|
|
1197
|
+
}
|
|
1198
|
+
saveAccount({
|
|
1199
|
+
token: result.token,
|
|
1200
|
+
baseUrl: result.baseUrl || DEFAULT_BASE_URL,
|
|
1201
|
+
userId: result.userId,
|
|
1202
|
+
savedAt: new Date().toISOString()
|
|
1203
|
+
});
|
|
1204
|
+
process.stdout.write([
|
|
1205
|
+
"Connected successfully!",
|
|
1206
|
+
` User ID: ${result.userId || "unknown"}`,
|
|
1207
|
+
` Base URL: ${result.baseUrl || DEFAULT_BASE_URL}`,
|
|
1208
|
+
"",
|
|
1209
|
+
"Restart RedScope AI with:",
|
|
1210
|
+
" redscope --channels plugin:weixin@builtin"
|
|
1211
|
+
].join(`
|
|
1212
|
+
`) + `
|
|
1213
|
+
`);
|
|
1214
|
+
}
|
|
1215
|
+
function runAccess(args) {
|
|
1216
|
+
if (args[0] !== "pair" || !args[1]) {
|
|
1217
|
+
printUsage();
|
|
1218
|
+
process.exit(1);
|
|
1219
|
+
}
|
|
1220
|
+
const userId = confirmPairing(args[1]);
|
|
1221
|
+
if (!userId) {
|
|
1222
|
+
process.stderr.write(`Invalid or expired pairing code.
|
|
1223
|
+
`);
|
|
1224
|
+
process.exit(1);
|
|
1225
|
+
}
|
|
1226
|
+
process.stdout.write(`Paired successfully: ${userId}
|
|
1227
|
+
`);
|
|
1228
|
+
}
|
|
1229
|
+
async function handleWeixinCli(args, serverDeps, version) {
|
|
1230
|
+
const [subcommand, ...rest] = args;
|
|
1231
|
+
switch (subcommand) {
|
|
1232
|
+
case "serve":
|
|
1233
|
+
if (!serverDeps) {
|
|
1234
|
+
process.stderr.write(`[weixin] serve handler not available in this context.
|
|
1235
|
+
`);
|
|
1236
|
+
process.exit(1);
|
|
1237
|
+
}
|
|
1238
|
+
await runWeixinMcpServer(version ?? "0.0.0", serverDeps);
|
|
1239
|
+
return;
|
|
1240
|
+
case "login":
|
|
1241
|
+
await runLogin(rest[0] === "clear");
|
|
1242
|
+
return;
|
|
1243
|
+
case "access":
|
|
1244
|
+
runAccess(rest);
|
|
1245
|
+
return;
|
|
1246
|
+
default:
|
|
1247
|
+
printUsage();
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
export {
|
|
1251
|
+
waitForLogin,
|
|
1252
|
+
uploadFile,
|
|
1253
|
+
startPollLoop,
|
|
1254
|
+
startLogin,
|
|
1255
|
+
setActivePermissionChat,
|
|
1256
|
+
sendTyping,
|
|
1257
|
+
sendText,
|
|
1258
|
+
sendMessage,
|
|
1259
|
+
sendMediaFile,
|
|
1260
|
+
savePendingPermission,
|
|
1261
|
+
saveAccount,
|
|
1262
|
+
saveAccessConfig,
|
|
1263
|
+
runWeixinMcpServer,
|
|
1264
|
+
parseAesKey,
|
|
1265
|
+
markdownToPlainText,
|
|
1266
|
+
loadAccount,
|
|
1267
|
+
loadAccessConfig,
|
|
1268
|
+
isAllowed,
|
|
1269
|
+
handleWeixinCli,
|
|
1270
|
+
guessMediaType,
|
|
1271
|
+
getUploadUrl,
|
|
1272
|
+
getUpdates,
|
|
1273
|
+
getStateDir,
|
|
1274
|
+
getContextToken,
|
|
1275
|
+
getConfig,
|
|
1276
|
+
getActivePermissionChat,
|
|
1277
|
+
extractPermissionReply,
|
|
1278
|
+
encryptAesEcb,
|
|
1279
|
+
downloadRemoteToTemp,
|
|
1280
|
+
downloadAndDecrypt,
|
|
1281
|
+
decryptAesEcb,
|
|
1282
|
+
createWeixinMcpServer,
|
|
1283
|
+
consumePendingPermission,
|
|
1284
|
+
confirmPairing,
|
|
1285
|
+
clearAccount,
|
|
1286
|
+
buildCdnUploadUrl,
|
|
1287
|
+
buildCdnDownloadUrl,
|
|
1288
|
+
aesEcbPaddedSize,
|
|
1289
|
+
addPendingPairing,
|
|
1290
|
+
UploadMediaType,
|
|
1291
|
+
TypingStatus,
|
|
1292
|
+
MessageType,
|
|
1293
|
+
MessageState,
|
|
1294
|
+
MessageItemType,
|
|
1295
|
+
DEFAULT_BASE_URL,
|
|
1296
|
+
CDN_BASE_URL
|
|
1297
|
+
};
|