@qwen-code/qwen-code 0.19.8 → 0.19.9-nightly.20260714.9dd8389eb
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/bundled/qc-helper/SKILL.md +1 -0
- package/bundled/qc-helper/docs/configuration/auth.md +40 -55
- package/bundled/qc-helper/docs/configuration/model-providers.md +224 -218
- package/bundled/qc-helper/docs/configuration/settings.md +61 -51
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +12 -2
- package/bundled/qc-helper/docs/features/channels/overview.md +82 -7
- package/bundled/qc-helper/docs/features/channels/wecom.md +6 -0
- package/bundled/qc-helper/docs/features/code-review.md +109 -41
- package/bundled/qc-helper/docs/features/commands.md +45 -44
- package/bundled/qc-helper/docs/features/computer-use.md +77 -0
- package/bundled/qc-helper/docs/features/hooks.md +29 -0
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +19 -23
- package/bundled/qc-helper/docs/integration-vscode.md +2 -2
- package/bundled/qc-helper/docs/qwen-serve.md +60 -22
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +2 -2
- package/bundled/review/DESIGN.md +303 -46
- package/bundled/review/SKILL.md +658 -165
- package/chunks/MaxSizedBox-QAYHOC4F.js +71 -0
- package/chunks/{StandaloneSessionPicker-EYRGH6PJ.js → StandaloneSessionPicker-D3R6YYX3.js} +82 -79
- package/chunks/{acpAgent-GRFTTRHW.js → acpAgent-ENHBW72A.js} +1178 -421
- package/chunks/agent-57LX4KMG.js +69 -0
- package/chunks/agent-headless-AC6EVNAP.js +63 -0
- package/chunks/{anthropicContentGenerator-CPF22MA7.js → anthropicContentGenerator-56U3YCP2.js} +187 -31
- package/chunks/{artifact-tool-D233YJFH.js → artifact-tool-BWZZJ42H.js} +5 -5
- package/chunks/{askUserQuestion-MKL5ZTMC.js → askUserQuestion-WU3S5A5T.js} +6 -6
- package/chunks/bridge-4OZH44MK.js +79 -0
- package/chunks/{ca-MKD32FQL.js → ca-C2JTT2N5.js} +68 -6
- package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
- package/chunks/channel-worker-manager-5RWKSGEU.js +418 -0
- package/chunks/channel-worker-supervisor-PCDAZN4D.js +20 -0
- package/chunks/{chunk-CSOTA7KX.js → chunk-2FO5GFKZ.js} +2 -2
- package/chunks/{chunk-QQDPRDVW.js → chunk-2HRYPZT5.js} +1 -1
- package/chunks/{chunk-I6WGFJJ3.js → chunk-2MF6ICOL.js} +38 -12
- package/chunks/{chunk-X3YGAX7V.js → chunk-2UUAIFQO.js} +4 -2
- package/chunks/{chunk-2PSWA5ID.js → chunk-2X56YUSZ.js} +1 -1
- package/chunks/{chunk-NQKLOAVJ.js → chunk-2Z5UX4KI.js} +2 -2
- package/chunks/chunk-3MX7D6QN.js +516 -0
- package/chunks/{chunk-YDOXPLYL.js → chunk-4DYYRLIE.js} +3890 -975
- package/chunks/{chunk-OQXDAMKY.js → chunk-4FPUAYTT.js} +8 -8
- package/chunks/{chunk-55ZMG67I.js → chunk-4LD5APFL.js} +4 -4
- package/chunks/{chunk-YKZIAK7C.js → chunk-4LJNI7MU.js} +166 -37
- package/chunks/{chunk-BOBOCR5H.js → chunk-4QOPEEL2.js} +4 -4
- package/chunks/{chunk-UIDXQNMV.js → chunk-4WGODMVR.js} +1 -1
- package/chunks/{chunk-E6US47KI.js → chunk-4WKAA4KS.js} +1 -1
- package/chunks/{chunk-3GONHQOA.js → chunk-57OAHC2Y.js} +1 -1
- package/chunks/{chunk-JZSY4WP3.js → chunk-5DTTYNB7.js} +1 -1
- package/chunks/chunk-5HBA2Z7V.js +28 -0
- package/chunks/{chunk-SKAZWEV5.js → chunk-5M6IDOMF.js} +35 -98
- package/chunks/{chunk-A4BMJM77.js → chunk-5O2XNYP6.js} +1 -0
- package/chunks/{chunk-GO6LNQXT.js → chunk-6AM5D4ME.js} +1 -1
- package/chunks/{chunk-BJBWRCSK.js → chunk-6H67XLET.js} +1 -1
- package/chunks/{chunk-AYNCLGTW.js → chunk-6HHAADP2.js} +8 -51
- package/chunks/{chunk-VZ7HY3YU.js → chunk-6OATMEYN.js} +3 -3
- package/chunks/{chunk-3UP777ZS.js → chunk-6RLROE6G.js} +1 -1
- package/chunks/{chunk-ZERZSAZL.js → chunk-75DOP5OR.js} +2 -2
- package/chunks/{chunk-RMLZAUWH.js → chunk-7BIZARI2.js} +10 -12
- package/chunks/{chunk-GN3F6PIU.js → chunk-7NAWTFVY.js} +5 -5
- package/chunks/{chunk-22MNNNXE.js → chunk-7NFB7LBQ.js} +11 -3
- package/chunks/{chunk-ZL5HN75Q.js → chunk-7R4DPSRA.js} +37 -3
- package/chunks/{chunk-BVYU3ZTI.js → chunk-7U7UIO5W.js} +1005 -942
- package/chunks/{chunk-SAIILPQ3.js → chunk-7X7TEQNX.js} +5 -3
- package/chunks/{chunk-IRJWHZWU.js → chunk-A4UCTEB5.js} +2 -2
- package/chunks/{chunk-WF4FAXDL.js → chunk-AAS2Q2TV.js} +62 -62
- package/chunks/{chunk-O7FIRWJV.js → chunk-AAWKZ5R7.js} +3 -3
- package/chunks/{chunk-JCH35JB3.js → chunk-AGBFWLA5.js} +2 -2
- package/chunks/{chunk-QYUE6W3T.js → chunk-ALGGS7UH.js} +2 -39
- package/chunks/{chunk-WMPVYQ4P.js → chunk-ARKANCNX.js} +3 -2
- package/chunks/{chunk-HDOH3QYE.js → chunk-ASVORVFT.js} +2 -2
- package/chunks/{chunk-CHB5SLZZ.js → chunk-AUGSSJX3.js} +3 -3
- package/chunks/{chunk-PUVCVELY.js → chunk-B6ABUBYY.js} +4 -4
- package/chunks/{chunk-L4AMBVQG.js → chunk-B6KHOCU7.js} +49 -21
- package/chunks/{chunk-HW4N45EE.js → chunk-B7NUUEXC.js} +38 -11
- package/chunks/{chunk-CD6USWHZ.js → chunk-BBNVFRGD.js} +2 -2
- package/chunks/{chunk-ZN5T4BHI.js → chunk-BPZALHVR.js} +2 -2
- package/chunks/{chunk-VGGOPZUL.js → chunk-C4CXFRKY.js} +12 -5
- package/chunks/{chunk-OFEVLU4C.js → chunk-CARU2RR2.js} +1 -1
- package/chunks/{chunk-SQ2UATK7.js → chunk-CLTWL6HD.js} +11 -11
- package/chunks/{chunk-GLE2YUPU.js → chunk-COH43MRJ.js} +1 -1
- package/chunks/{chunk-E5A7LHNN.js → chunk-CPBF7KYF.js} +1 -1
- package/chunks/{chunk-UWCTAVOD.js → chunk-CR3C7WXL.js} +1 -1
- package/chunks/{chunk-DIWVZ3VM.js → chunk-CSACSGAW.js} +5 -5
- package/chunks/{chunk-5P5XGNYH.js → chunk-CU3L64TP.js} +1 -1
- package/chunks/{chunk-IWKSG2AR.js → chunk-CXAOG665.js} +1 -1
- package/chunks/{chunk-64WXLC72.js → chunk-DJ2GSRLV.js} +1 -1
- package/chunks/chunk-DKXW66XA.js +38 -0
- package/chunks/{chunk-QN5NZ3UQ.js → chunk-DMTGGOSA.js} +2 -2
- package/chunks/{chunk-JZHIQJOE.js → chunk-DMTQY5GY.js} +6 -6
- package/chunks/{chunk-GSHQYYIV.js → chunk-DNKX35GS.js} +6 -26
- package/chunks/{chunk-6IAWPIQ6.js → chunk-DPSWJWZI.js} +4 -3
- package/chunks/{chunk-X2XNQQJI.js → chunk-E2UVIFI2.js} +186 -399
- package/chunks/{chunk-KHDZHZMH.js → chunk-E5Z2AVNV.js} +1 -1
- package/chunks/{chunk-3B26UVCX.js → chunk-E67NFMF4.js} +39 -10
- package/chunks/{chunk-ON3JA3RU.js → chunk-EU3U7USF.js} +7 -9
- package/chunks/{chunk-L46XKEGM.js → chunk-EUNRLYJG.js} +5 -8
- package/chunks/{chunk-OACJLMLD.js → chunk-FBU7WRZI.js} +18 -2
- package/chunks/{chunk-5IFG2VC4.js → chunk-FCMNKVXT.js} +1 -1
- package/chunks/{chunk-A5JOJ77H.js → chunk-FDL4PB5H.js} +38 -15
- package/chunks/{chunk-E7KNELIZ.js → chunk-FSA7ERJ2.js} +2 -2
- package/chunks/{chunk-TI3BWD4D.js → chunk-G6QTKQN4.js} +39 -19
- package/chunks/{chunk-44NROQYV.js → chunk-GDQQRV43.js} +4 -4
- package/chunks/{chunk-O2YT7VB4.js → chunk-GOXKNSDZ.js} +2 -65
- package/chunks/{chunk-V35MD7KN.js → chunk-GRC5HGPI.js} +1 -1
- package/chunks/chunk-GYGGUR4Q.js +253 -0
- package/chunks/{chunk-S6RLAIUR.js → chunk-GYTKQYDB.js} +1 -1
- package/chunks/{chunk-A2X3KLC3.js → chunk-GZXCZHCT.js} +3 -3
- package/chunks/{chunk-K5PGHDBN.js → chunk-H6XPXXMH.js} +1 -1
- package/chunks/{chunk-E7EMCSUG.js → chunk-HE54PGVI.js} +64 -42
- package/chunks/{chunk-KYMBIKIW.js → chunk-HTHUX2T5.js} +1 -1
- package/chunks/{chunk-LQ7TMOCE.js → chunk-HTO4JFDZ.js} +1 -1
- package/chunks/chunk-HZYUNZDQ.js +296 -0
- package/chunks/chunk-IDS7MSUP.js +74 -0
- package/chunks/chunk-J2TDDOSM.js +493 -0
- package/chunks/{chunk-4CGOWHKM.js → chunk-J4MOFEOK.js} +2 -2
- package/chunks/{chunk-22IFUCVR.js → chunk-JESCGQM3.js} +1 -1
- package/chunks/chunk-JR63TOV4.js +91 -0
- package/chunks/chunk-K3PPUB46.js +445 -0
- package/chunks/{chunk-42XGFRJS.js → chunk-KKRTYONM.js} +8 -6
- package/chunks/{chunk-GGQQA4JW.js → chunk-KSO42X3Z.js} +15 -2
- package/chunks/{chunk-MRO43B25.js → chunk-KW7NOTN6.js} +1 -1
- package/chunks/{chunk-54YZOP7P.js → chunk-L573Z2QZ.js} +11894 -5190
- package/chunks/{chunk-TLWA7TPR.js → chunk-L5U3ELZX.js} +2 -2
- package/chunks/{chunk-WHJQ3JUS.js → chunk-LAM6CGP5.js} +10 -10
- package/chunks/{chunk-H6EMK6QK.js → chunk-LQIDP6K5.js} +11913 -5207
- package/chunks/{chunk-MZ7BABX3.js → chunk-LXLTBIDP.js} +44 -7
- package/chunks/{chunk-HLKG6CZN.js → chunk-M5GB774H.js} +1 -1
- package/chunks/{chunk-EEN2TKST.js → chunk-MBJ3D6SF.js} +2 -2
- package/chunks/{chunk-PMFULMLX.js → chunk-MBP3K324.js} +2234 -377
- package/chunks/chunk-MR3PXB6E.js +48 -0
- package/chunks/{chunk-ZE6E424U.js → chunk-N7FCSERB.js} +2 -2
- package/chunks/{chunk-332PWN27.js → chunk-NHDKSOEY.js} +1 -1
- package/chunks/chunk-OATTJGPJ.js +448 -0
- package/chunks/{chunk-UX6OTBVD.js → chunk-OCC3UTWA.js} +2 -2
- package/chunks/{chunk-P7M4GA57.js → chunk-OCPBI7J5.js} +1 -1
- package/chunks/chunk-OJAMDVF5.js +66 -0
- package/chunks/{chunk-IJRL2S3D.js → chunk-OKAIGAYW.js} +6 -6
- package/chunks/{chunk-WQTHLB5T.js → chunk-P3S67A5R.js} +7 -7
- package/chunks/{chunk-FBET5XZ2.js → chunk-PEJWA3QQ.js} +29 -10
- package/chunks/{chunk-J7RCB6N5.js → chunk-PHYCWSDG.js} +2 -2
- package/chunks/{chunk-LAXNEOBG.js → chunk-PMRH4YYW.js} +18 -3
- package/chunks/{chunk-AGHU5VRK.js → chunk-PZL23GTM.js} +1 -1
- package/chunks/{chunk-PC4ZXHU2.js → chunk-Q6TUALBE.js} +3 -3
- package/chunks/{chunk-FXGLL2HL.js → chunk-Q7YDKOGY.js} +1 -1
- package/chunks/{chunk-P3XEEI3X.js → chunk-QABSSDQH.js} +36 -7
- package/chunks/{chunk-XOHNA2S6.js → chunk-QAW7PIHT.js} +3 -3
- package/chunks/{chunk-LGFAYIKX.js → chunk-QHTIBUWB.js} +1 -1
- package/chunks/{chunk-P3MYAZBY.js → chunk-QMGX2KO2.js} +1 -1
- package/chunks/{chunk-Z3I3QJK3.js → chunk-QRUIS3DN.js} +1 -1
- package/chunks/{chunk-ITOGNELQ.js → chunk-QSWDGAIC.js} +2 -2
- package/chunks/{chunk-GHOTR7HL.js → chunk-QUPXZXLV.js} +1 -1
- package/chunks/{chunk-W7EEOR7D.js → chunk-RCEEXIOO.js} +8 -6
- package/chunks/{chunk-2EM7ECZD.js → chunk-RJL5T4WJ.js} +281 -65
- package/chunks/{chunk-TLRYABYP.js → chunk-RKUWKYED.js} +1 -1
- package/chunks/{chunk-RNBYOUGV.js → chunk-RXFQM6FQ.js} +1 -1
- package/chunks/{chunk-JRQ7EVGE.js → chunk-S2QXYLUB.js} +2 -2
- package/chunks/{chunk-QXPI7FEC.js → chunk-S3TWXGKA.js} +4 -4
- package/chunks/{chunk-O33TBKDC.js → chunk-SE74CIZD.js} +155 -19
- package/chunks/{chunk-FV7425LN.js → chunk-SPJQO2CE.js} +18 -5
- package/chunks/{chunk-3GNOQZDC.js → chunk-SSFDPGFN.js} +11866 -11542
- package/chunks/{chunk-DCZWC4PF.js → chunk-SUWGUGAD.js} +5 -5
- package/chunks/{chunk-IBY3Q3HG.js → chunk-SXU3KKNI.js} +963 -181
- package/chunks/{chunk-MLZQVCF3.js → chunk-SZRN75WQ.js} +1 -1
- package/chunks/{chunk-M7S4GK5Z.js → chunk-T2L6SGQY.js} +115 -29
- package/chunks/{chunk-7RYW5LQV.js → chunk-T2NCM2ET.js} +2 -2
- package/chunks/{chunk-JPALE3PA.js → chunk-T5C2OUCI.js} +6 -6
- package/chunks/{chunk-BUZ6HGL4.js → chunk-T7FSRWQ5.js} +248 -55
- package/chunks/{chunk-Z2Z3GUXZ.js → chunk-TB6UDU4T.js} +1 -1
- package/chunks/{chunk-EXPMGZZV.js → chunk-TEGEBB2I.js} +1 -1
- package/chunks/{chunk-MX2YXRER.js → chunk-TJTKSVIV.js} +1 -1
- package/chunks/{chunk-CCGOFQV3.js → chunk-TQBODCFD.js} +8 -7
- package/chunks/chunk-TV6K2FB4.js +224 -0
- package/chunks/{chunk-5MBO76SL.js → chunk-TXY2C3D2.js} +3 -3
- package/chunks/{chunk-H6BD2ELD.js → chunk-TYAMGABM.js} +2 -2
- package/chunks/{chunk-QYNNN7BK.js → chunk-TYLOFD2U.js} +2 -2
- package/chunks/{chunk-VRDMOSQS.js → chunk-UDXSXLER.js} +2 -2
- package/chunks/{chunk-UXEW557D.js → chunk-UI3W56WF.js} +3 -3
- package/chunks/{chunk-CJCKDMWO.js → chunk-URK542T4.js} +1 -1
- package/chunks/{channel-worker-supervisor-NZQUOEFJ.js → chunk-URU5UEK6.js} +190 -34
- package/chunks/{chunk-AHNXYU4O.js → chunk-V6WHFGST.js} +1 -1
- package/chunks/chunk-V75IOTWF.js +71 -0
- package/chunks/{chunk-ZTQ26VBE.js → chunk-VDDGDZMA.js} +1 -1
- package/chunks/{chunk-OMX7CUOE.js → chunk-VGC4I5JJ.js} +1 -1
- package/chunks/{chunk-43W4YSO6.js → chunk-VJNBRRZG.js} +2 -2
- package/chunks/{chunk-ER3BKOLB.js → chunk-W7FJ3N32.js} +1 -1
- package/chunks/{chunk-3HX5LZ6R.js → chunk-WBL3FJEU.js} +2 -2
- package/chunks/{chunk-7LTB54MK.js → chunk-WIEO4CWB.js} +2 -2
- package/chunks/{chunk-BMFMJINR.js → chunk-WL4L7EZH.js} +1 -1
- package/chunks/{chunk-6VK6FIMQ.js → chunk-WM5HY72H.js} +415 -379
- package/chunks/{chunk-BOBRZZKD.js → chunk-WN4D7YCI.js} +5 -5
- package/chunks/{chunk-DHOLNQLC.js → chunk-WWQ3QIJS.js} +60 -40
- package/chunks/{chunk-FEJ2FZ3U.js → chunk-WX6SD4IQ.js} +2 -2
- package/chunks/{chunk-DICGXFAI.js → chunk-X7EBAABW.js} +11 -9
- package/chunks/{chunk-3RW4AZJV.js → chunk-XFSFZCM5.js} +1 -1
- package/chunks/{chunk-YHKAK72D.js → chunk-XHW5VUIQ.js} +102 -16
- package/chunks/{chunk-2MPVVENX.js → chunk-XU457J4V.js} +2 -2
- package/chunks/{chunk-SIUQ3YYX.js → chunk-XVNQMZ2I.js} +1 -1
- package/chunks/{chunk-SYCJMSIJ.js → chunk-XWRJCPHC.js} +1 -1
- package/chunks/{chunk-SUAKHHK7.js → chunk-Y66VOBRP.js} +3 -3
- package/chunks/chunk-YAF2MQZ6.js +19 -0
- package/chunks/{chunk-FQNC62B2.js → chunk-YH4J5XI3.js} +11 -11
- package/chunks/chunk-YHN5SUIJ.js +219 -0
- package/chunks/{chunk-BR4QREVK.js → chunk-YQ3U5MUC.js} +1 -1
- package/chunks/{chunk-Y6Z2O3WR.js → chunk-YUZI3WAC.js} +1 -1
- package/chunks/{chunk-II73RK2S.js → chunk-YVEDCAUE.js} +1 -1
- package/chunks/{chunk-XYR5RUA5.js → chunk-YWUK7OS7.js} +10 -3
- package/chunks/{chunk-27BHARDE.js → chunk-Z56JO4JZ.js} +2124 -30
- package/chunks/{chunk-TSPB77TG.js → chunk-ZLM3KXBT.js} +1015 -2967
- package/chunks/{chunk-AHNJGLFV.js → chunk-ZPAHLFZU.js} +3 -3
- package/chunks/chunk-ZRKBI3DP.js +34 -0
- package/chunks/cli-entry-path-4VJ3Y6T2.js +10 -0
- package/chunks/{computer-use-WMY3UOBX.js → computer-use-DIP5BWXP.js} +51 -50
- package/chunks/config-utils-CFT33LTP.js +24 -0
- package/chunks/contextCommand-QU4GJWWD.js +69 -0
- package/chunks/create-sub-session-TCLIYVGR.js +376 -0
- package/chunks/create-sub-session-WNX2OQVX.js +207 -0
- package/chunks/{cron-create-JSXEIPVS.js → cron-create-36TIFKRT.js} +9 -9
- package/chunks/{cron-delete-OIFVEPGU.js → cron-delete-OQD3WULU.js} +7 -7
- package/chunks/{cron-list-D4ZX4IOE.js → cron-list-4533T2FH.js} +14 -10
- package/chunks/{daemon-WPAENEBW.js → daemon-CEZ27OH4.js} +734 -24
- package/chunks/daemon-status-provider-SIBFMLBQ.js +77 -0
- package/chunks/{de-ZFPPQVSF.js → de-2VCDRDGU.js} +68 -6
- package/chunks/{devtools-FM6GJPYG.js → devtools-4QFYJT6U.js} +3 -3
- package/chunks/{dist-E6UANPIM.js → dist-3V3ZV6ML.js} +1011 -197
- package/chunks/{dist-SCFLLYMK.js → dist-ERCPDVA6.js} +12 -11
- package/chunks/{dist-Z34QPAQW.js → dist-HNN7DR2L.js} +529 -79
- package/chunks/{dist-O2IRTRPP.js → dist-JZE7F6YR.js} +10 -10
- package/chunks/{dist-BEXOZXLQ.js → dist-MOEC47TR.js} +36 -15
- package/chunks/{dist-H2AEJCZ5.js → dist-PHEPJLXD.js} +5 -5
- package/chunks/{dist-63IS3ZMI.js → dist-PZV5RKM6.js} +4 -4
- package/chunks/earlyInputCapture-L66BEG2C.js +70 -0
- package/chunks/{edit-OTYWAXGP.js → edit-Y5LAJSST.js} +52 -51
- package/chunks/{en-N4EPZAQI.js → en-NJCA3TAA.js} +78 -6
- package/chunks/{enter-worktree-HNYBDVCX.js → enter-worktree-X5LML7T4.js} +51 -50
- package/chunks/{enterPlanMode-CJCNGT63.js → enterPlanMode-XWF32QOW.js} +67 -51
- package/chunks/environment-YVMA5F4I.js +90 -0
- package/chunks/errors-4Y5SUAOC.js +76 -0
- package/chunks/{exit-worktree-DUUKOE3X.js → exit-worktree-SFHU7XYC.js} +51 -50
- package/chunks/{exitPlanMode-AMMSXOAJ.js → exitPlanMode-FP3NAN6E.js} +52 -51
- package/chunks/{fast-path-OV6NIP3K.js → fast-path-ZJNFFCBM.js} +8 -8
- package/chunks/{fast-path-settings-7RIFI3PK.js → fast-path-settings-DAOVFADC.js} +8 -6
- package/chunks/{fileFromPath-IBEHA3CO.js → fileFromPath-UDALK7FM.js} +3 -3
- package/chunks/{fr-5WWMY53B.js → fr-5F3E7WKD.js} +68 -6
- package/chunks/{gemini-NQ3WWBKB.js → gemini-5CAB22BI.js} +122 -109
- package/chunks/{geminiContentGenerator-CDUNEJQE.js → geminiContentGenerator-GE3HPIFB.js} +9 -9
- package/chunks/{getMachineId-bsd-4CASPIU4.js → getMachineId-bsd-EXV7SWPA.js} +3 -3
- package/chunks/{getMachineId-darwin-HPQPEMZR.js → getMachineId-darwin-IUOMFXU3.js} +3 -3
- package/chunks/{getMachineId-linux-AUARKYHL.js → getMachineId-linux-K7XJYFHL.js} +2 -2
- package/chunks/{getMachineId-unsupported-S32ZDA2T.js → getMachineId-unsupported-EA5FDRJ6.js} +2 -2
- package/chunks/{getMachineId-win-4EFLHYIJ.js → getMachineId-win-KBA6RAI5.js} +3 -3
- package/chunks/{glob-ROV3YS4R.js → glob-YPACZAEL.js} +98 -75
- package/chunks/{grep-NRITKDCD.js → grep-IPR4XW37.js} +51 -50
- package/chunks/handleAutoUpdate-P2KEP56V.js +70 -0
- package/chunks/i18n-BRCT66AA.js +85 -0
- package/chunks/initializer-34HXSK3A.js +74 -0
- package/chunks/installationInfo-WOTDQMSC.js +66 -0
- package/chunks/{ja-CUHZOLEJ.js → ja-66J6B53L.js} +69 -7
- package/chunks/{keychain-token-storage-UJV5XP4Z.js → keychain-token-storage-AU22CQI6.js} +4 -4
- package/chunks/{kittyProtocolDetector-OJRCJLIU.js → kittyProtocolDetector-HCNNKJTI.js} +2 -2
- package/chunks/list-XOGP7UPP.js +77 -0
- package/chunks/loadedSettingsAdapter-L4YKGU6F.js +71 -0
- package/chunks/{loop-wakeup-OHWEMFP5.js → loop-wakeup-MVUKDVCP.js} +10 -10
- package/chunks/{lowlight-FYAAUU5J.js → lowlight-J2OZNPCA.js} +1 -1
- package/chunks/{ls-7MFU2QYW.js → ls-RXNIAQDE.js} +6 -6
- package/chunks/{lsp-XHDTPTGV.js → lsp-HB5LM5IL.js} +4 -4
- package/chunks/mcp-HH7DIP7Y.js +71 -0
- package/chunks/{monitor-FL2ZO33W.js → monitor-25DEBT6U.js} +51 -50
- package/chunks/{multipart-parser-AJ4WASWR.js → multipart-parser-AWZKXSQN.js} +3 -3
- package/chunks/nonInteractiveCli-CT3VSSLK.js +130 -0
- package/chunks/{notebook-edit-6PULTHL5.js → notebook-edit-TAVXSWQ6.js} +52 -51
- package/chunks/openaiContentGenerator-6I7DKUAN.js +56 -0
- package/chunks/pidfile-SIQGCFLZ.js +74 -0
- package/chunks/{pt-OLYN42DS.js → pt-TFZO5Y6T.js} +68 -6
- package/chunks/{qwenContentGenerator-NX2E7PB7.js → qwenContentGenerator-5DDIXI2N.js} +53 -52
- package/chunks/{qwenOAuth2-ZV7YLMND.js → qwenOAuth2-LEYOU7RU.js} +9 -9
- package/chunks/read-file-WDOAYRFU.js +30 -0
- package/chunks/{read-mcp-resource-CNQHBSJM.js → read-mcp-resource-6LRTZKXI.js} +5 -5
- package/chunks/{read-package-up-ER5OJUGP.js → read-package-up-TCM6I7S2.js} +2 -2
- package/chunks/{record-artifact-SQ2OKRJW.js → record-artifact-PMDTY4OS.js} +4 -4
- package/chunks/ripGrep-MI7PHN3Q.js +61 -0
- package/chunks/{ru-LDM3GWVQ.js → ru-4L4LFHIT.js} +68 -6
- package/chunks/{run-qwen-serve-JK2DL7PI.js → run-qwen-serve-PNTYF3RE.js} +1289 -256
- package/chunks/runtime-V3FBMUTG.js +100 -0
- package/chunks/{scheduler-O4IGVZKK.js → scheduler-4TAUIJBM.js} +52 -51
- package/chunks/{send-message-76GT3JMC.js → send-message-SR4WSXP2.js} +7 -7
- package/chunks/serve-WB2TR7XM.js +77 -0
- package/chunks/{server-SGNPKX2O.js → server-AF6LNFPK.js} +8094 -2800
- package/chunks/{session-5BNM25EZ.js → session-BIGK4NRW.js} +341 -135
- package/chunks/settings-IXF5FIQO.js +121 -0
- package/chunks/shell-5VWJ2PPG.js +69 -0
- package/chunks/{skill-I22QK5XS.js → skill-SI667Y3B.js} +24 -24
- package/chunks/spawnChannel-IKX6DD7J.js +71 -0
- package/chunks/{src-BBQSM46M.js → src-55DZWDAK.js} +151 -52
- package/chunks/{src-7XL4G4DC.js → src-VLI3TKEY.js} +4 -4
- package/chunks/standalone-update-MHLSFHE6.js +80 -0
- package/chunks/{startInteractiveUI-JII36UGN.js → startInteractiveUI-V2EDWLAX.js} +2239 -1846
- package/chunks/stdioHelpers-UMY72QRP.js +14 -0
- package/chunks/{syntheticOutput-F7LSDCAR.js → syntheticOutput-YKFNUQZD.js} +5 -5
- package/chunks/task-create-NUFOHU53.js +23 -0
- package/chunks/{task-list-TGGJX7EA.js → task-list-Z2IKQY3S.js} +11 -10
- package/chunks/{task-stop-W7NGTMYQ.js → task-stop-KQFIVQTJ.js} +4 -4
- package/chunks/{task-update-XYWMHJGJ.js → task-update-HKADXSTD.js} +13 -12
- package/chunks/{team-create-A7NUU5AQ.js → team-create-IZAMLBJS.js} +51 -50
- package/chunks/{team-delete-UHQQ2QQX.js → team-delete-SDNTGZLG.js} +11 -10
- package/chunks/{team-plan-approval-TOQRJ2KI.js → team-plan-approval-3R4RCKCP.js} +51 -50
- package/chunks/theme-manager-LCOXZ5DO.js +65 -0
- package/chunks/{todoWrite-C4ZAMSR3.js → todoWrite-YNXB27GB.js} +6 -6
- package/chunks/{tool-search-SZ4EFS2T.js → tool-search-NYNCD5LF.js} +24 -24
- package/chunks/total-session-admission-PJWGOMQE.js +73 -0
- package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
- package/chunks/trustedFolders-DOJDHNYP.js +81 -0
- package/chunks/{types-QX5C3CHJ.js → types-JNKGKUJT.js} +2 -2
- package/chunks/updateCheck-ZXL66KIG.js +70 -0
- package/chunks/updateEventEmitter-5MKC7BLQ.js +10 -0
- package/chunks/validateNonInterActiveAuth-JSNJZCYY.js +195 -0
- package/chunks/{version-NO2XSNNP.js → version-3NLBENG5.js} +3 -3
- package/chunks/{web-fetch-UYGMOHW4.js → web-fetch-ZSPR3PRR.js} +8 -8
- package/chunks/{workflow-WO2H6NRI.js → workflow-BQYLF7XP.js} +52 -51
- package/chunks/workspace-providers-status-FA2DGEZW.js +74 -0
- package/chunks/workspace-registration-store-TARTAGMI.js +27 -0
- package/chunks/workspace-registry-AGE7WAXX.js +77 -0
- package/chunks/workspace-service-ERC5VR2B.js +83 -0
- package/chunks/workspace-skills-status-FKYWGNCN.js +73 -0
- package/chunks/{write-file-PX2Z7IBE.js → write-file-S47KSK7Z.js} +52 -51
- package/chunks/{yargs-B64EYTCF.js → yargs-6H2AUULL.js} +2 -2
- package/chunks/{zh-J4F6QWQV.js → zh-FSAH32JB.js} +79 -7
- package/chunks/{zh-TW-XVDWOLSW.js → zh-TW-D2YIE2LO.js} +79 -7
- package/cli.js +18 -17
- package/locales/ca.js +91 -7
- package/locales/de.js +90 -7
- package/locales/en.js +109 -7
- package/locales/fr.js +91 -7
- package/locales/ja.js +93 -7
- package/locales/pt.js +90 -7
- package/locales/ru.js +90 -7
- package/locales/zh-TW.js +106 -7
- package/locales/zh.js +106 -7
- package/package.json +3 -6
- package/web-shell/assets/{arc-BWyoJpY2.js → arc-Zj4EkBUY.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-BT0mGrz2.js → architectureDiagram-3BPJPVTR-DAk1Ua3Y.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BLgUWvyf.js → blockDiagram-GPEHLZMM-DBNqUthM.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-DYx9M7oU.js → c4Diagram-AAUBKEIU-Dq5QGJ53.js} +1 -1
- package/web-shell/assets/channel-DWfYijFS.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-CfMHWbuZ.js → chunk-2J33WTMH-DY0AeGru.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-B1URoqEV.js → chunk-4BX2VUAB-COX3OyIi.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DAIaM4QF.js → chunk-55IACEB6-Csoyddbh.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-B2X34knw.js → chunk-727SXJPM-BJPONdxX.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-Cif-zLTQ.js → chunk-AQP2D5EJ-syLVH6fg.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-H18WCXdY.js → chunk-FMBD7UC4-Cfm59Nhw.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-YFtetHi0.js → chunk-ND2GUHAM-DZf6tAqS.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-By2hiH3r.js → chunk-QZHKN3VN-DKBp_v5q.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-DDht-78J.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-DDht-78J.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-VrcnnLZu.js → cose-bilkent-S5V4N54A-DUU3mMQ5.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CGo-IaVV.js → dagre-BM42HDAG-BUgNfbh-.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-Dl4QjzIB.js → diagram-2AECGRRQ-DT7MVfAg.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-qMLmsO0u.js → diagram-5GNKFQAL-Cv4YG-ec.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CHlmuxPI.js → diagram-KO2AKTUF-BAe9LLkn.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BUwU3GwT.js → diagram-LMA3HP47-DW8wqTIP.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-HEhwPDUM.js → diagram-OG6HWLK6-CmkuWbaK.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-1n0llBmM.js → erDiagram-TEJ5UH35-DwvdHjZ9.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BN74uMnt.js → flowDiagram-I6XJVG4X-CSsXrhW_.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BoOq78i3.js → ganttDiagram-6RSMTGT7-BtuznCdi.js} +3 -3
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CN8b00c8.js → gitGraphDiagram-PVQCEYII-DGmAm06g.js} +1 -1
- package/web-shell/assets/index-B9Xwf4OS.css +5 -0
- package/web-shell/assets/index-BEtz1cvN.js +3 -0
- package/web-shell/assets/index-BUkM4ZXX.js +1088 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CCurnIna.js → infoDiagram-5YYISTIA-OAiZ1q0K.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-AwuRqdUP.js → ishikawaDiagram-YF4QCWOH-DyK0KTIT.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-B7IICk-E.js → journeyDiagram-JHISSGLW-DzYJlwfO.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-BYF0OKhx.js → kanban-definition-UN3LZRKU-CU_tcDwi.js} +1 -1
- package/web-shell/assets/{linear-GWWguGfD.js → linear-DvZXjF17.js} +1 -1
- package/web-shell/assets/{mermaid.core-JqtkxvCl.js → mermaid.core-_ZFEQlOl.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-B0MmHsZ6.js → mindmap-definition-RKZ34NQL-Or4p64HB.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-DhImUZLQ.js → pieDiagram-4H26LBE5-lXE-zZ6b.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DGeSC3DT.js → quadrantDiagram-W4KKPZXB-DUXb9mUV.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-DkspY6Re.js → requirementDiagram-4Y6WPE33-D_10uHfo.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CaOofS2x.js → sankeyDiagram-5OEKKPKP-E8c0fPqe.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DFQ_kFnN.js → sequenceDiagram-3UESZ5HK-CJMtFttK.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-D3snw0Tz.js → stateDiagram-AJRCARHV-DhbviRbB.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CntljfwW.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-l4zH8nLM.js → timeline-definition-PNZ67QCA-CM5yMkFK.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BnRlA98M.js → vennDiagram-CIIHVFJN-BCi-zWNN.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-BS0xUdmd.js → wardley-L42UT6IY-BJ_yJNjJ.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-DKGBUWyQ.js → wardleyDiagram-YWT4CUSO-TjtLk-qN.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-DVb2HuOB.js → xychartDiagram-2RQKCTM6-D1TjyoQ3.js} +1 -1
- package/web-shell/index.html +16 -4
- package/chunks/MaxSizedBox-5DT2SD7B.js +0 -71
- package/chunks/agent-H2DGKS77.js +0 -68
- package/chunks/agent-headless-KFMFIT6J.js +0 -62
- package/chunks/bridge-NA3ZQQKJ.js +0 -78
- package/chunks/chunk-6SHO7WFF.js +0 -79
- package/chunks/chunk-IFEWJXFS.js +0 -37
- package/chunks/chunk-XNXVCNAT.js +0 -88
- package/chunks/contextCommand-LXFZRP4L.js +0 -68
- package/chunks/daemon-status-provider-GJRXY5EN.js +0 -76
- package/chunks/earlyInputCapture-KNOYZ4MJ.js +0 -69
- package/chunks/environment-ATFTYMLZ.js +0 -88
- package/chunks/errors-A54HAADA.js +0 -75
- package/chunks/handleAutoUpdate-CEZJAARW.js +0 -65
- package/chunks/initializer-BRFJKRRX.js +0 -71
- package/chunks/list-KVHF7O4X.js +0 -73
- package/chunks/loadedSettingsAdapter-LL5PSFKX.js +0 -68
- package/chunks/mcp-3GCXRTOQ.js +0 -68
- package/chunks/nonInteractiveCli-PTQI3DV6.js +0 -119
- package/chunks/openaiContentGenerator-YE42PKCY.js +0 -56
- package/chunks/pidfile-NZYSCFRK.js +0 -73
- package/chunks/read-file-33XGP5HF.js +0 -30
- package/chunks/ripGrep-QWZLGTAN.js +0 -60
- package/chunks/serve-JTMIGANH.js +0 -74
- package/chunks/settings-3MI4XXP6.js +0 -118
- package/chunks/shell-YJKBE67T.js +0 -68
- package/chunks/spawnChannel-UNV6W4DU.js +0 -70
- package/chunks/task-create-WCHTB435.js +0 -22
- package/chunks/theme-manager-WZ4RRMMB.js +0 -64
- package/chunks/total-session-admission-ULXJWXFV.js +0 -72
- package/chunks/trustedFolders-LAZZPZ3D.js +0 -79
- package/chunks/updateCheck-KONLM73X.js +0 -65
- package/chunks/validateNonInterActiveAuth-MPKSRCXD.js +0 -184
- package/chunks/workspace-providers-status-3W7E7DFW.js +0 -71
- package/chunks/workspace-registry-SXJZNN3O.js +0 -74
- package/chunks/workspace-service-CZRQZ4Q4.js +0 -80
- package/chunks/workspace-skills-status-K7WFREPD.js +0 -70
- package/node_modules/@qwen-code/audio-capture/dist/index.d.ts +0 -35
- package/node_modules/@qwen-code/audio-capture/dist/index.js +0 -48
- package/node_modules/@qwen-code/audio-capture/dist/index.js.map +0 -1
- package/node_modules/@qwen-code/audio-capture/dist/platform.d.ts +0 -7
- package/node_modules/@qwen-code/audio-capture/dist/platform.js +0 -18
- package/node_modules/@qwen-code/audio-capture/dist/platform.js.map +0 -1
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/LICENSE +0 -21
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/README.md +0 -58
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/SECURITY.md +0 -5
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/bin.js +0 -84
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/build-test.js +0 -19
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/index.js +0 -6
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/node-gyp-build.js +0 -207
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/optional.js +0 -7
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/package.json +0 -43
- package/node_modules/@qwen-code/audio-capture/package.json +0 -30
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/linux-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/linux-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/web-shell/assets/channel-wmPUGHtg.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BA2ljEjW.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BA2ljEjW.js +0 -1
- package/web-shell/assets/index-CNwoO1Cn.js +0 -783
- package/web-shell/assets/index-CWQ0z6kZ.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BbSm_9d0.js +0 -1
|
@@ -1,243 +1,35 @@
|
|
|
1
1
|
// Force strict mode and setup for ESM
|
|
2
2
|
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
updateEventEmitter
|
|
5
|
+
} from "./chunk-YAF2MQZ6.js";
|
|
3
6
|
import {
|
|
4
7
|
require_undici
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-L573Z2QZ.js";
|
|
9
|
+
import {
|
|
10
|
+
t
|
|
11
|
+
} from "./chunk-SE74CIZD.js";
|
|
6
12
|
import {
|
|
7
|
-
So
|
|
8
|
-
|
|
9
|
-
} from "./chunk-3GNOQZDC.js";
|
|
13
|
+
So
|
|
14
|
+
} from "./chunk-SSFDPGFN.js";
|
|
10
15
|
import {
|
|
11
16
|
createDebugLogger
|
|
12
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-7NFB7LBQ.js";
|
|
13
18
|
import {
|
|
14
19
|
init_esbuild_shims
|
|
15
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-5O2XNYP6.js";
|
|
16
21
|
import {
|
|
17
22
|
__name,
|
|
18
23
|
__toESM
|
|
19
24
|
} from "./chunk-J2S4EL5Y.js";
|
|
20
25
|
|
|
21
|
-
// packages/cli/src/utils/installationInfo.ts
|
|
22
|
-
init_esbuild_shims();
|
|
23
|
-
import * as fs from "node:fs";
|
|
24
|
-
import * as path from "node:path";
|
|
25
|
-
import * as childProcess from "node:child_process";
|
|
26
|
-
var debugLogger = createDebugLogger("INSTALLATION_INFO");
|
|
27
|
-
var STANDALONE_UNIX_INSTALLER = "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh";
|
|
28
|
-
var STANDALONE_WINDOWS_INSTALLER = "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.ps1";
|
|
29
|
-
function getInstallationInfo(projectRoot, isAutoUpdateEnabled) {
|
|
30
|
-
const cliPath = process.argv[1];
|
|
31
|
-
if (!cliPath) {
|
|
32
|
-
return { packageManager: "unknown" /* UNKNOWN */, isGlobal: false };
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
const realPath = fs.realpathSync(cliPath).replace(/\\/g, "/");
|
|
36
|
-
const normalizedProjectRoot = projectRoot?.replace(/\\/g, "/");
|
|
37
|
-
const isGit = isGitRepository(process.cwd());
|
|
38
|
-
if (isGit && normalizedProjectRoot && isSamePathOrInside(realPath, normalizedProjectRoot) && !realPath.includes("/node_modules/")) {
|
|
39
|
-
return {
|
|
40
|
-
packageManager: "unknown" /* UNKNOWN */,
|
|
41
|
-
// Not managed by a package manager in this sense
|
|
42
|
-
isGlobal: false,
|
|
43
|
-
updateMessage: 'Running from a local git clone. Please update with "git pull".'
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
if (realPath.includes("/.npm/_npx") || realPath.includes("/npm/_npx")) {
|
|
47
|
-
return {
|
|
48
|
-
packageManager: "npx" /* NPX */,
|
|
49
|
-
isGlobal: false,
|
|
50
|
-
updateMessage: "Running via npx, update not applicable."
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (realPath.includes("/.pnpm/_pnpx")) {
|
|
54
|
-
return {
|
|
55
|
-
packageManager: "pnpx" /* PNPX */,
|
|
56
|
-
isGlobal: false,
|
|
57
|
-
updateMessage: "Running via pnpx, update not applicable."
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const standaloneInfo = getStandaloneInstallInfo(
|
|
61
|
-
realPath,
|
|
62
|
-
isAutoUpdateEnabled
|
|
63
|
-
);
|
|
64
|
-
if (standaloneInfo) {
|
|
65
|
-
return standaloneInfo;
|
|
66
|
-
}
|
|
67
|
-
if (process.platform === "darwin") {
|
|
68
|
-
try {
|
|
69
|
-
childProcess.execSync('brew list -1 | grep -q "^qwen-code$"', {
|
|
70
|
-
stdio: "ignore"
|
|
71
|
-
});
|
|
72
|
-
return {
|
|
73
|
-
packageManager: "homebrew" /* HOMEBREW */,
|
|
74
|
-
isGlobal: true,
|
|
75
|
-
updateMessage: 'Installed via Homebrew. Please update with "brew upgrade".'
|
|
76
|
-
};
|
|
77
|
-
} catch (_error) {
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (realPath.includes("/.pnpm/global")) {
|
|
81
|
-
const updateCommand2 = "pnpm add -g @qwen-code/qwen-code@latest";
|
|
82
|
-
return {
|
|
83
|
-
packageManager: "pnpm" /* PNPM */,
|
|
84
|
-
isGlobal: true,
|
|
85
|
-
updateCommand: updateCommand2,
|
|
86
|
-
updateMessage: isAutoUpdateEnabled ? "Installed with pnpm. Attempting to automatically update now..." : `Please run ${updateCommand2} to update`
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
if (realPath.includes("/.yarn/global")) {
|
|
90
|
-
const updateCommand2 = "yarn global add @qwen-code/qwen-code@latest";
|
|
91
|
-
return {
|
|
92
|
-
packageManager: "yarn" /* YARN */,
|
|
93
|
-
isGlobal: true,
|
|
94
|
-
updateCommand: updateCommand2,
|
|
95
|
-
updateMessage: isAutoUpdateEnabled ? "Installed with yarn. Attempting to automatically update now..." : `Please run ${updateCommand2} to update`
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (realPath.includes("/.bun/install/cache")) {
|
|
99
|
-
return {
|
|
100
|
-
packageManager: "bunx" /* BUNX */,
|
|
101
|
-
isGlobal: false,
|
|
102
|
-
updateMessage: "Running via bunx, update not applicable."
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
if (realPath.includes("/.bun/bin")) {
|
|
106
|
-
const updateCommand2 = "bun add -g @qwen-code/qwen-code@latest";
|
|
107
|
-
return {
|
|
108
|
-
packageManager: "bun" /* BUN */,
|
|
109
|
-
isGlobal: true,
|
|
110
|
-
updateCommand: updateCommand2,
|
|
111
|
-
updateMessage: isAutoUpdateEnabled ? "Installed with bun. Attempting to automatically update now..." : `Please run ${updateCommand2} to update`
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (normalizedProjectRoot && isSamePathOrInside(realPath, `${normalizedProjectRoot}/node_modules`)) {
|
|
115
|
-
let pm = "npm" /* NPM */;
|
|
116
|
-
if (fs.existsSync(path.join(projectRoot, "yarn.lock"))) {
|
|
117
|
-
pm = "yarn" /* YARN */;
|
|
118
|
-
} else if (fs.existsSync(path.join(projectRoot, "pnpm-lock.yaml"))) {
|
|
119
|
-
pm = "pnpm" /* PNPM */;
|
|
120
|
-
} else if (fs.existsSync(path.join(projectRoot, "bun.lockb"))) {
|
|
121
|
-
pm = "bun" /* BUN */;
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
packageManager: pm,
|
|
125
|
-
isGlobal: false,
|
|
126
|
-
updateMessage: "Locally installed. Please update via your project's package.json."
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
const npmPackageDir = path.dirname(path.dirname(realPath));
|
|
130
|
-
let npmPrefixWritable = false;
|
|
131
|
-
try {
|
|
132
|
-
fs.accessSync(npmPackageDir, fs.constants.W_OK);
|
|
133
|
-
npmPrefixWritable = true;
|
|
134
|
-
} catch {
|
|
135
|
-
}
|
|
136
|
-
if (!npmPrefixWritable) {
|
|
137
|
-
return {
|
|
138
|
-
packageManager: "npm" /* NPM */,
|
|
139
|
-
isGlobal: true,
|
|
140
|
-
updateMessage: "Update requires sudo. Please run: sudo npm install -g @qwen-code/qwen-code@latest"
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const updateCommand = "npm install -g @qwen-code/qwen-code@latest";
|
|
144
|
-
return {
|
|
145
|
-
packageManager: "npm" /* NPM */,
|
|
146
|
-
isGlobal: true,
|
|
147
|
-
updateCommand,
|
|
148
|
-
updateMessage: isAutoUpdateEnabled ? "Installed with npm. Attempting to automatically update now..." : `Please run ${updateCommand} to update`
|
|
149
|
-
};
|
|
150
|
-
} catch (error) {
|
|
151
|
-
debugLogger.error("Failed to detect installation info:", error);
|
|
152
|
-
return { packageManager: "unknown" /* UNKNOWN */, isGlobal: false };
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
__name(getInstallationInfo, "getInstallationInfo");
|
|
156
|
-
function stripTrailingSlashes(value) {
|
|
157
|
-
return value.replace(/\/+$/, "") || "/";
|
|
158
|
-
}
|
|
159
|
-
__name(stripTrailingSlashes, "stripTrailingSlashes");
|
|
160
|
-
function isSamePathOrInside(candidate, parent) {
|
|
161
|
-
const normalizedCandidate = stripTrailingSlashes(candidate);
|
|
162
|
-
const normalizedParent = stripTrailingSlashes(parent);
|
|
163
|
-
if (normalizedParent === "/") {
|
|
164
|
-
return normalizedCandidate === "/" || normalizedCandidate.startsWith("/");
|
|
165
|
-
}
|
|
166
|
-
return normalizedCandidate === normalizedParent || normalizedCandidate.startsWith(`${normalizedParent}/`);
|
|
167
|
-
}
|
|
168
|
-
__name(isSamePathOrInside, "isSamePathOrInside");
|
|
169
|
-
function getStandaloneInstallInfo(realPath, isAutoUpdateEnabled) {
|
|
170
|
-
const installDir = standaloneInstallDirForCliPath(realPath);
|
|
171
|
-
if (!installDir || !isStandaloneInstallDir(installDir)) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
const updateCommand = process.platform === "win32" ? `powershell -ExecutionPolicy Bypass -c "irm ${STANDALONE_WINDOWS_INSTALLER} | iex"` : `curl -fsSL ${STANDALONE_UNIX_INSTALLER} | bash`;
|
|
175
|
-
return {
|
|
176
|
-
packageManager: "standalone" /* STANDALONE */,
|
|
177
|
-
isGlobal: true,
|
|
178
|
-
isStandalone: true,
|
|
179
|
-
standaloneDir: installDir,
|
|
180
|
-
updateMessage: isAutoUpdateEnabled ? "Standalone install detected. Attempting to automatically update now..." : `Standalone install detected. Please rerun the standalone installer to update: ${updateCommand}`
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
__name(getStandaloneInstallInfo, "getStandaloneInstallInfo");
|
|
184
|
-
function standaloneInstallDirForCliPath(realPath) {
|
|
185
|
-
const normalized = realPath.replace(/\\/g, "/");
|
|
186
|
-
const suffix = "/lib/cli.js";
|
|
187
|
-
if (!normalized.endsWith(suffix)) {
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
return realPath.slice(0, -suffix.length);
|
|
191
|
-
}
|
|
192
|
-
__name(standaloneInstallDirForCliPath, "standaloneInstallDirForCliPath");
|
|
193
|
-
function isStandaloneInstallDir(installDir) {
|
|
194
|
-
try {
|
|
195
|
-
const manifestPath = path.join(installDir, "manifest.json");
|
|
196
|
-
if (!fs.existsSync(manifestPath)) {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
200
|
-
if (manifest.name !== "@qwen-code/qwen-code" || typeof manifest.target !== "string" || !isStandaloneTargetForCurrentPlatform(manifest.target)) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
const qwenBin = process.platform === "win32" ? path.join(installDir, "bin", "qwen.cmd") : path.join(installDir, "bin", "qwen");
|
|
204
|
-
const nodeBin = process.platform === "win32" ? path.join(installDir, "node", "node.exe") : path.join(installDir, "node", "bin", "node");
|
|
205
|
-
return fs.existsSync(qwenBin) && fs.existsSync(nodeBin) && isStandaloneRuntimeFile(qwenBin) && isStandaloneRuntimeFile(nodeBin);
|
|
206
|
-
} catch (err) {
|
|
207
|
-
debugLogger.error("Standalone detection failed:", installDir, err);
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
__name(isStandaloneInstallDir, "isStandaloneInstallDir");
|
|
212
|
-
function isStandaloneTargetForCurrentPlatform(target) {
|
|
213
|
-
switch (process.platform) {
|
|
214
|
-
case "darwin":
|
|
215
|
-
return /^darwin-(arm64|x64)$/.test(target);
|
|
216
|
-
case "linux":
|
|
217
|
-
return /^linux-(arm64|x64)$/.test(target);
|
|
218
|
-
case "win32":
|
|
219
|
-
return /^win-(arm64|x64)$/.test(target);
|
|
220
|
-
default:
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
__name(isStandaloneTargetForCurrentPlatform, "isStandaloneTargetForCurrentPlatform");
|
|
225
|
-
function isStandaloneRuntimeFile(filePath) {
|
|
226
|
-
const stats = fs.lstatSync(filePath);
|
|
227
|
-
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
return process.platform === "win32" || (stats.mode & 73) !== 0;
|
|
231
|
-
}
|
|
232
|
-
__name(isStandaloneRuntimeFile, "isStandaloneRuntimeFile");
|
|
233
|
-
|
|
234
26
|
// packages/cli/src/utils/standalone-update.ts
|
|
235
27
|
init_esbuild_shims();
|
|
236
28
|
var import_undici = __toESM(require_undici(), 1);
|
|
237
29
|
import { createHash } from "node:crypto";
|
|
238
|
-
import * as
|
|
30
|
+
import * as fs from "node:fs";
|
|
239
31
|
import * as os from "node:os";
|
|
240
|
-
import * as
|
|
32
|
+
import * as path from "node:path";
|
|
241
33
|
import { Readable, Transform } from "node:stream";
|
|
242
34
|
import { spawn, execFile } from "node:child_process";
|
|
243
35
|
import { pipeline } from "node:stream/promises";
|
|
@@ -268,7 +60,7 @@ function verifySignature(sha256sumsContent, signatureBase64) {
|
|
|
268
60
|
__name(verifySignature, "verifySignature");
|
|
269
61
|
|
|
270
62
|
// packages/cli/src/utils/standalone-update.ts
|
|
271
|
-
var
|
|
63
|
+
var debugLogger = createDebugLogger("STANDALONE_UPDATE");
|
|
272
64
|
var OSS_BASE = "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/releases/qwen-code";
|
|
273
65
|
var GITHUB_BASE = "https://github.com/QwenLM/qwen-code/releases/download";
|
|
274
66
|
var FETCH_TIMEOUT_MS = 3e4;
|
|
@@ -314,7 +106,7 @@ async function tryFetch(url, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
|
314
106
|
return { error: new Error(`HTTP ${res.status} ${res.statusText}`) };
|
|
315
107
|
} catch (err) {
|
|
316
108
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
317
|
-
|
|
109
|
+
debugLogger.debug(`Fetch failed for ${url}: ${error.message}`);
|
|
318
110
|
return { error };
|
|
319
111
|
}
|
|
320
112
|
}
|
|
@@ -339,18 +131,18 @@ async function verifyChecksum(actualHash, filename, versionPath) {
|
|
|
339
131
|
try {
|
|
340
132
|
sigResponse = await downloadWithFallback(versionPath, "SHA256SUMS.sig");
|
|
341
133
|
} catch (err) {
|
|
342
|
-
|
|
134
|
+
debugLogger.debug("SHA256SUMS.sig not available:", err);
|
|
343
135
|
}
|
|
344
136
|
if (sigResponse) {
|
|
345
137
|
const sigContent = await sigResponse.text();
|
|
346
138
|
verifySignature(text, sigContent.trim());
|
|
347
|
-
|
|
139
|
+
debugLogger.info("SHA256SUMS signature verified.");
|
|
348
140
|
} else if (requireSig) {
|
|
349
141
|
throw new Error(
|
|
350
142
|
"SHA256SUMS.sig not found and QWEN_REQUIRE_SIGNATURE=1 is set"
|
|
351
143
|
);
|
|
352
144
|
} else {
|
|
353
|
-
|
|
145
|
+
debugLogger.warn(
|
|
354
146
|
"SHA256SUMS.sig not available \u2014 update integrity relies on SHA256 checksum only. Set QWEN_REQUIRE_SIGNATURE=1 to enforce signature verification."
|
|
355
147
|
);
|
|
356
148
|
}
|
|
@@ -390,7 +182,7 @@ async function downloadToFile(versionPath, filename, destPath) {
|
|
|
390
182
|
}
|
|
391
183
|
const hash = createHash("sha256");
|
|
392
184
|
let bytesWritten = 0;
|
|
393
|
-
const dest =
|
|
185
|
+
const dest = fs.createWriteStream(destPath);
|
|
394
186
|
const sizeGuard = new Transform({
|
|
395
187
|
transform(chunk, _encoding, callback) {
|
|
396
188
|
bytesWritten += chunk.length;
|
|
@@ -408,19 +200,89 @@ async function downloadToFile(versionPath, filename, destPath) {
|
|
|
408
200
|
return hash.digest("hex");
|
|
409
201
|
}
|
|
410
202
|
__name(downloadToFile, "downloadToFile");
|
|
411
|
-
function
|
|
412
|
-
const
|
|
203
|
+
function isPathInside(base, candidate) {
|
|
204
|
+
const rel = path.relative(base, candidate);
|
|
205
|
+
return rel === "" || !!rel && rel !== ".." && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
|
|
206
|
+
}
|
|
207
|
+
__name(isPathInside, "isPathInside");
|
|
208
|
+
function normalizeTarEntryPath(entryPath) {
|
|
209
|
+
const parts = entryPath.split(/[\\/]+/).filter((part) => part && part !== ".");
|
|
210
|
+
if (parts.length === 0 || parts.includes("..")) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return parts.join("/");
|
|
214
|
+
}
|
|
215
|
+
__name(normalizeTarEntryPath, "normalizeTarEntryPath");
|
|
216
|
+
function isSafeTarLinkTarget(entryPath, linkPath, resolvedDest) {
|
|
217
|
+
if (path.posix.isAbsolute(linkPath) || path.win32.isAbsolute(linkPath)) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
const normalizedEntryPath = normalizeTarEntryPath(entryPath);
|
|
221
|
+
if (!normalizedEntryPath) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
const archiveRoot = normalizedEntryPath.split("/")[0];
|
|
225
|
+
const linkTarget = path.resolve(
|
|
226
|
+
resolvedDest,
|
|
227
|
+
path.posix.dirname(normalizedEntryPath),
|
|
228
|
+
linkPath
|
|
229
|
+
);
|
|
230
|
+
return isPathInside(path.join(resolvedDest, archiveRoot), linkTarget);
|
|
231
|
+
}
|
|
232
|
+
__name(isSafeTarLinkTarget, "isSafeTarLinkTarget");
|
|
233
|
+
function getTarEntryType(entry) {
|
|
234
|
+
if ("type" in entry) return entry.type;
|
|
235
|
+
if ("isFile" in entry && entry.isFile()) return "File";
|
|
236
|
+
if ("isDirectory" in entry && entry.isDirectory()) return "Directory";
|
|
237
|
+
if ("isSymbolicLink" in entry && entry.isSymbolicLink()) {
|
|
238
|
+
return "SymbolicLink";
|
|
239
|
+
}
|
|
240
|
+
return void 0;
|
|
241
|
+
}
|
|
242
|
+
__name(getTarEntryType, "getTarEntryType");
|
|
243
|
+
function isSafeTarEntry(entryPath, entry, resolvedDest) {
|
|
244
|
+
if (!isSafeTarEntryPath(entryPath)) return false;
|
|
245
|
+
const entryType = getTarEntryType(entry);
|
|
246
|
+
const linkPath = "linkpath" in entry ? entry.linkpath : void 0;
|
|
247
|
+
if (entryType !== "File" && entryType !== "Directory" && entryType !== "SymbolicLink") {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
if (entryType === "SymbolicLink") {
|
|
251
|
+
if (linkPath === void 0) return false;
|
|
252
|
+
return isSafeTarLinkTarget(entryPath, String(linkPath), resolvedDest);
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
__name(isSafeTarEntry, "isSafeTarEntry");
|
|
257
|
+
function isAlreadyExistsError(err) {
|
|
258
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "EEXIST";
|
|
259
|
+
}
|
|
260
|
+
__name(isAlreadyExistsError, "isAlreadyExistsError");
|
|
261
|
+
function validateExtractedPaths(resolvedDest, options = {}) {
|
|
262
|
+
const entries = fs.readdirSync(resolvedDest, {
|
|
413
263
|
recursive: true,
|
|
414
264
|
withFileTypes: true
|
|
415
265
|
});
|
|
416
266
|
for (const entry of entries) {
|
|
417
|
-
|
|
267
|
+
if (options.symlinksOnly && !entry.isSymbolicLink()) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const fullPath = path.join(
|
|
418
271
|
String(entry.parentPath || entry.path),
|
|
419
272
|
entry.name
|
|
420
273
|
);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
274
|
+
let resolved;
|
|
275
|
+
try {
|
|
276
|
+
resolved = fs.realpathSync(fullPath);
|
|
277
|
+
} catch (err) {
|
|
278
|
+
fs.rmSync(resolvedDest, { recursive: true, force: true });
|
|
279
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Invalid archive entry: ${entry.name} could not be resolved (${detail})`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
if (!isPathInside(resolvedDest, resolved)) {
|
|
285
|
+
fs.rmSync(resolvedDest, { recursive: true, force: true });
|
|
424
286
|
throw new Error(
|
|
425
287
|
`Path traversal detected in archive: ${entry.name} resolves to ${resolved}`
|
|
426
288
|
);
|
|
@@ -430,14 +292,14 @@ function validateExtractedPaths(resolvedDest) {
|
|
|
430
292
|
__name(validateExtractedPaths, "validateExtractedPaths");
|
|
431
293
|
function isSafeTarEntryPath(entryPath) {
|
|
432
294
|
if (entryPath.length === 0) return false;
|
|
433
|
-
if (
|
|
295
|
+
if (path.posix.isAbsolute(entryPath) || path.win32.isAbsolute(entryPath)) {
|
|
434
296
|
return false;
|
|
435
297
|
}
|
|
436
|
-
return
|
|
298
|
+
return normalizeTarEntryPath(entryPath) !== null;
|
|
437
299
|
}
|
|
438
300
|
__name(isSafeTarEntryPath, "isSafeTarEntryPath");
|
|
439
301
|
async function extractArchive(archivePath, destDir, target) {
|
|
440
|
-
|
|
302
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
441
303
|
if (target.startsWith("win")) {
|
|
442
304
|
await new Promise((resolve2, reject) => {
|
|
443
305
|
const ps = spawn(
|
|
@@ -455,30 +317,17 @@ async function extractArchive(archivePath, destDir, target) {
|
|
|
455
317
|
);
|
|
456
318
|
ps.on("error", reject);
|
|
457
319
|
});
|
|
458
|
-
const resolvedDest =
|
|
320
|
+
const resolvedDest = fs.realpathSync(destDir);
|
|
459
321
|
validateExtractedPaths(resolvedDest);
|
|
460
322
|
} else {
|
|
461
|
-
const resolvedDest =
|
|
323
|
+
const resolvedDest = fs.realpathSync(destDir);
|
|
462
324
|
await So({
|
|
463
325
|
file: archivePath,
|
|
464
326
|
cwd: destDir,
|
|
465
327
|
preservePaths: false,
|
|
466
|
-
filter: /* @__PURE__ */ __name((p, entry) =>
|
|
467
|
-
if (!isSafeTarEntryPath(p)) return false;
|
|
468
|
-
if ("type" in entry && entry.type === "SymbolicLink" && "linkpath" in entry) {
|
|
469
|
-
const linkTarget = path2.resolve(
|
|
470
|
-
resolvedDest,
|
|
471
|
-
path2.dirname(p),
|
|
472
|
-
String(entry.linkpath)
|
|
473
|
-
);
|
|
474
|
-
if (!linkTarget.startsWith(resolvedDest + path2.sep) && linkTarget !== resolvedDest) {
|
|
475
|
-
return false;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
return true;
|
|
479
|
-
}, "filter")
|
|
328
|
+
filter: /* @__PURE__ */ __name((p, entry) => isSafeTarEntry(p, entry, resolvedDest), "filter")
|
|
480
329
|
});
|
|
481
|
-
validateExtractedPaths(
|
|
330
|
+
validateExtractedPaths(fs.realpathSync(destDir), { symlinksOnly: true });
|
|
482
331
|
}
|
|
483
332
|
}
|
|
484
333
|
__name(extractArchive, "extractArchive");
|
|
@@ -513,13 +362,13 @@ function spawnAndCapture(command, args, timeoutMs) {
|
|
|
513
362
|
}
|
|
514
363
|
__name(spawnAndCapture, "spawnAndCapture");
|
|
515
364
|
async function smokeTest(newInstallDir, target) {
|
|
516
|
-
const resolvedInstallDir =
|
|
517
|
-
const nodeBin = target.startsWith("win") ?
|
|
518
|
-
const cliBin =
|
|
519
|
-
if (!
|
|
365
|
+
const resolvedInstallDir = path.resolve(newInstallDir);
|
|
366
|
+
const nodeBin = target.startsWith("win") ? path.join(resolvedInstallDir, "node", "node.exe") : path.join(resolvedInstallDir, "node", "bin", "node");
|
|
367
|
+
const cliBin = path.join(resolvedInstallDir, "lib", "cli.js");
|
|
368
|
+
if (!fs.existsSync(nodeBin)) {
|
|
520
369
|
throw new Error(`Smoke test failed: node binary not found at ${nodeBin}`);
|
|
521
370
|
}
|
|
522
|
-
if (!
|
|
371
|
+
if (!fs.existsSync(cliBin)) {
|
|
523
372
|
throw new Error(`Smoke test failed: cli.js not found at ${cliBin}`);
|
|
524
373
|
}
|
|
525
374
|
const { exitCode, stdout, stderr } = await spawnAndCapture(
|
|
@@ -539,56 +388,109 @@ async function smokeTest(newInstallDir, target) {
|
|
|
539
388
|
`Smoke test failed: unexpected version output "${version}"`
|
|
540
389
|
);
|
|
541
390
|
}
|
|
542
|
-
|
|
391
|
+
debugLogger.info(`Smoke test passed: ${version}`);
|
|
543
392
|
}
|
|
544
393
|
__name(smokeTest, "smokeTest");
|
|
545
|
-
function
|
|
394
|
+
function checkDeferredSwap(standaloneDir) {
|
|
395
|
+
const deferredMarker = `${standaloneDir}.deferred`;
|
|
396
|
+
if (fs.existsSync(deferredMarker)) {
|
|
397
|
+
try {
|
|
398
|
+
const batPid = parseInt(
|
|
399
|
+
fs.readFileSync(deferredMarker, "utf-8").trim(),
|
|
400
|
+
10
|
|
401
|
+
);
|
|
402
|
+
if (!Number.isNaN(batPid) && isProcessAlive(batPid)) {
|
|
403
|
+
throw new Error(
|
|
404
|
+
"A previous update is still being applied. Please wait a moment and try again."
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
} catch (readErr) {
|
|
408
|
+
if (readErr instanceof Error && readErr.message.startsWith("A previous update")) {
|
|
409
|
+
throw readErr;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
try {
|
|
413
|
+
fs.unlinkSync(deferredMarker);
|
|
414
|
+
} catch {
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (fs.existsSync(`${standaloneDir}.new`)) {
|
|
418
|
+
throw new Error(
|
|
419
|
+
`A previous update left a pending swap at ${standaloneDir}.new. If no qwen-update.bat process is running, remove the pending swap and .qwen-update.lock, then try again.`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
__name(checkDeferredSwap, "checkDeferredSwap");
|
|
424
|
+
function acquireLock(lockPath, standaloneDir) {
|
|
546
425
|
try {
|
|
547
|
-
|
|
426
|
+
fs.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
427
|
+
if (standaloneDir) {
|
|
428
|
+
checkDeferredSwap(standaloneDir);
|
|
429
|
+
}
|
|
548
430
|
return true;
|
|
549
|
-
} catch {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
fs2.unlinkSync(lockPath);
|
|
555
|
-
try {
|
|
556
|
-
fs2.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
557
|
-
return true;
|
|
558
|
-
} catch {
|
|
559
|
-
return false;
|
|
560
|
-
}
|
|
431
|
+
} catch (fastPathErr) {
|
|
432
|
+
if (fastPathErr instanceof Error && (fastPathErr.message.startsWith("A previous update") || fastPathErr.message.includes("pending swap"))) {
|
|
433
|
+
try {
|
|
434
|
+
fs.unlinkSync(lockPath);
|
|
435
|
+
} catch {
|
|
561
436
|
}
|
|
437
|
+
throw fastPathErr;
|
|
438
|
+
}
|
|
439
|
+
let pidStr;
|
|
440
|
+
try {
|
|
441
|
+
pidStr = fs.readFileSync(lockPath, "utf-8").trim();
|
|
442
|
+
} catch {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
const pid = parseInt(pidStr, 10);
|
|
446
|
+
if (!Number.isNaN(pid) && isProcessAlive(pid)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (standaloneDir) {
|
|
450
|
+
checkDeferredSwap(standaloneDir);
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
fs.unlinkSync(lockPath);
|
|
454
|
+
fs.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
455
|
+
return true;
|
|
562
456
|
} catch {
|
|
457
|
+
return false;
|
|
563
458
|
}
|
|
564
|
-
return false;
|
|
565
459
|
}
|
|
566
460
|
}
|
|
567
461
|
__name(acquireLock, "acquireLock");
|
|
568
462
|
function releaseLock(lockPath) {
|
|
569
463
|
try {
|
|
570
|
-
|
|
464
|
+
fs.unlinkSync(lockPath);
|
|
571
465
|
} catch {
|
|
572
466
|
}
|
|
573
467
|
}
|
|
574
468
|
__name(releaseLock, "releaseLock");
|
|
575
469
|
function cleanupEmptyStandaloneDir(standaloneDir) {
|
|
576
|
-
const manifestPath =
|
|
577
|
-
if (
|
|
578
|
-
|
|
470
|
+
const manifestPath = path.join(standaloneDir, "manifest.json");
|
|
471
|
+
if (fs.existsSync(standaloneDir) && !fs.existsSync(manifestPath)) {
|
|
472
|
+
fs.rmSync(standaloneDir, { recursive: true, force: true });
|
|
579
473
|
}
|
|
580
474
|
}
|
|
581
475
|
__name(cleanupEmptyStandaloneDir, "cleanupEmptyStandaloneDir");
|
|
582
|
-
var UNSAFE_SHELL_CHARS = /[
|
|
476
|
+
var UNSAFE_SHELL_CHARS = /[\0\n\r]/;
|
|
583
477
|
var UNSAFE_CMD_CHARS = /[&|<>^%!"`\n\r]/;
|
|
584
|
-
function
|
|
478
|
+
function assertSafeForSingleQuotedShellPath(p, context) {
|
|
585
479
|
if (UNSAFE_SHELL_CHARS.test(p)) {
|
|
586
480
|
throw new Error(
|
|
587
481
|
`${context} contains characters unsafe for shell embedding: ${p}`
|
|
588
482
|
);
|
|
589
483
|
}
|
|
590
484
|
}
|
|
591
|
-
__name(
|
|
485
|
+
__name(assertSafeForSingleQuotedShellPath, "assertSafeForSingleQuotedShellPath");
|
|
486
|
+
function shellQuoteForSh(p) {
|
|
487
|
+
return `'${p.replace(/'/g, "'\\''")}'`;
|
|
488
|
+
}
|
|
489
|
+
__name(shellQuoteForSh, "shellQuoteForSh");
|
|
490
|
+
function shellQuoteForFish(p) {
|
|
491
|
+
return shellQuoteForSh(p);
|
|
492
|
+
}
|
|
493
|
+
__name(shellQuoteForFish, "shellQuoteForFish");
|
|
592
494
|
function isProcessAlive(pid) {
|
|
593
495
|
try {
|
|
594
496
|
process.kill(pid, 0);
|
|
@@ -601,8 +503,8 @@ __name(isProcessAlive, "isProcessAlive");
|
|
|
601
503
|
function atomicReplace(standaloneDir, newDir, lockPath) {
|
|
602
504
|
const oldDir = `${standaloneDir}.old`;
|
|
603
505
|
const pendingDir = `${standaloneDir}.new`;
|
|
604
|
-
if (
|
|
605
|
-
|
|
506
|
+
if (fs.existsSync(oldDir)) {
|
|
507
|
+
fs.rmSync(oldDir, { recursive: true, force: true });
|
|
606
508
|
}
|
|
607
509
|
if (os.platform() === "win32") {
|
|
608
510
|
if (UNSAFE_CMD_CHARS.test(standaloneDir) || UNSAFE_CMD_CHARS.test(oldDir) || UNSAFE_CMD_CHARS.test(pendingDir)) {
|
|
@@ -610,12 +512,13 @@ function atomicReplace(standaloneDir, newDir, lockPath) {
|
|
|
610
512
|
"Installation path contains characters unsafe for deferred update script"
|
|
611
513
|
);
|
|
612
514
|
}
|
|
613
|
-
if (
|
|
614
|
-
|
|
515
|
+
if (fs.existsSync(pendingDir)) {
|
|
516
|
+
fs.rmSync(pendingDir, { recursive: true, force: true });
|
|
615
517
|
}
|
|
616
|
-
|
|
518
|
+
fs.renameSync(newDir, pendingDir);
|
|
617
519
|
const lockFile = lockPath;
|
|
618
|
-
const
|
|
520
|
+
const deferredMarker = `${standaloneDir}.deferred`;
|
|
521
|
+
const logFile = path.join(path.dirname(standaloneDir), "qwen-update.log");
|
|
619
522
|
const script = [
|
|
620
523
|
"@echo off",
|
|
621
524
|
"set /a TRIES=0",
|
|
@@ -643,27 +546,38 @@ function atomicReplace(standaloneDir, newDir, lockPath) {
|
|
|
643
546
|
` echo [%DATE% %TIME%] rollback succeeded >> "${logFile}"`,
|
|
644
547
|
")",
|
|
645
548
|
":cleanup",
|
|
549
|
+
`del /F /Q "${deferredMarker}" 2>nul`,
|
|
646
550
|
`del /F /Q "${lockFile}" 2>nul`,
|
|
647
551
|
`del "%~f0"`
|
|
648
552
|
].join("\r\n");
|
|
649
|
-
const scriptPath =
|
|
650
|
-
|
|
553
|
+
const scriptPath = path.join(
|
|
554
|
+
path.dirname(standaloneDir),
|
|
651
555
|
"qwen-update.bat"
|
|
652
556
|
);
|
|
653
|
-
|
|
654
|
-
spawn("cmd.exe", ["/c", scriptPath], {
|
|
557
|
+
fs.writeFileSync(scriptPath, script);
|
|
558
|
+
const child = spawn("cmd.exe", ["/c", scriptPath], {
|
|
655
559
|
detached: true,
|
|
656
560
|
stdio: "ignore",
|
|
657
561
|
windowsHide: true
|
|
658
|
-
})
|
|
562
|
+
});
|
|
563
|
+
child.on("error", (err) => {
|
|
564
|
+
debugLogger.warn("Deferred bat script failed to spawn:", err);
|
|
565
|
+
});
|
|
566
|
+
child.unref();
|
|
567
|
+
if (!child.pid) {
|
|
568
|
+
throw new Error(
|
|
569
|
+
"Failed to spawn deferred update script. Update was not applied."
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
fs.writeFileSync(deferredMarker, String(child.pid));
|
|
659
573
|
return "deferred";
|
|
660
574
|
} else {
|
|
661
|
-
|
|
575
|
+
fs.renameSync(standaloneDir, oldDir);
|
|
662
576
|
try {
|
|
663
|
-
|
|
577
|
+
fs.renameSync(newDir, standaloneDir);
|
|
664
578
|
} catch (promoteErr) {
|
|
665
579
|
try {
|
|
666
|
-
|
|
580
|
+
fs.renameSync(oldDir, standaloneDir);
|
|
667
581
|
} catch (rollbackErr) {
|
|
668
582
|
const detail = `Standalone update failed AND rollback failed.
|
|
669
583
|
Original error: ${promoteErr.message}
|
|
@@ -678,75 +592,164 @@ Manual recovery: mv "${oldDir}" "${standaloneDir}"`;
|
|
|
678
592
|
}
|
|
679
593
|
__name(atomicReplace, "atomicReplace");
|
|
680
594
|
function ensureBinWrapper(standaloneDir, target) {
|
|
681
|
-
const binDir =
|
|
595
|
+
const binDir = path.join(path.dirname(standaloneDir), "..", "bin");
|
|
596
|
+
const artifacts = { wrapperCreated: false };
|
|
682
597
|
try {
|
|
683
|
-
|
|
598
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
684
599
|
if (target.startsWith("win")) {
|
|
685
600
|
if (UNSAFE_CMD_CHARS.test(standaloneDir)) {
|
|
686
601
|
throw new Error(
|
|
687
602
|
"standaloneDir contains characters unsafe for cmd.exe wrapper"
|
|
688
603
|
);
|
|
689
604
|
}
|
|
690
|
-
const wrapperPath =
|
|
691
|
-
|
|
692
|
-
|
|
605
|
+
const wrapperPath = path.join(binDir, "qwen.cmd");
|
|
606
|
+
artifacts.wrapperPath = wrapperPath;
|
|
607
|
+
const content = `@echo off\r
|
|
693
608
|
call "${standaloneDir}\\bin\\qwen.cmd" %*\r
|
|
694
609
|
`;
|
|
695
|
-
|
|
610
|
+
try {
|
|
611
|
+
fs.writeFileSync(wrapperPath, content, { flag: "wx" });
|
|
612
|
+
artifacts.wrapperCreated = true;
|
|
613
|
+
} catch (err) {
|
|
614
|
+
if (!isAlreadyExistsError(err)) {
|
|
615
|
+
throw err;
|
|
616
|
+
}
|
|
617
|
+
artifacts.wrapperNeedsAttention = !existingWrapperMatches(
|
|
618
|
+
wrapperPath,
|
|
619
|
+
standaloneDir
|
|
620
|
+
);
|
|
696
621
|
}
|
|
697
622
|
} else {
|
|
698
|
-
|
|
699
|
-
const wrapperPath =
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
623
|
+
assertSafeForSingleQuotedShellPath(standaloneDir, "standaloneDir");
|
|
624
|
+
const wrapperPath = path.join(binDir, "qwen");
|
|
625
|
+
artifacts.wrapperPath = wrapperPath;
|
|
626
|
+
const quotedQwenBin = shellQuoteForSh(
|
|
627
|
+
path.join(standaloneDir, "bin", "qwen")
|
|
628
|
+
);
|
|
629
|
+
const content = `#!/usr/bin/env sh
|
|
630
|
+
exec ${quotedQwenBin} "$@"
|
|
703
631
|
`;
|
|
704
|
-
|
|
632
|
+
try {
|
|
633
|
+
fs.writeFileSync(wrapperPath, content, { mode: 493, flag: "wx" });
|
|
634
|
+
artifacts.wrapperCreated = true;
|
|
635
|
+
} catch (err) {
|
|
636
|
+
if (!isAlreadyExistsError(err)) {
|
|
637
|
+
throw err;
|
|
638
|
+
}
|
|
639
|
+
artifacts.wrapperNeedsAttention = !existingWrapperMatches(
|
|
640
|
+
wrapperPath,
|
|
641
|
+
standaloneDir
|
|
642
|
+
);
|
|
705
643
|
}
|
|
706
|
-
ensurePathInShellRc(binDir);
|
|
644
|
+
artifacts.shellPathUpdate = ensurePathInShellRc(binDir);
|
|
707
645
|
}
|
|
646
|
+
return artifacts;
|
|
708
647
|
} catch (err) {
|
|
709
|
-
|
|
648
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
649
|
+
throw new Error(`Failed to create bin wrapper: ${detail}`);
|
|
710
650
|
}
|
|
711
651
|
}
|
|
712
652
|
__name(ensureBinWrapper, "ensureBinWrapper");
|
|
653
|
+
function existingWrapperMatches(wrapperPath, standaloneDir) {
|
|
654
|
+
try {
|
|
655
|
+
return fs.readFileSync(wrapperPath, "utf-8").includes(standaloneDir);
|
|
656
|
+
} catch {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
__name(existingWrapperMatches, "existingWrapperMatches");
|
|
713
661
|
function ensurePathInShellRc(binDir) {
|
|
714
|
-
|
|
662
|
+
assertSafeForSingleQuotedShellPath(binDir, "binDir");
|
|
715
663
|
const shell = process.env["SHELL"] || "";
|
|
716
664
|
let rcFile = null;
|
|
717
665
|
const home = process.env["HOME"] || os.homedir();
|
|
718
666
|
if (shell.endsWith("/zsh")) {
|
|
719
|
-
rcFile =
|
|
667
|
+
rcFile = path.join(home, ".zshrc");
|
|
720
668
|
} else if (shell.endsWith("/bash")) {
|
|
721
|
-
const bashrc =
|
|
722
|
-
const profile =
|
|
723
|
-
if (
|
|
724
|
-
rcFile =
|
|
669
|
+
const bashrc = path.join(home, ".bashrc");
|
|
670
|
+
const profile = path.join(home, ".bash_profile");
|
|
671
|
+
if (fs.existsSync(bashrc)) {
|
|
672
|
+
rcFile = bashrc;
|
|
673
|
+
} else if (fs.existsSync(profile)) {
|
|
674
|
+
rcFile = profile;
|
|
725
675
|
} else {
|
|
726
676
|
rcFile = bashrc;
|
|
727
677
|
}
|
|
728
678
|
} else if (shell.endsWith("/fish")) {
|
|
729
|
-
rcFile =
|
|
679
|
+
rcFile = path.join(home, ".config", "fish", "config.fish");
|
|
730
680
|
}
|
|
731
|
-
if (!rcFile) return;
|
|
681
|
+
if (!rcFile) return { blockAdded: false };
|
|
732
682
|
try {
|
|
733
|
-
const content =
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
683
|
+
const content = fs.existsSync(rcFile) ? fs.readFileSync(rcFile, "utf-8") : "";
|
|
684
|
+
const beginMarker = "# Qwen Code PATH block begin";
|
|
685
|
+
const endMarker = "# Qwen Code PATH block end";
|
|
686
|
+
const legacyMarker = "# Added by Qwen Code standalone installer";
|
|
687
|
+
if (content.includes(beginMarker) && content.includes(endMarker)) {
|
|
688
|
+
return { rcFile, blockAdded: false };
|
|
689
|
+
}
|
|
690
|
+
if (content.includes(legacyMarker)) return { rcFile, blockAdded: false };
|
|
691
|
+
const exportLine = shell.endsWith("/fish") ? `set -gx PATH ${shellQuoteForFish(binDir)} $PATH` : `export PATH=${shellQuoteForSh(binDir)}:$PATH`;
|
|
692
|
+
const block = `
|
|
693
|
+
${beginMarker}
|
|
694
|
+
${exportLine}
|
|
695
|
+
${endMarker}
|
|
742
696
|
`;
|
|
743
|
-
|
|
744
|
-
|
|
697
|
+
fs.mkdirSync(path.dirname(rcFile), { recursive: true });
|
|
698
|
+
fs.appendFileSync(rcFile, block);
|
|
699
|
+
debugLogger.info(`Added ${binDir} to ${rcFile}`);
|
|
700
|
+
return { rcFile, blockAdded: true };
|
|
745
701
|
} catch (err) {
|
|
746
|
-
|
|
702
|
+
debugLogger.debug("Failed to update shell rc:", err);
|
|
703
|
+
return {
|
|
704
|
+
rcFile,
|
|
705
|
+
blockAdded: false,
|
|
706
|
+
error: err instanceof Error ? err.message : String(err)
|
|
707
|
+
};
|
|
747
708
|
}
|
|
748
709
|
}
|
|
749
710
|
__name(ensurePathInShellRc, "ensurePathInShellRc");
|
|
711
|
+
function surfaceBinWrapperWarnings(artifacts) {
|
|
712
|
+
if (!artifacts) return;
|
|
713
|
+
if (artifacts.wrapperNeedsAttention && artifacts.wrapperPath) {
|
|
714
|
+
const message = `Update completed, but the existing wrapper at ${artifacts.wrapperPath} does not point to this standalone installation.`;
|
|
715
|
+
debugLogger.warn(message);
|
|
716
|
+
updateEventEmitter.emit("update-info", { message });
|
|
717
|
+
}
|
|
718
|
+
if (artifacts.shellPathUpdate?.error && artifacts.shellPathUpdate.rcFile) {
|
|
719
|
+
const message = `Update completed, but ${artifacts.shellPathUpdate.rcFile} could not be updated. Add ~/.local/bin to PATH manually.`;
|
|
720
|
+
debugLogger.warn(message);
|
|
721
|
+
updateEventEmitter.emit("update-info", { message });
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
__name(surfaceBinWrapperWarnings, "surfaceBinWrapperWarnings");
|
|
725
|
+
function cleanupShellPathBlock(rcFile) {
|
|
726
|
+
try {
|
|
727
|
+
if (!fs.existsSync(rcFile)) return;
|
|
728
|
+
const content = fs.readFileSync(rcFile, "utf-8");
|
|
729
|
+
const blockPattern = /\n?# Qwen Code PATH block begin\n(?:.|\n)*?\n# Qwen Code PATH block end\n?/;
|
|
730
|
+
const nextContent = content.replace(blockPattern, "");
|
|
731
|
+
if (nextContent !== content) {
|
|
732
|
+
fs.writeFileSync(rcFile, nextContent);
|
|
733
|
+
}
|
|
734
|
+
} catch (err) {
|
|
735
|
+
debugLogger.debug("Failed to roll back shell rc PATH block:", err);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
__name(cleanupShellPathBlock, "cleanupShellPathBlock");
|
|
739
|
+
function cleanupFirstTimeMigrationArtifacts(artifacts) {
|
|
740
|
+
if (!artifacts) return;
|
|
741
|
+
if (artifacts.wrapperCreated && artifacts.wrapperPath) {
|
|
742
|
+
try {
|
|
743
|
+
fs.unlinkSync(artifacts.wrapperPath);
|
|
744
|
+
} catch (err) {
|
|
745
|
+
debugLogger.debug("Failed to roll back bin wrapper:", err);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (artifacts.shellPathUpdate?.blockAdded && artifacts.shellPathUpdate.rcFile) {
|
|
749
|
+
cleanupShellPathBlock(artifacts.shellPathUpdate.rcFile);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
__name(cleanupFirstTimeMigrationArtifacts, "cleanupFirstTimeMigrationArtifacts");
|
|
750
753
|
function detectTarget() {
|
|
751
754
|
const platform2 = os.platform();
|
|
752
755
|
const arch2 = os.arch();
|
|
@@ -765,12 +768,12 @@ async function performStandaloneUpdate(standaloneDir, newVersion) {
|
|
|
765
768
|
const versionPath = normalizeVersion(newVersion);
|
|
766
769
|
let target;
|
|
767
770
|
let isFirstTimeMigration = false;
|
|
768
|
-
const manifestPath =
|
|
769
|
-
if (
|
|
770
|
-
const manifestRaw =
|
|
771
|
+
const manifestPath = path.join(standaloneDir, "manifest.json");
|
|
772
|
+
if (fs.existsSync(manifestPath)) {
|
|
773
|
+
const manifestRaw = fs.readFileSync(manifestPath, "utf-8");
|
|
771
774
|
const manifest = JSON.parse(manifestRaw);
|
|
772
775
|
target = manifest.target ?? detectTarget();
|
|
773
|
-
} else if (
|
|
776
|
+
} else if (fs.existsSync(standaloneDir)) {
|
|
774
777
|
throw new Error(
|
|
775
778
|
`${standaloneDir} exists but is not a Qwen Code standalone install. Remove it manually to proceed.`
|
|
776
779
|
);
|
|
@@ -780,58 +783,67 @@ async function performStandaloneUpdate(standaloneDir, newVersion) {
|
|
|
780
783
|
}
|
|
781
784
|
validateTarget(target);
|
|
782
785
|
const filename = archiveFilename(target);
|
|
783
|
-
const parentDir =
|
|
784
|
-
|
|
785
|
-
const lockPath =
|
|
786
|
-
if (!acquireLock(lockPath)) {
|
|
786
|
+
const parentDir = path.dirname(standaloneDir);
|
|
787
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
788
|
+
const lockPath = path.join(parentDir, ".qwen-update.lock");
|
|
789
|
+
if (!acquireLock(lockPath, standaloneDir)) {
|
|
787
790
|
throw new Error("Another update is already in progress");
|
|
788
791
|
}
|
|
789
792
|
if (isFirstTimeMigration) {
|
|
790
|
-
|
|
793
|
+
try {
|
|
794
|
+
fs.mkdirSync(standaloneDir, { recursive: true });
|
|
795
|
+
} catch (err) {
|
|
796
|
+
releaseLock(lockPath);
|
|
797
|
+
throw err;
|
|
798
|
+
}
|
|
791
799
|
}
|
|
792
|
-
const tempDir =
|
|
800
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "qwen-code-update-"));
|
|
793
801
|
let extractDir;
|
|
794
802
|
let updateResult;
|
|
803
|
+
let migrationArtifacts;
|
|
795
804
|
try {
|
|
796
|
-
extractDir =
|
|
805
|
+
extractDir = fs.mkdtempSync(path.join(parentDir, ".qwen-code-update-"));
|
|
797
806
|
} catch (err) {
|
|
798
|
-
|
|
807
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
799
808
|
releaseLock(lockPath);
|
|
800
809
|
throw err;
|
|
801
810
|
}
|
|
802
811
|
try {
|
|
803
|
-
const archivePath =
|
|
804
|
-
|
|
812
|
+
const archivePath = path.join(tempDir, filename);
|
|
813
|
+
debugLogger.info(`Downloading ${filename} (${versionPath})...`);
|
|
814
|
+
updateEventEmitter.emit("update-info", {
|
|
815
|
+
message: t("Downloading update...")
|
|
816
|
+
});
|
|
805
817
|
const archiveHash = await downloadToFile(
|
|
806
818
|
versionPath,
|
|
807
819
|
filename,
|
|
808
820
|
archivePath
|
|
809
821
|
);
|
|
810
|
-
|
|
822
|
+
debugLogger.info("Verifying checksum...");
|
|
811
823
|
await verifyChecksum(archiveHash, filename, versionPath);
|
|
812
|
-
|
|
824
|
+
debugLogger.info("Extracting archive...");
|
|
813
825
|
await extractArchive(archivePath, extractDir, target);
|
|
814
|
-
const newInstallDir =
|
|
815
|
-
if (!
|
|
826
|
+
const newInstallDir = path.join(extractDir, "qwen-code");
|
|
827
|
+
if (!fs.existsSync(path.join(newInstallDir, "manifest.json"))) {
|
|
816
828
|
throw new Error(
|
|
817
829
|
"Extracted archive does not contain expected qwen-code directory"
|
|
818
830
|
);
|
|
819
831
|
}
|
|
820
|
-
|
|
832
|
+
debugLogger.info("Running smoke test...");
|
|
821
833
|
await smokeTest(newInstallDir, target);
|
|
822
|
-
|
|
834
|
+
debugLogger.info("Replacing installation...");
|
|
823
835
|
updateResult = atomicReplace(standaloneDir, newInstallDir, lockPath);
|
|
824
836
|
const oldDir = `${standaloneDir}.old`;
|
|
825
|
-
if (
|
|
837
|
+
if (fs.existsSync(oldDir)) {
|
|
826
838
|
if (isFirstTimeMigration) {
|
|
827
|
-
|
|
839
|
+
fs.rmSync(oldDir, { recursive: true, force: true });
|
|
828
840
|
} else {
|
|
829
841
|
try {
|
|
830
|
-
const oldManifestPath =
|
|
842
|
+
const oldManifestPath = path.join(oldDir, "manifest.json");
|
|
831
843
|
let oldVersion = "unknown";
|
|
832
|
-
if (
|
|
844
|
+
if (fs.existsSync(oldManifestPath)) {
|
|
833
845
|
const oldManifest = JSON.parse(
|
|
834
|
-
|
|
846
|
+
fs.readFileSync(oldManifestPath, "utf-8")
|
|
835
847
|
);
|
|
836
848
|
oldVersion = oldManifest.version || "unknown";
|
|
837
849
|
}
|
|
@@ -841,43 +853,61 @@ async function performStandaloneUpdate(standaloneDir, newVersion) {
|
|
|
841
853
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
842
854
|
reason: "auto-update"
|
|
843
855
|
};
|
|
844
|
-
|
|
845
|
-
|
|
856
|
+
fs.writeFileSync(
|
|
857
|
+
path.join(oldDir, ".qwen-rollback-info.json"),
|
|
846
858
|
JSON.stringify(rollbackInfo, null, 2)
|
|
847
859
|
);
|
|
848
860
|
} catch {
|
|
849
861
|
}
|
|
850
862
|
}
|
|
851
863
|
}
|
|
852
|
-
|
|
853
|
-
|
|
864
|
+
try {
|
|
865
|
+
migrationArtifacts = ensureBinWrapper(standaloneDir, target);
|
|
866
|
+
surfaceBinWrapperWarnings(migrationArtifacts);
|
|
867
|
+
} catch (wrapperErr) {
|
|
868
|
+
debugLogger.warn("Failed to refresh bin wrapper:", wrapperErr);
|
|
869
|
+
updateEventEmitter.emit("update-info", {
|
|
870
|
+
message: isFirstTimeMigration ? "Update installed, but the PATH wrapper could not be created. Add the standalone bin directory to your PATH manually, or re-run the update." : "Update completed, but the PATH wrapper could not be refreshed. The existing installation remains usable."
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
debugLogger.info("Standalone update complete.");
|
|
854
874
|
return updateResult;
|
|
855
875
|
} catch (err) {
|
|
856
876
|
const pendingDir = `${standaloneDir}.new`;
|
|
857
|
-
if (
|
|
858
|
-
|
|
877
|
+
if (updateResult !== "deferred" && fs.existsSync(pendingDir)) {
|
|
878
|
+
fs.rmSync(pendingDir, { recursive: true, force: true });
|
|
859
879
|
}
|
|
860
880
|
cleanupEmptyStandaloneDir(standaloneDir);
|
|
881
|
+
if (isFirstTimeMigration) {
|
|
882
|
+
cleanupFirstTimeMigrationArtifacts(migrationArtifacts);
|
|
883
|
+
}
|
|
861
884
|
throw err;
|
|
862
885
|
} finally {
|
|
863
886
|
if (updateResult !== "deferred") {
|
|
864
887
|
releaseLock(lockPath);
|
|
888
|
+
const deferredMarker = `${standaloneDir}.deferred`;
|
|
889
|
+
if (fs.existsSync(deferredMarker)) {
|
|
890
|
+
try {
|
|
891
|
+
fs.unlinkSync(deferredMarker);
|
|
892
|
+
} catch {
|
|
893
|
+
}
|
|
894
|
+
}
|
|
865
895
|
}
|
|
866
896
|
try {
|
|
867
|
-
|
|
897
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
868
898
|
} catch {
|
|
869
899
|
}
|
|
870
900
|
try {
|
|
871
|
-
|
|
901
|
+
fs.rmSync(extractDir, { recursive: true, force: true });
|
|
872
902
|
} catch {
|
|
873
903
|
}
|
|
874
904
|
}
|
|
875
905
|
}
|
|
876
906
|
__name(performStandaloneUpdate, "performStandaloneUpdate");
|
|
877
907
|
function rollbackStandaloneUpdate(standaloneDir) {
|
|
878
|
-
const lockPath =
|
|
908
|
+
const lockPath = path.join(path.dirname(standaloneDir), ".qwen-update.lock");
|
|
879
909
|
try {
|
|
880
|
-
const pidStr =
|
|
910
|
+
const pidStr = fs.readFileSync(lockPath, "utf-8").trim();
|
|
881
911
|
const pid = parseInt(pidStr, 10);
|
|
882
912
|
if (!Number.isNaN(pid) && isProcessAlive(pid)) {
|
|
883
913
|
return {
|
|
@@ -889,12 +919,12 @@ function rollbackStandaloneUpdate(standaloneDir) {
|
|
|
889
919
|
} catch {
|
|
890
920
|
}
|
|
891
921
|
const oldDir = `${standaloneDir}.old`;
|
|
892
|
-
if (!
|
|
922
|
+
if (!fs.existsSync(oldDir)) {
|
|
893
923
|
return { ok: false, reason: "no-old", detail: `${oldDir} does not exist` };
|
|
894
924
|
}
|
|
895
|
-
const oldManifest =
|
|
896
|
-
if (!
|
|
897
|
-
|
|
925
|
+
const oldManifest = path.join(oldDir, "manifest.json");
|
|
926
|
+
if (!fs.existsSync(oldManifest)) {
|
|
927
|
+
debugLogger.error("Rollback failed: .old directory has no manifest.json");
|
|
898
928
|
return {
|
|
899
929
|
ok: false,
|
|
900
930
|
reason: "no-manifest",
|
|
@@ -903,23 +933,23 @@ function rollbackStandaloneUpdate(standaloneDir) {
|
|
|
903
933
|
}
|
|
904
934
|
const failedDir = `${standaloneDir}.failed`;
|
|
905
935
|
try {
|
|
906
|
-
if (
|
|
907
|
-
|
|
936
|
+
if (fs.existsSync(failedDir)) {
|
|
937
|
+
fs.rmSync(failedDir, { recursive: true, force: true });
|
|
908
938
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
939
|
+
fs.renameSync(standaloneDir, failedDir);
|
|
940
|
+
fs.renameSync(oldDir, standaloneDir);
|
|
941
|
+
debugLogger.info("Rollback successful.");
|
|
912
942
|
try {
|
|
913
|
-
|
|
943
|
+
fs.rmSync(failedDir, { recursive: true, force: true });
|
|
914
944
|
} catch {
|
|
915
|
-
|
|
945
|
+
debugLogger.debug(`Leftover .failed dir at ${failedDir}, safe to delete`);
|
|
916
946
|
}
|
|
917
947
|
return { ok: true };
|
|
918
948
|
} catch (err) {
|
|
919
|
-
|
|
920
|
-
if (!
|
|
949
|
+
debugLogger.error("Rollback failed:", err);
|
|
950
|
+
if (!fs.existsSync(standaloneDir) && fs.existsSync(failedDir)) {
|
|
921
951
|
try {
|
|
922
|
-
|
|
952
|
+
fs.renameSync(failedDir, standaloneDir);
|
|
923
953
|
return {
|
|
924
954
|
ok: false,
|
|
925
955
|
reason: "rename-failed",
|
|
@@ -938,7 +968,13 @@ function rollbackStandaloneUpdate(standaloneDir) {
|
|
|
938
968
|
__name(rollbackStandaloneUpdate, "rollbackStandaloneUpdate");
|
|
939
969
|
|
|
940
970
|
export {
|
|
941
|
-
|
|
971
|
+
isSafeTarLinkTarget,
|
|
972
|
+
isSafeTarEntry,
|
|
973
|
+
isSafeTarEntryPath,
|
|
974
|
+
acquireLock,
|
|
975
|
+
ensureBinWrapper,
|
|
976
|
+
ensurePathInShellRc,
|
|
977
|
+
cleanupFirstTimeMigrationArtifacts,
|
|
942
978
|
performStandaloneUpdate,
|
|
943
979
|
rollbackStandaloneUpdate
|
|
944
980
|
};
|