@qwen-code/qwen-code 0.21.7 → 0.21.8-nightly.20260810.55e20db328
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 +2 -0
- package/bundled/qc-helper/docs/configuration/settings.md +73 -59
- package/bundled/qc-helper/docs/extension/introduction.md +15 -1
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +40 -2
- package/bundled/qc-helper/docs/features/channels/feishu.md +13 -2
- package/bundled/qc-helper/docs/features/channels/github.md +13 -11
- package/bundled/qc-helper/docs/features/channels/gitlab.md +13 -11
- package/bundled/qc-helper/docs/features/channels/overview.md +49 -31
- package/bundled/qc-helper/docs/features/channels/plugins.md +2 -2
- package/bundled/qc-helper/docs/features/channels/qqbot.md +4 -2
- package/bundled/qc-helper/docs/features/channels/telegram.md +4 -2
- package/bundled/qc-helper/docs/features/channels/wecom.md +1 -1
- package/bundled/qc-helper/docs/features/code-review.md +4 -0
- package/bundled/qc-helper/docs/features/commands.md +1 -1
- package/bundled/qc-helper/docs/features/hooks.md +52 -0
- package/bundled/qc-helper/docs/integration-jetbrains.md +1 -0
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +10 -5
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +50 -36
- package/bundled/review/SKILL.md +32 -5
- package/chunks/{MaxSizedBox-ANWZBPTS.js → MaxSizedBox-A52T4GEU.js} +29 -25
- package/chunks/{StandaloneSessionPicker-XKS3VU3A.js → StandaloneSessionPicker-4J654SOB.js} +48 -44
- package/chunks/{acp-startup-profiler-ORIQ2CCQ.js → acp-startup-profiler-B5BYAMYQ.js} +2 -2
- package/chunks/{acpAgent-KUAZ3GCZ.js → acpAgent-65AM4AOR.js} +1833 -843
- package/chunks/{agent-T6PTGX5R.js → agent-SVQ7U7NJ.js} +28 -24
- package/chunks/{agent-headless-PR7YCB7S.js → agent-headless-XXGY2SQO.js} +28 -24
- package/chunks/{artifact-tool-U4VOZIK5.js → artifact-tool-N652YE4L.js} +1 -1
- package/chunks/{askUserQuestion-XOBQLPFA.js → askUserQuestion-ONW74PKJ.js} +1 -1
- package/chunks/{bridge-NU6YEEHK.js → bridge-Y32B5S3G.js} +34 -30
- package/chunks/{ca-NYKNH222.js → ca-ZLKAB4K3.js} +6 -0
- package/chunks/{channel-management-service-FSQ7SHYI.js → channel-management-service-PHELKOW2.js} +19 -10
- package/chunks/{channel-settings-store-35VQVUVV.js → channel-settings-store-OW43U6VB.js} +36 -32
- package/chunks/{channel-worker-group-JWQK224X.js → channel-worker-group-MSHT6CWR.js} +7 -7
- package/chunks/{channel-worker-manager-77E3OXRQ.js → channel-worker-manager-XXD3GDSK.js} +7 -7
- package/chunks/{channel-worker-supervisor-62YWUGP2.js → channel-worker-supervisor-IVSDIMI4.js} +4 -4
- package/chunks/{chunk-HYRDKNUY.js → chunk-2545EHZR.js} +1 -1
- package/chunks/{chunk-SPMY6CX6.js → chunk-2ASQDZSJ.js} +3 -3
- package/chunks/{chunk-CJXIIILK.js → chunk-2FRY5CRX.js} +1 -1
- package/chunks/{chunk-CNIID3TV.js → chunk-2UUMVNYT.js} +1 -1
- package/chunks/{chunk-KXSDEOFU.js → chunk-3KJQZEN3.js} +1 -1
- package/chunks/{chunk-22NBYCPD.js → chunk-3P2LV43B.js} +1 -1
- package/chunks/{chunk-Y7E5LNLO.js → chunk-47ZUMGGY.js} +2634 -2114
- package/chunks/{chunk-LA7YLSR6.js → chunk-4EOURKA4.js} +839 -153
- package/chunks/chunk-4JRM2BSM.js +48 -0
- package/chunks/{chunk-BGG4MBYD.js → chunk-4PYCZH2V.js} +4 -187
- package/chunks/{chunk-L4N6TIP7.js → chunk-4TRQPFDP.js} +4 -2
- package/chunks/{chunk-6XJMFJ4D.js → chunk-5WZL724W.js} +177 -120
- package/chunks/{chunk-23RZCH76.js → chunk-5ZTS3OQ3.js} +3 -3
- package/chunks/{chunk-VWOVHOTT.js → chunk-67EWJE77.js} +1 -1
- package/chunks/{chunk-3K7FH2KQ.js → chunk-67N6HB5H.js} +1310 -171
- package/chunks/{chunk-CXE7E23H.js → chunk-6Q5ABMTU.js} +45 -17
- package/chunks/{chunk-NG2R4N5O.js → chunk-6ZRFAKXK.js} +1 -1
- package/chunks/{chunk-RERATVSK.js → chunk-7XX5IBXL.js} +145 -10
- package/chunks/{chunk-S7CV4KO6.js → chunk-AKJQSWV4.js} +4 -4
- package/chunks/{chunk-5KH532V7.js → chunk-AUWN7BAG.js} +1 -1
- package/chunks/{chunk-DBOFL3LQ.js → chunk-BL65MO72.js} +10 -10
- package/chunks/{chunk-AKA24BGO.js → chunk-BT6GQIEJ.js} +1 -1
- package/chunks/{chunk-W7U4ESW2.js → chunk-CG3WBKJK.js} +1 -1
- package/chunks/{chunk-2M5N3DHY.js → chunk-CMOBWHWW.js} +1 -1
- package/chunks/chunk-COBO5EBO.js +135 -0
- package/chunks/chunk-CPG6P4GG.js +82 -0
- package/chunks/{chunk-3NB7TSE2.js → chunk-D2D7J3EW.js} +1 -1
- package/chunks/{chunk-NLREQJFK.js → chunk-DA4HRSBW.js} +15 -0
- package/chunks/{chunk-RNVQB725.js → chunk-DPMJLKUP.js} +2 -2
- package/chunks/{chunk-DIEFUBV6.js → chunk-DX3RGJMS.js} +218 -37
- package/chunks/{chunk-33ACCIIY.js → chunk-DZUO626D.js} +1 -1
- package/chunks/chunk-E2FPSSKP.js +244 -0
- package/chunks/{chunk-72LNFGUY.js → chunk-E2N554HK.js} +3 -3
- package/chunks/{chunk-6EOI4HOK.js → chunk-E2T7FLDU.js} +12 -17
- package/chunks/{chunk-EUQTXRKZ.js → chunk-EISUQQPS.js} +6 -6
- package/chunks/{chunk-H2UQ2M5Z.js → chunk-EUVOKP6Y.js} +96 -22
- package/chunks/{chunk-RMH5OWLD.js → chunk-F3II4BTZ.js} +1 -1
- package/chunks/{chunk-P3LEG54R.js → chunk-F6TUUA2U.js} +3 -3
- package/chunks/chunk-F6WFNA7U.js +22 -0
- package/chunks/{chunk-RZHU3ILK.js → chunk-FAD7OC7V.js} +4 -4
- package/chunks/{chunk-OMKQH5C5.js → chunk-FWWQIFDT.js} +6 -23
- package/chunks/{chunk-TLV2IMHR.js → chunk-FYB4GIDW.js} +3 -3
- package/chunks/{chunk-ZJ3VGYHK.js → chunk-GY24H6IA.js} +40 -22
- package/chunks/{chunk-P2AJ7FTI.js → chunk-H4JC7LZX.js} +1 -1
- package/chunks/{chunk-55LYDVPU.js → chunk-HDYQYYWB.js} +1 -1
- package/chunks/{chunk-PQBHU2IA.js → chunk-HKI3KHAO.js} +11 -11
- package/chunks/{chunk-Y4NGLFGJ.js → chunk-HUWENAHO.js} +1 -1
- package/chunks/{chunk-3ULCB3NE.js → chunk-HV76SFIA.js} +1 -1
- package/chunks/{chunk-CSZEXZBE.js → chunk-HWXGX534.js} +3 -3
- package/chunks/{chunk-E33LOKRA.js → chunk-I5VM3SKY.js} +22 -5
- package/chunks/{chunk-LZC3B5N2.js → chunk-IA7TGCN2.js} +2 -2
- package/chunks/{chunk-RGSBTHSU.js → chunk-KMS57JDD.js} +137 -7
- package/chunks/{chunk-VOARQPTA.js → chunk-KP25NJNM.js} +65 -21
- package/chunks/{chunk-6M26GBKX.js → chunk-L2AFWWJE.js} +42 -3
- package/chunks/{chunk-ZXU5UHMI.js → chunk-LHEC5V6G.js} +2 -2
- package/chunks/{chunk-J26HHFI5.js → chunk-LP2QGNSP.js} +32 -2
- package/chunks/{chunk-R574ATRM.js → chunk-M2PNLYGY.js} +41 -0
- package/chunks/{chunk-MKVZE4ZJ.js → chunk-MFDYOYZZ.js} +3 -2
- package/chunks/{chunk-ALGGS7UH.js → chunk-NPQ5ZKRP.js} +82 -1
- package/chunks/{chunk-YHEEE624.js → chunk-NV3F44FL.js} +7 -3
- package/chunks/{chunk-6GONZVLS.js → chunk-NZMXUSKS.js} +1 -1
- package/chunks/{chunk-HQB2KUAN.js → chunk-O277O7U6.js} +1 -1
- package/chunks/{chunk-Y4EWSQF7.js → chunk-OBP6QWD5.js} +2 -2
- package/chunks/{chunk-CYR3HI5X.js → chunk-OQTXYMKW.js} +2 -2
- package/chunks/{chunk-TYKC75AX.js → chunk-OR6R3IUW.js} +2 -2
- package/chunks/{chunk-TRLYP7OF.js → chunk-OSVH4SMN.js} +16 -141
- package/chunks/{chunk-FPM27XN4.js → chunk-OW2BWT2P.js} +4 -4
- package/chunks/{chunk-TDXGKHDN.js → chunk-P5ULXPK5.js} +2 -2
- package/chunks/{chunk-24ER7UV4.js → chunk-PBRVUF5B.js} +1 -1
- package/chunks/{chunk-LKRMNRSN.js → chunk-PDPFQ2FO.js} +2 -0
- package/chunks/{chunk-2VSTGY6M.js → chunk-PJRW65JO.js} +1 -1
- package/chunks/{chunk-6HVUFDS2.js → chunk-PNVPFARW.js} +22 -13
- package/chunks/{chunk-IC4Z6LX6.js → chunk-PYQADEFD.js} +5 -0
- package/chunks/chunk-R4ZA6GBK.js +208 -0
- package/chunks/{chunk-KR4ZSC7K.js → chunk-RMPLEWF3.js} +3 -3
- package/chunks/{chunk-EORNAQDT.js → chunk-RQ6U2JJQ.js} +1 -1
- package/chunks/{chunk-AE77C5ZU.js → chunk-RYQMJCUO.js} +1 -1
- package/chunks/{chunk-6UWFTUQL.js → chunk-S5CULOHB.js} +75 -31
- package/chunks/{chunk-7UFKAV7Y.js → chunk-S6HYI3MF.js} +2 -2
- package/chunks/chunk-SAH4BD2J.js +92 -0
- package/chunks/chunk-SR7RZ4MS.js +202 -0
- package/chunks/{chunk-QETYKPMG.js → chunk-T2O6NIOY.js} +1 -1
- package/chunks/chunk-TQOF5KBL.js +71 -0
- package/chunks/{chunk-OHJLEW5J.js → chunk-TWFFY5BP.js} +4 -4
- package/chunks/{chunk-SCI7K3GM.js → chunk-TXO5BMR2.js} +19 -10
- package/chunks/{chunk-YJQCUTT2.js → chunk-UAB6J2IE.js} +4 -4
- package/chunks/{chunk-OFI7IGST.js → chunk-UGUKH3SU.js} +10 -10
- package/chunks/{chunk-SHZYHGQH.js → chunk-V2226RFW.js} +1 -1
- package/chunks/{chunk-KKJJB5X6.js → chunk-V47QNK5W.js} +1526 -833
- package/chunks/{chunk-W4B7UBUS.js → chunk-VHXPSL57.js} +6 -6
- package/chunks/{chunk-WUC6ZFXO.js → chunk-VKJ4KTPJ.js} +1 -1
- package/chunks/{chunk-MAJS7AT4.js → chunk-VNNWAZSI.js} +2 -2
- package/chunks/{chunk-BVWVWGLE.js → chunk-WAUGQKUU.js} +4 -64
- package/chunks/{chunk-OH2VKQXH.js → chunk-WH6QMLUW.js} +37 -30
- package/chunks/{chunk-PJOBIWUG.js → chunk-WQYWK4DG.js} +1 -1
- package/chunks/{chunk-LEMXGVEP.js → chunk-YFRFZCIP.js} +3 -3
- package/chunks/{chunk-2U3WZGZG.js → chunk-YGT2AUJ7.js} +103 -135
- package/chunks/{chunk-6XU3PH66.js → chunk-YR7ZQ4RD.js} +22 -69
- package/chunks/{chunk-OA4JVLSA.js → chunk-Z7VOMGDC.js} +22 -1
- package/chunks/{chunk-RUL4S3K3.js → chunk-ZCJBCKL5.js} +175 -60
- package/chunks/{chunk-GSS34377.js → chunk-ZI5IH2HP.js} +2 -2
- package/chunks/{chunk-CB2464BK.js → chunk-ZIKTCMQF.js} +117 -10
- package/chunks/chunk-ZLBIFIMV.js +1099 -0
- package/chunks/{chunk-D3UEZIQH.js → chunk-ZSNBQXMZ.js} +48 -55
- package/chunks/{chunk-FZBZSYKU.js → chunk-ZV7LTLFE.js} +1 -1
- package/chunks/{computer-use-KEAPATUY.js → computer-use-SLN7DV2E.js} +28 -24
- package/chunks/{config-utils-K7SCOWHD.js → config-utils-ULCSRMWD.js} +4 -4
- package/chunks/{contextCommand-ZJA6A5K5.js → contextCommand-EHFYX6FW.js} +30 -26
- package/chunks/{core-runtime-QMJPWHCI.js → core-runtime-FBSP5IIG.js} +33 -29
- package/chunks/{create-sub-session-E4PBYXV5.js → create-sub-session-QIDZUOPU.js} +1 -1
- package/chunks/{create-sub-session-DJE6XICH.js → create-sub-session-WC7YGVSL.js} +29 -25
- package/chunks/{cron-create-GRBWYMIJ.js → cron-create-VONA5JYY.js} +1 -1
- package/chunks/{cron-delete-4CMKBR2M.js → cron-delete-5JXSP2MI.js} +1 -1
- package/chunks/{cron-list-W7K4ASOA.js → cron-list-KE4F2CIR.js} +1 -1
- package/chunks/{daemon-SCTQMM7Z.js → daemon-VSX3FHTY.js} +119 -4
- package/chunks/{daemon-status-provider-FSWDPE2G.js → daemon-status-provider-WW2AD2T7.js} +39 -35
- package/chunks/{daemon-trust-policy-P5L5VFAY.js → daemon-trust-policy-E4MAYWPI.js} +35 -31
- package/chunks/{daemon-trust-policy-monitor-73JYN6ET.js → daemon-trust-policy-monitor-XVIDV6T4.js} +35 -31
- package/chunks/{de-VL76CPLV.js → de-LIW4XVLN.js} +5 -0
- package/chunks/{deferred-core-runtime-BWRCCFTE.js → deferred-core-runtime-5SVUC6UC.js} +28 -24
- package/chunks/{display-image-O2XFPQTC.js → display-image-NQRSIBXM.js} +2 -2
- package/chunks/{dist-HVBMEYWK.js → dist-3NTTUAHT.js} +1 -1
- package/chunks/{dist-7JGAAQSC.js → dist-6BMOAE3Z.js} +2 -2
- package/chunks/{dist-3BMEUGTG.js → dist-B2CGTW6T.js} +1 -1
- package/chunks/{dist-C5U4LJKW.js → dist-EWW3J4HQ.js} +5 -4
- package/chunks/{dist-K4WWQBHS.js → dist-EZE3V3Q7.js} +55 -15
- package/chunks/{dist-DPPHJAVL.js → dist-J47AXBZC.js} +918 -142
- package/chunks/{dist-SFQ34F4M.js → dist-OTUO3AS2.js} +8 -1091
- package/chunks/{dist-KS4O2NKE.js → dist-Z3CS4OVP.js} +14 -8
- package/chunks/{earlyInputCapture-L5ST23A6.js → earlyInputCapture-72FYHYRD.js} +28 -24
- package/chunks/{edit-LHHRFNFK.js → edit-SWVVWHXW.js} +28 -24
- package/chunks/{en-IRJ2WN5T.js → en-SY5GTIGX.js} +6 -0
- package/chunks/{enter-worktree-6NXCRZPF.js → enter-worktree-2HF6WQEO.js} +28 -24
- package/chunks/{enterPlanMode-ZVQT4U7D.js → enterPlanMode-OW6S7L4P.js} +28 -24
- package/chunks/{environment-GJ2HWJOS.js → environment-LRTBTDXH.js} +32 -28
- package/chunks/{errors-6RLH3XXC.js → errors-4CO2DME6.js} +30 -26
- package/chunks/{exit-worktree-I2YLUHHY.js → exit-worktree-GHJEIRGL.js} +28 -24
- package/chunks/{exitPlanMode-7CCWKO7I.js → exitPlanMode-JVP4FNNK.js} +28 -24
- package/chunks/{fast-path-DVFD4HQD.js → fast-path-HCCY7GR2.js} +24 -3
- package/chunks/{fast-path-settings-WQJU2LAT.js → fast-path-settings-MN5QQQET.js} +6 -3
- package/chunks/{fr-GK3HQYVB.js → fr-RQFO7U4P.js} +5 -0
- package/chunks/{gemini-7FWGOYD4.js → gemini-V3YVRKXU.js} +85 -72
- package/chunks/{geminiContentGenerator-V2WVLIXU.js → geminiContentGenerator-LVPMQUWX.js} +1 -1
- package/chunks/{glob-3N6GGI75.js → glob-7HRXHYDR.js} +28 -24
- package/chunks/{goal-tools-APOW6UXL.js → goal-tools-PXWN5VK3.js} +4 -2
- package/chunks/{grep-V43ILZVX.js → grep-BITQUON5.js} +28 -24
- package/chunks/{handleAutoUpdate-A5WFVWIA.js → handleAutoUpdate-DKFY454S.js} +32 -28
- package/chunks/{i18n-PLVQ4FBZ.js → i18n-53BQIQSH.js} +29 -25
- package/chunks/{image-gen-7C6IK6DC.js → image-gen-H62FLDFB.js} +7 -5
- package/chunks/{initializer-CVAIKZYL.js → initializer-Q7NUQRSU.js} +35 -31
- package/chunks/{installationInfo-J6QDHNTK.js → installationInfo-BWFHT7WU.js} +29 -25
- package/chunks/{ja-3FA46IKD.js → ja-KOZKHJHZ.js} +5 -0
- package/chunks/{list-ZZ4OUUWV.js → list-OWQKR6JK.js} +38 -34
- package/chunks/{list-agents-KFFIIS2G.js → list-agents-Z4WABFDZ.js} +1 -1
- package/chunks/{loadedSettingsAdapter-QRYRJSWL.js → loadedSettingsAdapter-HNPKQMFA.js} +35 -31
- package/chunks/{loggingContentGenerator-OJCO75HM.js → loggingContentGenerator-A5I3VQUC.js} +10 -8
- package/chunks/{loop-wakeup-TLMJPMMP.js → loop-wakeup-UZ5RL5Y2.js} +2 -2
- package/chunks/{ls-UVVE2XGE.js → ls-TVHDGIES.js} +1 -1
- package/chunks/{lsp-QMEA2VLB.js → lsp-CVN6OQPI.js} +1 -1
- package/chunks/main-PXAUXNF2.js +8 -0
- package/chunks/{managed-npm-update-PCOSCP2N.js → managed-npm-update-CUUJGUTV.js} +29 -25
- package/chunks/{mcp-M3WKKWKY.js → mcp-GJSC7ZPO.js} +35 -31
- package/chunks/{monitor-GN24FH6C.js → monitor-TZ2II7JM.js} +38 -30
- package/chunks/{nonInteractiveCli-KPTU3VSQ.js → nonInteractiveCli-22RS4EVH.js} +72 -66
- package/chunks/{notebook-edit-4YM65BBO.js → notebook-edit-YZC3YPY2.js} +36 -24
- package/chunks/{openaiContentGenerator-EDQT6GTV.js → openaiContentGenerator-OIGO5XNF.js} +21 -11
- package/chunks/{pidfile-JOIIRN2C.js → pidfile-QJQ65RJ2.js} +28 -24
- package/chunks/{process-registry-2CHQBXH5.js → process-registry-PMJOA5CO.js} +15 -0
- package/chunks/{processUtils-5SV4MX3Q.js → processUtils-V5VSDIKS.js} +2 -2
- package/chunks/{pt-3AOBKPIJ.js → pt-U6AOCTMF.js} +5 -0
- package/chunks/{qwenContentGenerator-ODRJSUGR.js → qwenContentGenerator-HXM25BGB.js} +35 -30
- package/chunks/{qwenOAuth2-NESCMZ47.js → qwenOAuth2-7MTMS2Z5.js} +7 -5
- package/chunks/{read-file-HPSODLPK.js → read-file-PMGXB3ZB.js} +8 -6
- package/chunks/{read-mcp-resource-2TNSJTC3.js → read-mcp-resource-PZ4ZF6YL.js} +1 -1
- package/chunks/{record-artifact-RAON52FC.js → record-artifact-P4HFMS7X.js} +2 -2
- package/chunks/{resumeHistoryUtils-TXCOFFMQ.js → resumeHistoryUtils-YUTPLHUH.js} +33 -29
- package/chunks/{ripGrep-ZKQGTQAO.js → ripGrep-XUS66YIV.js} +28 -24
- package/chunks/{ru-VJRAMC4W.js → ru-CMX4UMYP.js} +5 -0
- package/chunks/{run-qwen-serve-ZPKPKECF.js → run-qwen-serve-4NVSU75L.js} +261 -62
- package/chunks/{runtime-2FLNNM36.js → runtime-QLRVP6HM.js} +40 -36
- package/chunks/{scheduler-365PJHNR.js → scheduler-PBB2NSOP.js} +28 -24
- package/chunks/{sdk-exporters-http-KHAB5JSD.js → sdk-exporters-http-XVTZQRCE.js} +2 -2
- package/chunks/{sdk-impl-KD7FSTC3.js → sdk-impl-7W7AKCS4.js} +7 -3
- package/chunks/{send-message-ZM7MRUGP.js → send-message-CAMSLG2L.js} +4 -3
- package/chunks/{serve-QD2RNLKJ.js → serve-BWKTRX72.js} +37 -31
- package/chunks/{server-XLJVLTYM.js → server-E7CH7WPK.js} +1437 -593
- package/chunks/{session-3VTUHH4Q.js → session-QEKSJ6YU.js} +166 -105
- package/chunks/{settings-KULVPCQC.js → settings-BRAOSJIM.js} +34 -30
- package/chunks/{shell-3SWW22MH.js → shell-OF3CK4AT.js} +28 -24
- package/chunks/{skill-KDHWYS7W.js → skill-HLH2NO2H.js} +9 -7
- package/chunks/{skill-settings-NMY4JEJC.js → skill-settings-DRPU7YI5.js} +34 -30
- package/chunks/{spawnChannel-ZKS4Q5OU.js → spawnChannel-4KO7YTFM.js} +31 -27
- package/chunks/{standalone-update-7CXPGAQ4.js → standalone-update-DJN2R3YW.js} +30 -26
- package/chunks/{startInteractiveUI-2QQLEKM6.js → startInteractiveUI-O3WQQ2WC.js} +384 -173
- package/chunks/{syntheticOutput-ZLCUTKO2.js → syntheticOutput-PEBJQYJV.js} +2 -2
- package/chunks/{task-create-CQP5UEA3.js → task-create-5NWCQSJF.js} +5 -4
- package/chunks/{task-list-XLEZOJXP.js → task-list-53265TRZ.js} +1 -1
- package/chunks/{task-stop-7ZQM5CFF.js → task-stop-FPCOIRYX.js} +1 -1
- package/chunks/{task-update-JA75U2SN.js → task-update-5HN577LS.js} +5 -4
- package/chunks/{team-create-2WTNGAOX.js → team-create-2E4ACBJD.js} +28 -24
- package/chunks/{team-delete-MHY3UZGY.js → team-delete-MMQB4OSC.js} +1 -1
- package/chunks/{team-plan-approval-LZTYLEG4.js → team-plan-approval-LWIDXYOA.js} +28 -24
- package/chunks/{terminal-image-renderer-R5HHAFJN.js → terminal-image-renderer-PJM7663W.js} +30 -26
- package/chunks/{theme-manager-PAUCSJFF.js → theme-manager-FDQTM3RP.js} +28 -24
- package/chunks/{todoWrite-UPVOHYGD.js → todoWrite-JGV6VLOX.js} +1 -1
- package/chunks/{tool-search-2BFCGLI6.js → tool-search-TL5ZXBF4.js} +11 -8
- package/chunks/{total-session-admission-MK4SINFK.js → total-session-admission-LS6EY5KT.js} +37 -32
- package/chunks/{trustedFolders-TJ5S26N7.js → trustedFolders-5RWP5OB7.js} +32 -26
- package/chunks/{types-ML3TRJQ5.js → types-WYCFCEHR.js} +5 -3
- package/chunks/{update-relaunch-N7AYLARF.js → update-relaunch-HWQ4USKY.js} +5 -5
- package/chunks/{updateCheck-QRZ3DVT5.js → updateCheck-EZMBTEIR.js} +31 -27
- package/chunks/{useAutoAcceptIndicator-DBJ7Y5AF.js → useAutoAcceptIndicator-JDMI627A.js} +37 -33
- package/chunks/{validateNonInterActiveAuth-6ZQWUDS3.js → validateNonInterActiveAuth-RRUHC5RO.js} +67 -63
- package/chunks/{version-AJQGQWXC.js → version-XS4UTKUX.js} +1 -1
- package/chunks/{web-fetch-QWJYRXFL.js → web-fetch-2JV7H6OM.js} +14 -10
- package/chunks/{web-search-2AOXJGHU.js → web-search-RCTN2GAM.js} +10 -7
- package/chunks/{workflow-ERH3SJG2.js → workflow-6MKLKQ6R.js} +909 -273
- package/chunks/{workspace-providers-status-HZ474RA4.js → workspace-providers-status-YZ2IJ4DK.js} +38 -34
- package/chunks/{workspace-registration-store-6EUP4JXG.js → workspace-registration-store-IYN72LBS.js} +1 -1
- package/chunks/{workspace-registry-R4APRRNC.js → workspace-registry-7LFBZQLT.js} +37 -32
- package/chunks/{workspace-service-HFIFDMU7.js → workspace-service-2EHSPRJB.js} +45 -39
- package/chunks/{workspace-skills-status-HAHEIHGK.js → workspace-skills-status-5VJ2D5HN.js} +36 -32
- package/chunks/{workspace-trust-reconciler-65GTAGDK.js → workspace-trust-reconciler-X2LZ6XCI.js} +44 -39
- package/chunks/{write-file-B34CDELV.js → write-file-CJK6SCCF.js} +28 -24
- package/chunks/{zh-ARWDLDLR.js → zh-AGL2FVBI.js} +6 -0
- package/chunks/{zh-TW-Y4RGI3P7.js → zh-TW-KI66MHQY.js} +6 -0
- package/chunks/{zoom-image-HPRBZHSS.js → zoom-image-BVW4RFYW.js} +8 -6
- package/cli.js +13 -13
- package/locales/ca.js +10 -0
- package/locales/de.js +9 -0
- package/locales/en.js +10 -0
- package/locales/fr.js +9 -0
- package/locales/ja.js +9 -0
- package/locales/pt.js +9 -0
- package/locales/ru.js +9 -0
- package/locales/zh-TW.js +10 -0
- package/locales/zh.js +10 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-Ip-FFDJ0.js → arc-DDtoJrAW.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-CChqgwIb.js → architectureDiagram-3BPJPVTR-BAInIW4O.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BHN-Tfss.js → blockDiagram-GPEHLZMM-ChPDk7fP.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BhyjzDjN.js → c4Diagram-AAUBKEIU-Cd9BJuUy.js} +1 -1
- package/web-shell/assets/channel-0OQklTfP.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-BB9eyHrx.js → chunk-2J33WTMH-COQkLp56.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BeV7ce_J.js → chunk-4BX2VUAB-GUJshQ_l.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DO7kXDiV.js → chunk-55IACEB6-Boaa7c10.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-B27MPznD.js → chunk-727SXJPM-CcRXaly2.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DHIjqjD_.js → chunk-AQP2D5EJ-BY0OARHh.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-DabMqyN2.js → chunk-FMBD7UC4-DLFQfv0S.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-Dw7Nnnxc.js → chunk-ND2GUHAM-C_S0u-D2.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-DdaZew1Q.js → chunk-QZHKN3VN-DP9m64hw.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CZ4-apsu.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CZ4-apsu.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-CgBpCYH5.js → cose-bilkent-S5V4N54A-CGY6zGE1.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-BB4IU8G0.js → dagre-BM42HDAG-yB7whKNn.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BcUTHU37.js → diagram-2AECGRRQ-Bdlc59La.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-B6Lyihyv.js → diagram-5GNKFQAL-BUClP18L.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CRIJOjpG.js → diagram-KO2AKTUF-aZm08kjn.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DdNiwWWT.js → diagram-LMA3HP47-7DGwEkxC.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-Dz4b32Do.js → diagram-OG6HWLK6-CAGKayxx.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-D-8NGw77.js → erDiagram-TEJ5UH35-CptoHHQi.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-Dun26LyM.js → flowDiagram-I6XJVG4X-CNOH0s7Q.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-F10Hu1Gc.js → ganttDiagram-6RSMTGT7-CCQuCU3y.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Bf8Ez6-D.js → gitGraphDiagram-PVQCEYII-B7gv9f4E.js} +1 -1
- package/web-shell/assets/{index-BXqw-nGq.js → index-BoUPVvpf.js} +1 -1
- package/web-shell/assets/index-D1YQXYsB.css +5 -0
- package/web-shell/assets/index-J4N7zCmU.js +1768 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DVgTMLvj.js → infoDiagram-5YYISTIA-Bb3KYEbR.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-uT-KepvK.js → ishikawaDiagram-YF4QCWOH-DWEzbAGi.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Vg_XadQf.js → journeyDiagram-JHISSGLW-CmxwEqeb.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-Dyv1ESBE.js → kanban-definition-UN3LZRKU-Ci0gDD8O.js} +1 -1
- package/web-shell/assets/{linear-BMIepYX3.js → linear-BqxZqGhS.js} +1 -1
- package/web-shell/assets/{mermaid.core-zA8pJ9ag.js → mermaid.core-BDAFffHv.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BCW_BZ_5.js → mindmap-definition-RKZ34NQL-Btvx-xvS.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-DseNEGp2.js → pieDiagram-4H26LBE5-CKAg7yG7.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-6Z7wr1Fi.js → quadrantDiagram-W4KKPZXB-DIt8E1mC.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-CVOlCRPf.js → requirementDiagram-4Y6WPE33-BA7mQWQJ.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CGhgrUJZ.js → sankeyDiagram-5OEKKPKP-D0JppnVU.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-dlqmpLuQ.js → sequenceDiagram-3UESZ5HK-29DIQFjB.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-B9EW10Xb.js → stateDiagram-AJRCARHV-iiXMdK--.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CEGK3l80.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-BBRh0mgZ.js → timeline-definition-PNZ67QCA-CeF7ngSW.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-B8Gs-REP.js → vennDiagram-CIIHVFJN-Beilq8D6.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-D_y80Ur7.js → wardley-L42UT6IY-DOYjY4zO.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-D-CNfHJ-.js → wardleyDiagram-YWT4CUSO-Dtqp8o18.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-DQ5CvELo.js → xychartDiagram-2RQKCTM6-cdAc0Dfv.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-6PEXNQTX.js +0 -68
- package/chunks/chunk-IUFV6FYU.js +0 -81
- package/chunks/chunk-RXFQM6FQ.js +0 -42
- package/web-shell/assets/channel-Cu8qd6OB.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BI3KrXhq.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BI3KrXhq.js +0 -1
- package/web-shell/assets/index-QQlUCJGg.css +0 -5
- package/web-shell/assets/index-hcgjV7vS.js +0 -1768
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CJTZJJ5X.js +0 -1
- package/chunks/{anthropicContentGenerator-DTMVEL5M.js → anthropicContentGenerator-SSFE2753.js} +9 -9
- /package/chunks/{chunk-VXZBKKQR.js → chunk-NTTBXH7U.js} +0 -0
- /package/chunks/{chunk-GRC5HGPI.js → chunk-OIBUG24X.js} +0 -0
|
@@ -78,17 +78,17 @@ Local `gh` authentication requires an HTTPS `baseUrl` so the daemon host credent
|
|
|
78
78
|
|
|
79
79
|
## Configuration Options
|
|
80
80
|
|
|
81
|
-
| Option | Default | Description
|
|
82
|
-
| ------------------------- | ------------------------ |
|
|
83
|
-
| `token` | unset | Optional classic PAT with `notifications` scope; overrides local `gh` authentication
|
|
84
|
-
| `useLocalGh` | `false` | Explicitly reuse the daemon host's account-wide GitHub CLI authentication
|
|
85
|
-
| `pollInterval` | `60000` | Poll interval in ms
|
|
86
|
-
| `baseUrl` | `https://api.github.com` | API base URL (for GHE)
|
|
87
|
-
| `groupPolicy` | `"disabled"` | Must be `"open"` for notifications to flow
|
|
88
|
-
| `senderPolicy` | `"allowlist"` | Who can trigger the bot
|
|
89
|
-
| `groups.*.requireMention` | `true` | Require @mentions for ordinary comments; directed notification reasons still run
|
|
90
|
-
| `blockStreaming` | `"off"` | Always forced to `"off"`; intermediate model chunks aren't published; `"on"` is not supported
|
|
91
|
-
| `reasonFilter` | unset | Optional allowlist of GitHub notification reasons to process
|
|
81
|
+
| Option | Default | Description |
|
|
82
|
+
| ------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
83
|
+
| `token` | unset | Optional classic PAT with `notifications` scope; overrides local `gh` authentication |
|
|
84
|
+
| `useLocalGh` | `false` | Explicitly reuse the daemon host's account-wide GitHub CLI authentication |
|
|
85
|
+
| `pollInterval` | `60000` | Poll interval in ms |
|
|
86
|
+
| `baseUrl` | `https://api.github.com` | API base URL (for GHE) |
|
|
87
|
+
| `groupPolicy` | `"disabled"` | Must be `"open"`, `"allowlist"` with the repo (`owner/repo`) listed in `groups`, or `"pairing"` with the repo approved for notifications to flow |
|
|
88
|
+
| `senderPolicy` | `"allowlist"` | Who can trigger the bot |
|
|
89
|
+
| `groups.*.requireMention` | `true` | Require @mentions for ordinary comments; directed notification reasons still run |
|
|
90
|
+
| `blockStreaming` | `"off"` | Always forced to `"off"`; intermediate model chunks aren't published; `"on"` is not supported |
|
|
91
|
+
| `reasonFilter` | unset | Optional allowlist of GitHub notification reasons to process |
|
|
92
92
|
|
|
93
93
|
Use `reasonFilter` to drop noisy notification classes such as `ci_activity` or `state_change`. Do not use `reasonFilter: ["mention"]` as a replacement for `groups.*.requireMention`: GitHub's `mention` reason is sticky at the thread level, so real new @mentions can arrive later under `comment`, `subscribed`, `author`, or other reasons and would be skipped.
|
|
94
94
|
|
|
@@ -104,6 +104,8 @@ Always use `senderPolicy: "allowlist"` with explicit `allowedUsers` on public re
|
|
|
104
104
|
|
|
105
105
|
Allowlist and pairing entries follow the **username**, not the immutable account ID. If an allowlisted user renames their GitHub account, remove the stale entry — GitHub releases the old username for anyone else to claim, and the new holder would inherit the allowlist/pairing authorization.
|
|
106
106
|
|
|
107
|
+
Note that under `groupPolicy: "pairing"`, access is granted per repository: once a repository is approved, **any GitHub user** can drive the bot through that repository's issues and pull requests. All GitHub traffic is group traffic, so `senderPolicy` and `allowedUsers` do not gate members of an approved repository. Approvals are keyed by the repository full name (`owner/repo`), which changes on rename or transfer — revoke stale group approvals after any repository rename, transfer, or deletion.
|
|
108
|
+
|
|
107
109
|
## Mention Detection
|
|
108
110
|
|
|
109
111
|
The adapter detects mentions by scanning comment text and first-contact issue or PR bodies for `@bot-username` using a case-insensitive regex. It does not trust `reason: "mention"` alone because that value is sticky at the thread level. Other reasons select review, triage, followed-thread, or fallback prompts.
|
|
@@ -56,14 +56,14 @@ For self-hosted instances, set `baseUrl`:
|
|
|
56
56
|
|
|
57
57
|
## Configuration Options
|
|
58
58
|
|
|
59
|
-
| Option | Default | Description
|
|
60
|
-
| ------------------------ | ------------------------- |
|
|
61
|
-
| `token` | (required) | PAT with `read_api` + `api` scopes
|
|
62
|
-
| `pollInterval` | `60000` | Poll interval in ms
|
|
63
|
-
| `baseUrl` | `https://gitlab.com` | GitLab instance URL
|
|
64
|
-
| `action_prompt_template` | (required for processing) | Maps GitLab action names to metadata templates
|
|
65
|
-
| `groupPolicy` | `"disabled"` | Must be `"open"`,
|
|
66
|
-
| `senderPolicy` | `"allowlist"` | Who can trigger the bot
|
|
59
|
+
| Option | Default | Description |
|
|
60
|
+
| ------------------------ | ------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `token` | (required) | PAT with `read_api` + `api` scopes |
|
|
62
|
+
| `pollInterval` | `60000` | Poll interval in ms |
|
|
63
|
+
| `baseUrl` | `https://gitlab.com` | GitLab instance URL |
|
|
64
|
+
| `action_prompt_template` | (required for processing) | Maps GitLab action names to metadata templates |
|
|
65
|
+
| `groupPolicy` | `"disabled"` | Must be `"open"`, `"allowlist"` with the project listed, or `"pairing"` with the project approved |
|
|
66
|
+
| `senderPolicy` | `"allowlist"` | Who can trigger the bot |
|
|
67
67
|
|
|
68
68
|
## action_prompt_template
|
|
69
69
|
|
|
@@ -132,13 +132,15 @@ On a **public project**, setting `senderPolicy: "open"` allows **any GitLab user
|
|
|
132
132
|
|
|
133
133
|
Always use `senderPolicy: "allowlist"` with explicit `allowedUsers` on public projects.
|
|
134
134
|
|
|
135
|
+
Note that under `groupPolicy: "pairing"`, access is granted per project: once a project is approved, **any GitLab user** can drive the bot through that project's issues and merge requests. All GitLab traffic is group traffic, so `senderPolicy` and `allowedUsers` do not gate members of an approved project. Approvals are keyed by the project path (`owner/repo`), which changes on rename or transfer — revoke stale group approvals after any project rename, transfer, or deletion.
|
|
136
|
+
|
|
135
137
|
## Mention Detection
|
|
136
138
|
|
|
137
139
|
The adapter always sets `isMentioned = true` on dispatched envelopes, because GitLab has already determined the mention when creating the todo. The `action_prompt_template` config is the real event filter — only actions with a configured template are processed. The `@bot` mention is stripped from the message text before dispatch via `stripBotMention`.
|
|
138
140
|
|
|
139
|
-
### ⚠️ groupPolicy Must Be "open" or "
|
|
141
|
+
### ⚠️ groupPolicy Must Be "open", "allowlist", or "pairing"
|
|
140
142
|
|
|
141
|
-
`groupPolicy` must be set to `"open"`,
|
|
143
|
+
`groupPolicy` must be set to `"open"`, `"allowlist"` with the project explicitly listed, or `"pairing"` for todos to be processed. Under `"pairing"`, the first mention from an unapproved project creates a group pairing request; approve it once with `qwen channel pairing approve`, and todos from that project are dispatched from then on. The default value `"disabled"` drops all mentions: todos are marked done and the cursor advances, but no dispatch occurs. A rejection is logged (`preflight rejected reason=group_disabled`) but the todo is still consumed. If your bot is not responding to mentions, check that `groupPolicy` is not `"disabled"`.
|
|
142
144
|
|
|
143
145
|
## How It Works
|
|
144
146
|
|
|
@@ -151,7 +153,7 @@ The adapter uses GitLab's Todos API as the message source:
|
|
|
151
153
|
5. **Detect mention type** via `target_url` anchor:
|
|
152
154
|
- `#note_123` present → comment mention → text is `todo.body` (the comment)
|
|
153
155
|
- No anchor → description mention → text is the issue/MR description
|
|
154
|
-
6. **Dispatch** the envelope through `handleInbound` (requires `groupPolicy: "open"` or `"
|
|
156
|
+
6. **Dispatch** the envelope through `handleInbound` (requires `groupPolicy: "open"`, `"allowlist"` with the project listed, or `"pairing"` with the project approved)
|
|
155
157
|
7. **Advance cursor** and **mark todo done** (best-effort)
|
|
156
158
|
|
|
157
159
|
The cursor (`lastProcessedId`) advances regardless of dispatch success or failure. Failed dispatches post a ⚠️ error comment on the issue/MR and are not retried — the user can re-mention the bot to trigger a new todo.
|
|
@@ -50,30 +50,30 @@ Channels are configured under the `channels` key in `settings.json`. Each channe
|
|
|
50
50
|
|
|
51
51
|
### Options
|
|
52
52
|
|
|
53
|
-
| Option | Required | Description
|
|
54
|
-
| ------------------------ | ---------------- |
|
|
55
|
-
| `type` | Yes | Channel type: `telegram`, `weixin`, `qq`, `dingtalk`, `wecom`, `feishu`, `github`, or a custom type from an extension (see [Plugins](./plugins))
|
|
56
|
-
| `token` | Telegram | Bot token. Supports `$ENV_VAR` syntax to read from environment variables. Not needed for WeChat, DingTalk, WeCom, or Feishu
|
|
57
|
-
| `clientId` | DingTalk, Feishu | DingTalk AppKey or Feishu App ID. Supports `$ENV_VAR` syntax
|
|
58
|
-
| `clientSecret` | DingTalk, Feishu | DingTalk AppSecret or Feishu App Secret. Supports `$ENV_VAR` syntax
|
|
59
|
-
| `botId` | WeCom | WeCom intelligent robot Bot ID. Supports `$ENV_VAR` syntax. See [WeCom](./wecom)
|
|
60
|
-
| `secret` | WeCom | WeCom intelligent robot Secret. Supports `$ENV_VAR` syntax. See [WeCom](./wecom)
|
|
61
|
-
| `model` | No | Model to use for this channel (e.g., `qwen3.5-plus`). Overrides the default model. Useful for multimodal models that support image input
|
|
62
|
-
| `senderPolicy` | No | Who can talk to the bot: `allowlist` (default), `open`, or `pairing`
|
|
63
|
-
| `allowedUsers` | No | List of user IDs allowed to use the bot (used by `allowlist` and `pairing` policies)
|
|
64
|
-
| `sessionScope` | No | How sessions are scoped: `user` (default), `thread`, or `single`
|
|
65
|
-
| `cwd` | No | Working directory for the agent. Defaults to the current directory
|
|
66
|
-
| `approvalMode` | No | Tool approval mode for channel sessions. Unattended webhook tasks require `yolo`; the setting applies to every session on the channel
|
|
67
|
-
| `instructions` | No | Custom instructions prepended to the first message of each session
|
|
68
|
-
| `webhooks` | No | Webhook sources and delivery targets for daemon-managed channels. See [Webhook-triggered tasks](#webhook-triggered-tasks)
|
|
69
|
-
| `groupPolicy` | No | Group chat access: `disabled` (default), `allowlist`, or `open`. See [Group Chats](#group-chats)
|
|
70
|
-
| `dmPolicy` | No | Private/DM access: `open` (default) or `disabled` (silently drop all DMs). Useful for group-only bots
|
|
71
|
-
| `groupHistoryLimit` | No | Opt-in group history backfill. `0` or omitted disables it. A positive number persists that many
|
|
72
|
-
| `groups` | No | Per-group settings. Keys are group chat IDs or `"*"` for defaults. See [Group Chats](#group-chats)
|
|
73
|
-
| `dispatchMode` | No | What happens when you send a message while the bot is busy: `steer` (default), `collect`, or `followup`. See [Dispatch Modes](#dispatch-modes)
|
|
74
|
-
| `blockStreaming` | No | Progressive response delivery: `on` or `off` (default). See [Block Streaming](#block-streaming)
|
|
75
|
-
| `blockStreamingChunk` | No | Chunk size bounds: `{ "minChars": 400, "maxChars": 1000 }`. See [Block Streaming](#block-streaming)
|
|
76
|
-
| `blockStreamingCoalesce` | No | Idle flush: `{ "idleMs": 1500 }`. See [Block Streaming](#block-streaming)
|
|
53
|
+
| Option | Required | Description |
|
|
54
|
+
| ------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `type` | Yes | Channel type: `telegram`, `weixin`, `qq`, `dingtalk`, `wecom`, `feishu`, `github`, or a custom type from an extension (see [Plugins](./plugins)) |
|
|
56
|
+
| `token` | Telegram | Bot token. Supports `$ENV_VAR` syntax to read from environment variables. Not needed for WeChat, DingTalk, WeCom, or Feishu |
|
|
57
|
+
| `clientId` | DingTalk, Feishu | DingTalk AppKey or Feishu App ID. Supports `$ENV_VAR` syntax |
|
|
58
|
+
| `clientSecret` | DingTalk, Feishu | DingTalk AppSecret or Feishu App Secret. Supports `$ENV_VAR` syntax |
|
|
59
|
+
| `botId` | WeCom | WeCom intelligent robot Bot ID. Supports `$ENV_VAR` syntax. See [WeCom](./wecom) |
|
|
60
|
+
| `secret` | WeCom | WeCom intelligent robot Secret. Supports `$ENV_VAR` syntax. See [WeCom](./wecom) |
|
|
61
|
+
| `model` | No | Model to use for this channel (e.g., `qwen3.5-plus`). Overrides the default model. Useful for multimodal models that support image input |
|
|
62
|
+
| `senderPolicy` | No | Who can talk to the bot: `allowlist` (default), `open`, or `pairing` |
|
|
63
|
+
| `allowedUsers` | No | List of user IDs allowed to use the bot (used by `allowlist` and `pairing` policies) |
|
|
64
|
+
| `sessionScope` | No | How sessions are scoped: `user` (default), `thread`, or `single` |
|
|
65
|
+
| `cwd` | No | Working directory for the agent. Defaults to the current directory |
|
|
66
|
+
| `approvalMode` | No | Tool approval mode for channel sessions. Unattended webhook tasks require `yolo`; the setting applies to every session on the channel |
|
|
67
|
+
| `instructions` | No | Custom instructions prepended to the first message of each session |
|
|
68
|
+
| `webhooks` | No | Webhook sources and delivery targets for daemon-managed channels. See [Webhook-triggered tasks](#webhook-triggered-tasks) |
|
|
69
|
+
| `groupPolicy` | No | Group chat access: `disabled` (default), `allowlist`, `pairing`, or `open`. See [Group Chats](#group-chats) |
|
|
70
|
+
| `dmPolicy` | No | Private/DM access: `open` (default) or `disabled` (silently drop all DMs). Useful for group-only bots |
|
|
71
|
+
| `groupHistoryLimit` | No | Opt-in group history backfill. `0` or omitted disables it. A positive number persists that many unmentioned group messages from authorized senders or members of approved paired groups for the next bot mention/reply. |
|
|
72
|
+
| `groups` | No | Per-group settings. Keys are group chat IDs or `"*"` for defaults. See [Group Chats](#group-chats) |
|
|
73
|
+
| `dispatchMode` | No | What happens when you send a message while the bot is busy: `steer` (default), `collect`, or `followup`. See [Dispatch Modes](#dispatch-modes) |
|
|
74
|
+
| `blockStreaming` | No | Progressive response delivery: `on` or `off` (default). See [Block Streaming](#block-streaming) |
|
|
75
|
+
| `blockStreamingChunk` | No | Chunk size bounds: `{ "minChars": 400, "maxChars": 1000 }`. See [Block Streaming](#block-streaming) |
|
|
76
|
+
| `blockStreamingCoalesce` | No | Idle flush: `{ "idleMs": 1500 }`. See [Block Streaming](#block-streaming) |
|
|
77
77
|
|
|
78
78
|
### Sender Policy
|
|
79
79
|
|
|
@@ -200,13 +200,13 @@ Run these from the channel's workspace directory (or pass `--cwd <dir>`) — pai
|
|
|
200
200
|
|
|
201
201
|
- Codes are 8 characters, uppercase, using an unambiguous alphabet (no `0`/`O`/`1`/`I`)
|
|
202
202
|
- Codes expire after 1 hour
|
|
203
|
-
- Maximum 3 pending requests per channel at a time — additional requests are
|
|
204
|
-
- Users listed in `allowedUsers` in `settings.json`
|
|
203
|
+
- Maximum 3 pending requests per channel at a time, and at most one per sender — additional requests are declined until one expires or is approved
|
|
204
|
+
- Users listed in `allowedUsers` in `settings.json` skip user pairing; under `groupPolicy: "pairing"`, the group itself must still be approved
|
|
205
205
|
- Approved users are stored per workspace in `~/.qwen/channels/<workspace-scope>/<name>-allowlist.json` — treat this file as sensitive
|
|
206
206
|
|
|
207
207
|
## Group Chats
|
|
208
208
|
|
|
209
|
-
By default, the bot only works in direct messages. To enable group chat support, set `groupPolicy` to `"allowlist"` or `"open"`.
|
|
209
|
+
By default, the bot only works in direct messages. To enable group chat support, set `groupPolicy` to `"allowlist"`, `"pairing"`, or `"open"`.
|
|
210
210
|
|
|
211
211
|
### Group Policy
|
|
212
212
|
|
|
@@ -214,8 +214,26 @@ Controls whether the bot participates in group chats at all:
|
|
|
214
214
|
|
|
215
215
|
- **`disabled`** (default) — The bot ignores all group messages. Safest option.
|
|
216
216
|
- **`allowlist`** — The bot only responds in groups explicitly listed in `groups` by chat ID. The `"*"` key provides default settings but does **not** act as a wildcard allow.
|
|
217
|
+
- **`pairing`** — A deliberate mention or reply from an unknown group creates one pairing request for the group. Once approved, every member can use the bot in that group; `senderPolicy` continues to control direct messages.
|
|
217
218
|
- **`open`** — The bot responds in all groups it's added to. Use with caution.
|
|
218
219
|
|
|
220
|
+
Approve a group with the same CLI command used for user pairing. The pending
|
|
221
|
+
request identifies the group and the member who initiated it:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
qwen channel pairing approve my-channel <CODE>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Group approvals are stored by the group's chat ID in the channel's workspace scope. On GitHub and GitLab the chat ID is the repository/project path, so a rename or transfer detaches the stored approval — re-approve the group after renaming. A repo or project re-created under the same path inherits any stale approval — revoke group approvals after any rename, transfer, or deletion.
|
|
228
|
+
An unmentioned message never creates a group pairing request, even when a group
|
|
229
|
+
sets `requireMention` to `false`; after approval, the configured mention policy
|
|
230
|
+
applies normally.
|
|
231
|
+
|
|
232
|
+
Group pairing requests share the same pending queue as DM pairing requests:
|
|
233
|
+
a channel holds at most 3 pending requests overall, and a sender holds at most
|
|
234
|
+
one pending request across user and group requests (see
|
|
235
|
+
[Pairing Rules](#pairing-rules)).
|
|
236
|
+
|
|
219
237
|
### Mention Gating
|
|
220
238
|
|
|
221
239
|
In groups, the bot requires an `@mention` or a reply to one of its messages by default. This prevents the bot from responding to every message in a group chat.
|
|
@@ -262,7 +280,7 @@ By default, Qwen ignores unmentioned group messages and does not store them as s
|
|
|
262
280
|
|
|
263
281
|
- Omitted or `0` disables backfill.
|
|
264
282
|
- Group-level `groupHistoryLimit` overrides the channel-level value.
|
|
265
|
-
- Only messages from authorized senders are persisted.
|
|
283
|
+
- Only messages from authorized senders, or members of an approved paired group, are persisted.
|
|
266
284
|
- Messages rejected by `groupPolicy` or group allowlist are not persisted.
|
|
267
285
|
- Pending group history is stored as local JSONL under `~/.qwen/channels/<channel-name>-group-history.jsonl` or `$QWEN_HOME/channels/<channel-name>-group-history.jsonl`.
|
|
268
286
|
- Cached messages are injected as untrusted context on the next real trigger and are not written as standalone session turns.
|
|
@@ -270,10 +288,10 @@ By default, Qwen ignores unmentioned group messages and does not store them as s
|
|
|
270
288
|
### How group messages are evaluated
|
|
271
289
|
|
|
272
290
|
```
|
|
273
|
-
1. groupPolicy — is this group
|
|
274
|
-
2. dmPolicy
|
|
291
|
+
1. groupPolicy — is this group disabled, listed, paired, or open? (no → ignore/pairing flow)
|
|
292
|
+
2. dmPolicy — is this DM allowed? (disabled → ignore)
|
|
275
293
|
3. requireMention — was the bot mentioned/replied to? (no → ignore)
|
|
276
|
-
4. senderPolicy — is this sender approved?
|
|
294
|
+
4. senderPolicy — is this sender approved? (skipped for a paired group; otherwise no → user pairing flow)
|
|
277
295
|
5. Route to session
|
|
278
296
|
```
|
|
279
297
|
|
|
@@ -54,7 +54,7 @@ All standard channel options work with custom channels:
|
|
|
54
54
|
| `cwd` | Working directory for the agent |
|
|
55
55
|
| `instructions` | Prepended to the first message of each session |
|
|
56
56
|
| `model` | Model override for the channel |
|
|
57
|
-
| `groupPolicy` | `disabled`, `allowlist`, or `open`
|
|
57
|
+
| `groupPolicy` | `disabled`, `allowlist`, `pairing`, or `open` |
|
|
58
58
|
| `dmPolicy` | `open` or `disabled` |
|
|
59
59
|
| `groups` | Per-group settings |
|
|
60
60
|
|
|
@@ -77,7 +77,7 @@ Custom channels automatically support everything built-in channels do:
|
|
|
77
77
|
- **Sender policies** — `allowlist`, `pairing`, and `open` access control
|
|
78
78
|
- **Group policies** — Per-group settings with optional @mention gating
|
|
79
79
|
- **Session routing** — Per-user, per-thread, or single shared sessions
|
|
80
|
-
- **DM pairing** — Full pairing code flow for unknown users
|
|
80
|
+
- **DM and group pairing** — Full pairing code flow for unknown users and groups
|
|
81
81
|
- **Slash commands** — `/help`, `/clear`, `/status` work out of the box
|
|
82
82
|
- **Custom instructions** — Prepended to the first message in each session
|
|
83
83
|
- **Crash recovery** — Automatic restart with session preservation
|
|
@@ -100,9 +100,10 @@ Open QQ and send a message to your bot. You should see the response arrive in yo
|
|
|
100
100
|
|
|
101
101
|
To use the bot in QQ groups:
|
|
102
102
|
|
|
103
|
-
1. Set `groupPolicy` to `"allowlist"` or `"open"` in your channel config
|
|
103
|
+
1. Set `groupPolicy` to `"allowlist"`, `"pairing"`, or `"open"` in your channel config
|
|
104
104
|
2. Add the bot to a QQ group via the QQ Bot Open Platform dashboard or by having a group admin invite it
|
|
105
105
|
3. Group members must **@mention** the bot to trigger a response
|
|
106
|
+
4. If using `groupPolicy: "pairing"`, approve the group's pairing request once before responses start. Note that once a group is approved, **any member of that group** can use the bot; `senderPolicy` and `allowedUsers` do not gate members of an approved group.
|
|
106
107
|
|
|
107
108
|
QQ Bot API V2 only delivers group messages that @mention the bot — the bot does not see all group messages. By default, `requireMention` is `true` and should be left that way for QQ.
|
|
108
109
|
|
|
@@ -159,7 +160,8 @@ Token refresh continues across WebSocket reconnects — the channel never goes o
|
|
|
159
160
|
|
|
160
161
|
### Bot doesn't respond in groups
|
|
161
162
|
|
|
162
|
-
- Check that `groupPolicy` is set to `"allowlist"` or `"open"` (default is `"disabled"`)
|
|
163
|
+
- Check that `groupPolicy` is set to `"allowlist"`, `"pairing"`, or `"open"` (default is `"disabled"`)
|
|
164
|
+
- If using `"pairing"`, verify the group's pairing request has been approved
|
|
163
165
|
- **You must @mention the bot** — QQ only delivers messages that tag the bot
|
|
164
166
|
- Verify the bot has been added to the group
|
|
165
167
|
|
|
@@ -70,10 +70,11 @@ Then open your bot in Telegram and send a message. You should see "Working..." a
|
|
|
70
70
|
|
|
71
71
|
To use the bot in Telegram groups:
|
|
72
72
|
|
|
73
|
-
1. Set `groupPolicy` to `"allowlist"` or `"open"` in your channel config
|
|
73
|
+
1. Set `groupPolicy` to `"allowlist"`, `"pairing"`, or `"open"` in your channel config
|
|
74
74
|
2. **Disable privacy mode** in BotFather: `/mybots` → select your bot → Bot Settings → Group Privacy → Turn Off
|
|
75
75
|
3. Add the bot to a group. If it was already in the group, **remove and re-add it** (Telegram caches privacy settings from when the bot joined)
|
|
76
76
|
4. If using `groupPolicy: "allowlist"`, add the group's chat ID to `groups` in your config
|
|
77
|
+
5. If using `groupPolicy: "pairing"`, approve the group's pairing request once before responses start. Note that once a group is approved, **any member of that group** can use the bot; `senderPolicy` and `allowedUsers` do not gate members of an approved group.
|
|
77
78
|
|
|
78
79
|
By default, the bot requires an @mention or a reply to respond in groups. Set `"requireMention": false` for a specific group to make it respond to all messages (useful for dedicated task groups). See [Group Chats](./overview#group-chats) for full details.
|
|
79
80
|
|
|
@@ -105,8 +106,9 @@ The agent's markdown responses are automatically converted to Telegram-compatibl
|
|
|
105
106
|
|
|
106
107
|
### Bot doesn't respond in groups
|
|
107
108
|
|
|
108
|
-
- Check that `groupPolicy` is set to `"allowlist"` or `"open"` (default is `"disabled"`)
|
|
109
|
+
- Check that `groupPolicy` is set to `"allowlist"`, `"pairing"`, or `"open"` (default is `"disabled"`)
|
|
109
110
|
- If using `"allowlist"`, verify the group's chat ID is in the `groups` config
|
|
111
|
+
- If using `"pairing"`, verify the group's pairing request has been approved
|
|
110
112
|
- Make sure **Group Privacy is turned off** in BotFather — without this, the bot can't see non-command messages in groups
|
|
111
113
|
- If you changed privacy mode after adding the bot to a group, **remove and re-add the bot** to the group
|
|
112
114
|
- By default, the bot requires an @mention or a reply. Send `@yourbotname hello` to test
|
|
@@ -79,7 +79,7 @@ Open WeCom and send a message to the intelligent robot.
|
|
|
79
79
|
- `pairing`: users must pair before using the bot.
|
|
80
80
|
- `open`: anyone who can message the robot can use it.
|
|
81
81
|
|
|
82
|
-
For groups, set `groupPolicy` to `"allowlist"` or `"open"`. WeCom only delivers group messages that mention the intelligent robot, so every delivered group callback is treated as mentioned. The `requireMention` setting cannot enable responses to unmentioned group messages because those messages are not delivered to the bot.
|
|
82
|
+
For groups, set `groupPolicy` to `"allowlist"`, `"pairing"`, or `"open"`. Under `"pairing"`, the group's first mention creates a pairing request that must be approved once before responses start. Note that under `groupPolicy: "pairing"`, access is granted per group: once a group is approved, **any member of that group** can use the bot; `senderPolicy` and `allowedUsers` do not gate members of an approved group. WeCom only delivers group messages that mention the intelligent robot, so every delivered group callback is treated as mentioned. The `requireMention` setting cannot enable responses to unmentioned group messages because those messages are not delivered to the bot.
|
|
83
83
|
|
|
84
84
|
### Group Mention Compatibility
|
|
85
85
|
|
|
@@ -225,6 +225,10 @@ A finding is skipped when its fix would change intended behavior, would need cha
|
|
|
225
225
|
|
|
226
226
|
Confirmed findings are canonicalized into `.qwen/tmp/qwen-review-<target>-findings.json` before anything else consumes them — the terminal report, the saved Markdown report, and the PR review JSON all read that one artifact instead of re-typing the list. Each finding carries a unique `id` (what outcomes and resolved anchors join on), `severity`, `confidence`, `source`, `summary`, a `shortSummary` capped at 60 characters for list rendering, `failureScenario`, and one or more `locations` — a pattern-aggregated finding keeps **one location per occurrence**, so each still gets its own inline comment.
|
|
227
227
|
|
|
228
|
+
**Before anything else, the review checks that it is running your code.** Every `qwen review …` step runs the built bundle, not the working tree, so a review command edited since the last build takes no effect and the run measures the old behaviour. The build records a digest of the review sources it bundled; `parse-args` re-derives it and compares, and `drive` checks again, because the verifier brief sends agents straight there without a step 1. On a mismatch it says on stderr that the bundle was not built from these sources, and what to rebuild. The check runs when the CLI resolves to the bundled `dist/cli.js` (the `qwen` binary, or `node dist/cli.js`); launchers that run unbundled output, such as `npm start` and `npm run dev`, skip it. Two cases it cannot compare are treated differently: a checkout whose build predates the recording is told the check could not run and why, and an installed package — which has no sources to differ from — is left silent. The digest covers the review commands, the file that registers them, the review-only lease they import from outside their directory, and the bundled review skill; it does not follow those into the shared helpers they import, so a quiet run means the review code matches the bundle rather than that the whole tree does.
|
|
229
|
+
|
|
230
|
+
**A Critical the base tree already failed is held back, not filed.** When a test command failed and the merge base could be built, `test-delta` records which failing files also fail without the pull request. Canonicalization reads that measurement back (`qwen review findings --test-delta`, beside `--outcomes`): a Critical whose own text names one of those files is lowered to a Suggestion, keeps its evidence, gains the measurement that demoted it and a `heldByMeasurement` field, and the demotion is announced. A test that was already red is not a test this pull request turns red — and if it now fails for a _new_ reason, say which test, quote both sides, and file it at Critical again: a finding that already carries the measurement and is raised anyway is left where you put it.
|
|
231
|
+
|
|
228
232
|
The command validates on write: a duplicate id, a finding with no failure scenario, an empty locations array, or an unknown severity is an error rather than a silently mangled entry.
|
|
229
233
|
|
|
230
234
|
## Evidence Images in PR Comments
|
|
@@ -119,7 +119,7 @@ Commands for managing AI tools and models.
|
|
|
119
119
|
| `/arena` | Manage Arena sessions | `/arena start`, `/arena stop`, `/arena status`, `/arena select` (alias `choose`) |
|
|
120
120
|
| `/goal` | Set a goal — keep working until condition met | `/goal <condition>`, `/goal clear` |
|
|
121
121
|
| `/tasks` | List background tasks | `/tasks` |
|
|
122
|
-
| `/workflows` | Inspect workflow runs
|
|
122
|
+
| `/workflows` | Inspect workflow runs; cooperatively pause/resume a background run | `/workflows`, `/workflows <runId>`, `/workflows p <runId>` |
|
|
123
123
|
| `/lsp` | Show LSP server status | `/lsp` |
|
|
124
124
|
| `/trust` | Manage folder trust settings | `/trust` |
|
|
125
125
|
|
|
@@ -522,6 +522,8 @@ The `permissionDecision` value controls whether the tool runs:
|
|
|
522
522
|
- `"deny"` — block the tool; it does not execute and an error is returned to the model.
|
|
523
523
|
- `"ask"` — pause and ask the user to confirm the tool call in the TUI before it runs. Confirming runs the tool once; declining cancels it. In contexts that cannot prompt for confirmation — headless (`--prompt`) runs and background subagents — `"ask"` falls back to `"deny"`.
|
|
524
524
|
|
|
525
|
+
For `"ask"`, the TUI displays `permissionDecisionReason` as literal text rather than interpreting inline Markdown. This keeps formatting markers and link targets visible to the user.
|
|
526
|
+
|
|
525
527
|
**Note**: While standard hook output fields like `decision` and `reason` are technically supported by the underlying class, the official interface expects the `hookSpecificOutput` with `permissionDecision` and `permissionDecisionReason`.
|
|
526
528
|
|
|
527
529
|
**Example Output**:
|
|
@@ -634,6 +636,56 @@ When both fields are present, prompt-hook payloads contain overlapping text and
|
|
|
634
636
|
|
|
635
637
|
Sequential UserPromptSubmit hooks can append `additionalContext` to `prompt`; `submitted_prompt` continues to represent the captured submission. Function hooks are trusted same-process code and are not constrained by an immutability guarantee.
|
|
636
638
|
|
|
639
|
+
When the final hook output contains non-empty `additionalContext`, Qwen first
|
|
640
|
+
sanitizes the value and then sends it to the model as a separate text part:
|
|
641
|
+
|
|
642
|
+
```xml
|
|
643
|
+
<qwen:user-prompt-submit-context>
|
|
644
|
+
sanitized hook context
|
|
645
|
+
</qwen:user-prompt-submit-context>
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
The tag tells the model and transcript consumers that the part came from a
|
|
649
|
+
configured hook rather than from the user prompt. It is a provenance marker,
|
|
650
|
+
not authentication, authorization, or a general trust boundary.
|
|
651
|
+
|
|
652
|
+
For a `UserQuery` with this added context, the session JSONL record preserves
|
|
653
|
+
the model-bound parts, including the tagged part, and adds the following
|
|
654
|
+
`systemPayload`:
|
|
655
|
+
|
|
656
|
+
```json
|
|
657
|
+
{
|
|
658
|
+
"displayText": "pre-hook display projection",
|
|
659
|
+
"hookContext": "sanitized hook context"
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
This two-field payload is written only for this kind of user-prompt record.
|
|
664
|
+
`hookContext` intentionally duplicates the tagged part so offline and
|
|
665
|
+
third-party consumers can identify its provenance without parsing model text.
|
|
666
|
+
`displayText` is the pre-hook display projection and never includes the hook
|
|
667
|
+
context. For a supported interactive TUI submission it is the raw composer
|
|
668
|
+
projection carried by `submitted_prompt`; ACP, headless, `serve`, SDK, remote
|
|
669
|
+
input, and other paths without that provenance record the expanded pre-hook
|
|
670
|
+
prompt instead.
|
|
671
|
+
|
|
672
|
+
Transcript display consumers treat `displayText` as this user-prompt projection
|
|
673
|
+
when `systemPayload.hookContext` is a string. For compatibility with released
|
|
674
|
+
`displayText`-only user-prompt records, a complete tagged context in the final
|
|
675
|
+
part after at least one other part is equivalent pairing evidence. Notification,
|
|
676
|
+
cron, and mid-turn records can also have `displayText`, but those values are
|
|
677
|
+
compact display labels and must not be substituted for their model-bound text
|
|
678
|
+
without that evidence.
|
|
679
|
+
Legacy bare-context records keep their model-bound display behavior because the
|
|
680
|
+
context cannot be separated reliably. For metadata-free records that use the
|
|
681
|
+
current tagged shape, compatibility consumers may remove the same complete
|
|
682
|
+
final tagged part; they must not infer that arbitrary tag-like user text is hook
|
|
683
|
+
provenance.
|
|
684
|
+
|
|
685
|
+
Sensitive prompt telemetry attributes, when enabled, and managed auto-memory
|
|
686
|
+
recall both use the pre-hook prompt. They do not include
|
|
687
|
+
`UserPromptSubmit`-added context.
|
|
688
|
+
|
|
637
689
|
**Output Options**:
|
|
638
690
|
|
|
639
691
|
- `decision`: "allow", "deny", "block", or "ask"
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- **Agent Client Protocol**: Full support for ACP enabling advanced IDE interactions
|
|
9
9
|
- **Symbol management**: #-mention files to add them to the conversation context
|
|
10
10
|
- **Conversation history**: Access to past conversations within the IDE
|
|
11
|
+
- **Context usage**: See the current context-window occupancy while Qwen Code works
|
|
11
12
|
|
|
12
13
|
### Requirements
|
|
13
14
|
|
|
@@ -250,7 +250,7 @@ A daemon **restart** drops all in-memory sessions; clients reconnect and start f
|
|
|
250
250
|
|
|
251
251
|
- **Containerized deployment** — Dockerfile, docker-compose, Kubernetes manifests, nginx + TLS reverse proxy, multi-instance token isolation. Defers to v0.16.x once an enterprise pilot is committed; the doc would otherwise rot from no-one-validating.
|
|
252
252
|
- **Cross-host federation / multi-daemon coordination on one host** — one daemon can host multiple registered workspace runtimes, but daemons do not coordinate. Instance-path token keying + stale-token cleanup defer to v0.16.x.
|
|
253
|
-
- **
|
|
253
|
+
- **General daemon token storage** — `--local-control` generates a fresh token for that process; long-lived deployments remain BYO-token. Persistent token-store infrastructure defers to v0.16.x.
|
|
254
254
|
- **Windows native service** (`nssm`, Service Control Manager wrapper) — for now use [WSL2](https://learn.microsoft.com/en-us/windows/wsl/) and follow the systemd section above.
|
|
255
255
|
|
|
256
256
|
See the [v0.16-alpha known limits](./qwen-serve.md#v016-alpha-known-limits) callout in the main user guide for the full deferred-features list, and [#4175](https://github.com/QwenLM/qwen-code/issues/4175) for the v0.16-alpha rollout tracking issue.
|
|
@@ -39,7 +39,7 @@ The first npm release of `qwen serve` (v0.16-alpha) is intentionally narrow —
|
|
|
39
39
|
- ✅ Bring-your-own bearer token via `QWEN_SERVER_TOKEN` env var ([Authentication](#authentication) for setup)
|
|
40
40
|
- ❌ **Containerized deployment** — Docker / Compose / Kubernetes / nginx reverse-proxy with TLS termination NOT in v0.16-alpha. Defers to v0.16.x once an enterprise pilot is committed (would otherwise rot from no-one-validating).
|
|
41
41
|
- ❌ **Multi-daemon coordination on one host** — one daemon can host several explicitly registered workspaces, but daemons do not coordinate with each other. Cross-host federation, instance-path token keying, and stale-token cleanup defer to v0.16.x.
|
|
42
|
-
-
|
|
42
|
+
- ✅ **Fresh Local Control tokens** — `--local-control` generates a token for that process. General daemon token storage remains BYO-token.
|
|
43
43
|
|
|
44
44
|
**Hardening — minimum viable for local single-user:**
|
|
45
45
|
|
|
@@ -192,7 +192,7 @@ idle daemon returns `initialized: false` with an empty snapshot. Once a
|
|
|
192
192
|
session is alive they switch to `initialized: true` and surface the real
|
|
193
193
|
state.
|
|
194
194
|
|
|
195
|
-
To mirror the CLI `/skills` panel remotely, call `POST /workspace/skills/:name/enable` with `{ "enabled": true | false }` after checking the `workspace_skill_toggle` capability. The
|
|
195
|
+
To mirror the CLI `/skills` panel remotely, call `POST /workspace/skills/:name/enable` with `{ "enabled": true | false }` after checking the `workspace_skill_toggle` capability. To change several Skills, check `workspace_skill_batch_toggle` and call `POST /workspace/skills/enable` with `{ "skillNames": ["review", "deploy"], "enabled": false }`; its response separates successful `results` from per-target `errors`, persists valid targets together, and refreshes active ACP sessions once. The routes update workspace `skills.disabled` and `skills.enabled` as needed and reject unknown, hidden, inactive-extension, higher-scope-locked, and untrusted targets. Enabling a `skills.defaultDisabled` skill writes a canonical opt-in to `skills.enabled`; a hard `skills.disabled` entry inherited from a higher scope still cannot be overridden. Skill status cells expose `disabledReason` (`hard`, `default`, or `inactive_extension`) and an optional `lockedScope`. A `deferred` response means the setting was saved while no ACP child was running; it will apply when the child starts. `skills.disabled` disables both manual and model use, unlike `disable-model-invocation: true`, which keeps direct `/skill-name` invocation available.
|
|
196
196
|
|
|
197
197
|
`GET /workspace/env` and `GET /workspace/preflight` always answer with
|
|
198
198
|
`initialized: true` regardless of ACP state. `env` never consults ACP
|
|
@@ -212,7 +212,7 @@ always render. **ACP-level cells** (auth, MCP discovery, skills, providers,
|
|
|
212
212
|
tool registry, egress) require a live ACP child — when the daemon is idle
|
|
213
213
|
they emit `status: 'not_started'` placeholders rather than spawning ACP just
|
|
214
214
|
to populate them. Failures map to a closed `errorKind` enum (`missing_binary`,
|
|
215
|
-
`auth_env_error`, `init_timeout`, `protocol_error`, `missing_file`,
|
|
215
|
+
`auth_env_error`, `init_timeout`, `restore_timeout`, `protocol_error`, `missing_file`,
|
|
216
216
|
`parse_error`, `blocked_egress`) so client UIs can render structured
|
|
217
217
|
remediation.
|
|
218
218
|
|
|
@@ -384,6 +384,7 @@ Notes:
|
|
|
384
384
|
| --------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
385
385
|
| `--port <n>` | `4170` | TCP port. `0` = OS-assigned ephemeral port. |
|
|
386
386
|
| `--hostname <addr>` | `127.0.0.1` | Bind interface. Anything beyond loopback requires a token. |
|
|
387
|
+
| `--local-control` | `false` | Share the authenticated Web Shell on every non-loopback IPv4 interface with a fresh per-process token, labelled terminal QR codes, exact browser origins, a fixed port, and best-effort sleep inhibition. Conflicts with `--token`, `--allow-origin`, `--no-web`, `--port 0`, and non-default `--hostname`; add `--tls-cert` + `--tls-key` for secure-context browser APIs such as voice input. |
|
|
387
388
|
| `--token <str>` | — | Bearer token. Falls back to `QWEN_SERVER_TOKEN` env var (with leading/trailing whitespace stripped — handy for `$(cat token.txt)`). |
|
|
388
389
|
| `--require-auth` | `false` | Refuse to start without a bearer token, even on loopback. Hardens the `127.0.0.1` developer default for shared dev hosts / CI runners / multi-tenant workstations where any local user can hit the listener. Boots only with `--token` or `QWEN_SERVER_TOKEN` set; gates `/health` behind the bearer too. |
|
|
389
390
|
| `--tls-cert <path>` | — | Path to a PEM certificate file. Serve over **HTTPS** instead of HTTP. Must be paired with `--tls-key` (boot fails if only one is given). Unlocks secure-context browser APIs — voice input (`getUserMedia`), WebRTC — over a LAN IP, which browsers otherwise block on plain `http://`. TLS termination only; no auto-generation / ACME. See [HTTPS / TLS](#https--tls-for-mobile--cross-device-access) below. |
|
|
@@ -396,6 +397,8 @@ Notes:
|
|
|
396
397
|
| `--channel <name\|all>` | — | Experimental daemon-managed channel worker. Repeat the flag to select multiple configured channels, or pass `all` to start every configured channel. `all` cannot be combined with named channels. Selected channel `cwd` values must resolve to a registered workspace; a multi-workspace daemon runs one worker per owning workspace. The worker is owned by `qwen serve`; stop the daemon to stop serve-managed channels. |
|
|
397
398
|
| `--max-connections <n>` | `256` | Listener-level TCP connection cap (`server.maxConnections`). Bounds raw socket count irrespective of session count — slow / phantom SSE clients get rejected at accept time once full. Raise alongside `--max-sessions` if your deployment expects many SSE subscribers per session. |
|
|
398
399
|
| `--memory-budget-mb <n>` | 50% of cgroup/host | Total memory budget in MB for the whole daemon process tree. When unset, derived as 50% of the cgroup limit or host memory; either way the effective value is capped at resolved available memory, and both the configured and effective figures are reported. Currently observation only — it does not change how any `qwen --acp` child is sized. Resolved figures appear under `limits.memory` in `GET /daemon/status`, alongside registered and live child counts and advisory per-child shares under `runtime.memory`. A host too small for the minimum reports `insufficientMemory` rather than being clamped upward; because the derived fraction is 50%, any host under ~2 GB trips this. Pass an explicit `--memory-budget-mb 1024` on such a host to override the derived figure (the flag still requires at least 1024 MB of available memory to clear the warning). Must be an integer in `[1024, 1048576]`. |
|
|
400
|
+
| `--memory-pressure-mode <mode>` | `observe` | Whether the daemon turns its own memory reading into a verdict. `observe` (default) reports the pressure level under `runtime.memory.pressure` in `GET /daemon/status` and raises a `daemon_memory_pressure` issue — a `warning`, so the overall `status` leaves `ok` — whenever the level leaves `normal`. `off` still reports every figure, including the level, but raises no issue, so the overall `status` is unchanged; use it while calibrating, or if you alert on the top-level status. The level is the worse of two ratios: RSS against available memory (what the cgroup OOM killer watches) and V8 heap used against this process's heap ceiling. It covers the daemon root process only; compare it against `runtime.memory.children.rssBytes` for the children. Nothing remediates in either mode. One of `off`, `observe`. |
|
|
401
|
+
| `--child-heap-mode <mode>` | `observe` | Whether the daemon models a per-child heap partition of `--memory-budget-mb`. `observe` (default) reports what it would apply — `limits.memory.childHeap.perChildCeilingMb` and `maxConcurrentChildren` — and counts spawns that would have exceeded the limit. **Nothing is applied**: no child is sized from the budget and no spawn is refused. `off` models nothing, and says so on the wire: `maxConcurrentChildren` and `perChildCeilingMb` are both `null` rather than carrying a partition you switched off. A refusal count of 0 does **not** mean the partition would be safe to apply: children still run on the much larger host-derived ceiling, so a workload needing more old space than the modeled ceiling looks perfectly healthy here. Applying the partition ships with the measurement that can answer that. |
|
|
399
402
|
| `--event-ring-size <n>` | `8000` | Per-session SSE replay ring depth (#3803 §02 target). Sets the backlog available to `GET /session/:id/events` with `Last-Event-ID: N`. Larger = more reconnect headroom at the cost of a few hundred KB extra RAM per session. SDK clients can additionally request a larger per-subscriber backlog cap on a specific subscription via `?maxQueued=N` (range `[16, 2048]`, default 256). Daemons also emit a non-terminal `slow_client_warning` SSE frame at 75% queue fill so clients can drain / reconnect before getting evicted. Pre-flight `caps.features.slow_client_warning`. |
|
|
400
403
|
| `--compacted-replay-max-bytes <n>` | `4194304` | Per-live-session byte cap for the retained replay events in the bounded snapshot returned by `POST /session/:id/load`. The cap applies to `compactedReplay`; the current in-flight `liveJournal` is separately capped by `--max-journal-events` and `--max-journal-bytes`. Values must be positive safe integers; invalid values fail at boot, and the hard ceiling is 256 MiB. When older retained replay is dropped, the snapshot begins with `history_truncated`. This does not limit the on-disk transcript. |
|
|
401
404
|
| `--max-journal-events <n>` | `10000` | Per-session cap on the number of raw events retained in the in-flight live journal (the current unfinished turn). When exceeded, the oldest journal entries are dropped and a `history_truncated` marker is prepended. Must be a positive safe integer. |
|
|
@@ -407,6 +410,7 @@ Notes:
|
|
|
407
410
|
| `--external-tool-guard-timeout-ms <n>` | `3000` | Integer `100..30000`; applies independently to the startup handshake and each prepare request. |
|
|
408
411
|
| `--http-bridge` | `true` | Stage 1 mode: production attempts to preheat one primary `qwen --acp` child for compatibility and retries on first use after failure, while each trusted secondary can start one child on demand. Sessions targeting a runtime multiplex onto its child via ACP `newSession()`; untrusted secondaries cannot start ACP. Stage 2 native in-process becomes available later. |
|
|
409
412
|
| `--initialize-timeout-ms <n>` | `10000` | ACP child request timeout, including the `initialize` handshake (ms). Must be a positive integer up to `2147483647`. Values above the JS timer ceiling (`2^31-1`) are rejected at boot because Node silently compresses them to 1 ms. Cold-container deployments that need extra headroom for child startup can raise this; the same value governs `newSession`, workspace-status polls, and other ACP ext-method deadlines. |
|
|
413
|
+
| `--session-restore-timeout-ms <n>` | `60000` | ACP session load/resume deadline in milliseconds. Must be a positive integer up to `2147483647`; `0` is invalid. If omitted, the default is 60 seconds, raised to an explicitly supplied `--initialize-timeout-ms` when that value is larger; a shorter initialize timeout never lowers the restore budget. The SDK and WebUI add 10 and 15 seconds of client headroom. A timeout returns retryable `504 session_restore_timeout`; it does not imply that the daemon itself exited. |
|
|
410
414
|
| `--allow-origin <pat>` | — | T2.4 ([#4514](https://github.com/QwenLM/qwen-code/issues/4514)). Cross-origin allowlist for browser webui clients. Repeatable. Each value is `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended so `/health` and `/demo` are also bearer-gated, since both are pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo / query). **Subdomain wildcards (`https://*.example.com`) are intentionally unsupported** — list each subdomain explicitly, or use `*` with a configured token (and `--require-auth` for full hardening). Matched origins receive CORS response headers (`Access-Control-Allow-Origin`, `Vary: Origin`, methods, headers, max-age, and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as today's wall. `Origin: null` (sandboxed iframes, file:// docs) is always rejected, even under `*`. Pre-flight via `caps.features.allow_origin`. Loopback self-origin hits are unaffected. |
|
|
411
415
|
| `--web` / `--no-web` | `true` | Serve the built Web Shell SPA at the daemon root (`GET /`, `/assets/*`, and `GET /session/<id>` document navigations). These entry points are registered **before** the bearer-auth gate — a browser can't attach a token to a `<script>` subresource or an address-bar navigation, and the shell carries no secrets. Every API route stays token-gated regardless, and the SPA deep-link fallback for all other paths sits behind the bearer gate too. On non-loopback binds a one-line stderr warning notes the UI is reachable without auth. Use `--no-web` for an API-only daemon. No effect when the build omits the Web Shell assets (the daemon logs a breadcrumb and runs API-only). |
|
|
412
416
|
| `--open` | `false` | After the listener is up, open the Web Shell in your default browser at the daemon URL (with `#token=` appended as a URL fragment when a token is configured — a fragment is never sent to the server, keeping the token out of access logs and Referer headers). No-op with `--no-web`, or in headless / CI / SSH environments where no browser is available. |
|
|
@@ -554,7 +558,8 @@ provider decision with their normal tool policy and isolation boundary.
|
|
|
554
558
|
- **Host header allowlist** — on **loopback** binds the daemon checks `Host:` matches `localhost:port` / `127.0.0.1:port` / `[::1]:port` / `host.docker.internal:port` (case-insensitive per RFC 7230 §5.4) to defend against DNS rebinding. **Non-loopback binds (`--hostname 0.0.0.0`) intentionally bypass the Host allowlist** — the operator has chosen the surface area, so the bearer-token gate is the sole authentication layer; reverse proxies / SNI / client cert pinning are the operator's responsibility, not the daemon's. If you need Host-based isolation on a non-loopback bind, terminate TLS + check Host at a front proxy.
|
|
555
559
|
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` and `/demo` remain pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the `/demo` page) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
|
|
556
560
|
- **Chrome extension browser automation is separate from framing.** `qwen serve --allow-origin chrome-extension://<id>` lets the extension frame the Web Shell and connect to the daemon. Console/network/screenshot/click tools require an external CDP MCP adapter command: `QWEN_CDP_MCP_COMMAND=/path/to/cdp-mcp-adapter qwen serve --allow-origin chrome-extension://<id>`. The main CLI package does not bundle a browser automation adapter; clients can check `caps.features.includes('browser_automation_mcp')` before presenting those tools as available.
|
|
557
|
-
- **A spawned `qwen --acp` child receives its owning runtime's effective environment.** The daemon freezes a process-env base, applies that workspace's settings/env-file overlay to a runtime-local snapshot, and never writes the overlay back to `process.env`; same-named keys in another runtime do not cross over. `QWEN_SERVER_TOKEN` is scrubbed before spawn because the agent does not need the daemon bearer. Base credentials such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `QWEN_*`, and `DASHSCOPE_API_KEY` otherwise pass through unless the runtime overlay changes them. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc`, `~/.aws/credentials`, or `~/.npmrc` is reachable by prompt injection regardless. Environment isolation between runtimes is not an operating-system security boundary; do not run `qwen serve` under an identity that has credentials you would not trust the agent with.
|
|
561
|
+
- **A spawned `qwen --acp` child receives its owning runtime's effective environment.** The daemon freezes a process-env base, applies that workspace's settings/env-file overlay to a runtime-local snapshot, and never writes the overlay back to `process.env`; same-named keys in another runtime do not cross over. `QWEN_SERVER_TOKEN` is scrubbed before spawn because the agent does not need the daemon bearer. Loader-affecting variables (`NODE_OPTIONS`, `npm_config_node_options` and npm's config-file redirects, `NODE_PATH`, `LD_PRELOAD`, `LD_AUDIT`, `DYLD_INSERT_LIBRARIES`, `BASH_ENV`, `ZDOTDIR`, exported bash function definitions `BASH_FUNC_*`) are likewise never passed to session subprocesses — the daemon scrubs them from its own `process.env` and from the frozen base env that session-hosting children spawn with (the base env keeps them only under the `DEV=true` harness, whose `.ts` entries still need the tsx loader), and `.env` / `settings.json` `env` sources reject them (see [settings](./configuration/settings.md)); this applies to every session the daemon hosts. Base credentials such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `QWEN_*`, and `DASHSCOPE_API_KEY` otherwise pass through unless the runtime overlay changes them. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc`, `~/.aws/credentials`, or `~/.npmrc` is reachable by prompt injection regardless. Environment isolation between runtimes is not an operating-system security boundary; do not run `qwen serve` under an identity that has credentials you would not trust the agent with.
|
|
562
|
+
- **Agent text reads are child-local and follow the regular CLI permission rules, not the workspace filesystem boundary.** Direct `read_file` can reach host text paths outside every registered workspace: external paths default to confirmation, and allow rules or approval modes may approve them automatically. Approved reads use the configurable CLI output limits rather than the workspace filesystem's returned-output, full-snapshot, and large-text scan caps. This applies to every shared text-read consumer, so the pre-reads performed by write, edit, notebook, sed, and artifact operations lose those caps together with the workspace filesystem's read audit, symlink rejection, and read-side TOCTOU protections — see [the design doc](../design/daemon-local-text-reads.md) for the exact list. Because a confirmation payload is built by reading the file, an out-of-workspace diff is fanned out to **every** attached SSE subscriber before anyone approves it — in the interactive CLI that content is seen only by the person at the terminal. Treat authenticated daemon clients as the same security principal. HTTP filesystem routes remain workspace-scoped and still refuse these paths, agent discovery-tool behavior is unchanged, and final ACP `writeTextFile` content writes continue through the workspace filesystem.
|
|
558
563
|
- **Per-subscriber bounded SSE queues** — a slow client that overflows its queue gets a `client_evicted` terminal frame and is closed; one stuck consumer can't pin the daemon.
|
|
559
564
|
- **Per-session prompt admission cap** — defaults to 5 accepted-but-unsettled prompts per session. A buggy client cannot enqueue unbounded prompt promises or temporary SSE waits for one session.
|
|
560
565
|
- **Graceful shutdown** — SIGINT/SIGTERM drain the agent children before closing the listener (10s deadline per child).
|
|
@@ -641,7 +646,7 @@ for await (const event of session.events()) {
|
|
|
641
646
|
}
|
|
642
647
|
```
|
|
643
648
|
|
|
644
|
-
Pre-flight `caps.features.session_load`, `caps.features.session_resume`, or `caps.features.session_transcript` before calling the matching route — older daemons return `404`. `unstable_session_resume` is still advertised as a deprecated compatibility alias. Concurrent same-action requests for the same id coalesce; cross-action races (a `load` racing a `resume`) get `409 restore_in_progress` with `Retry-After: 5`. See the [protocol reference](../developers/qwen-serve-protocol.md) for the full error envelope.
|
|
649
|
+
Pre-flight `caps.features.session_load`, `caps.features.session_resume`, or `caps.features.session_transcript` before calling the matching route — older daemons return `404`. `unstable_session_resume` is still advertised as a deprecated compatibility alias. Concurrent same-action requests for the same id coalesce; cross-action races (a `load` racing a `resume`) and caller-supplied-id spawns racing a restore get `409 restore_in_progress` with `Retry-After: 5`. A restore that exceeds `limits.sessionRestoreTimeoutMs` gets retryable `504 session_restore_timeout` with a budget-derived `Retry-After` (clamped to 5-120s); the still-running child request remains fenced until cleanup settles, and same-id retries during that window get `409 restore_in_progress` with `reason: awaiting_abandoned_cleanup` and a budget-derived `Retry-After` clamped to 5-120 seconds instead of a fixed 5-second delay. If cleanup is uncertain, or the abandoned restore has still not settled a full restore budget after its deadline, fresh session work temporarily gets `503 acp_channel_unavailable` with `reason: restore_cleanup_failed` or `restore_settlement_overdue`, while already-live sessions remain usable. See the [protocol reference](../developers/qwen-serve-protocol.md) for the full error envelope.
|
|
645
650
|
|
|
646
651
|
For full persisted replay, page with `DaemonClient.getSessionTranscriptPage(sessionId, { cursor, limit })` or the raw REST route:
|
|
647
652
|
|