@qwen-code/qwen-code 0.19.7 → 0.19.8-nightly.20260710.205430235
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 +43 -36
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +20 -12
- package/bundled/qc-helper/docs/features/channels/plugins.md +1 -0
- package/bundled/qc-helper/docs/features/code-review.md +2 -1
- package/bundled/qc-helper/docs/features/commands.md +39 -38
- package/bundled/qc-helper/docs/features/computer-use.md +77 -0
- package/bundled/qc-helper/docs/features/hooks.md +36 -34
- package/bundled/qc-helper/docs/features/memory.md +1 -1
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +19 -23
- package/bundled/qc-helper/docs/qwen-serve.md +22 -12
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +14 -13
- package/bundled/review/SKILL.md +38 -61
- package/chunks/{MaxSizedBox-XY5LIO5O.js → MaxSizedBox-LOFYQFYJ.js} +13 -14
- package/chunks/{StandaloneSessionPicker-APISIRJZ.js → StandaloneSessionPicker-U5OQBGEB.js} +31 -29
- package/chunks/{acpAgent-MMOSC2YA.js → acpAgent-SDIFRIED.js} +637 -131
- package/chunks/{agent-TKIBLLQT.js → agent-JIBBVHNQ.js} +10 -10
- package/chunks/{agent-headless-VLX4C7KX.js → agent-headless-6LGZYJYU.js} +10 -10
- package/chunks/{anthropicContentGenerator-AKYPSZIV.js → anthropicContentGenerator-55REPTTF.js} +30 -3
- package/chunks/{artifact-tool-D233YJFH.js → artifact-tool-EIN46DPM.js} +1 -1
- package/chunks/{askUserQuestion-MKL5ZTMC.js → askUserQuestion-6YX6ZRX7.js} +1 -1
- package/chunks/{bridge-BCU73DZO.js → bridge-HVPFYNM4.js} +17 -16
- package/chunks/{ca-HCMB2I54.js → ca-MULEGDVS.js} +89 -5
- package/chunks/{channel-worker-supervisor-CRCVYQIE.js → channel-worker-supervisor-OPXXT4JK.js} +20 -3
- package/chunks/{chunk-DGHJTO2K.js → chunk-2AF26HVM.js} +31 -2
- package/chunks/{chunk-3B26UVCX.js → chunk-2GUVUHJY.js} +6 -4
- package/chunks/{chunk-FV7425LN.js → chunk-2SZOMGOR.js} +4 -1
- package/chunks/{chunk-CNSF3WO5.js → chunk-32KS5XSX.js} +3 -3
- package/chunks/{chunk-4UCTWSTP.js → chunk-34UUM3IN.js} +1 -1
- package/chunks/{chunk-G7ZG7CA6.js → chunk-3UP777ZS.js} +8 -7
- package/chunks/{chunk-MIG5SQNL.js → chunk-4CSVIZLT.js} +4 -4
- package/chunks/{chunk-GD236YPV.js → chunk-4ONWIT5C.js} +1 -1
- package/chunks/{chunk-4ZJIPVPB.js → chunk-4XK7TNBP.js} +8 -8
- package/chunks/{chunk-I4A4K72C.js → chunk-5F2H3PXG.js} +446 -232
- package/chunks/chunk-5HOF2K5U.js +19 -0
- package/chunks/{chunk-GMOWQOQQ.js → chunk-5ZVIYNLN.js} +228 -36
- package/chunks/chunk-6O6Z2I5Q.js +292 -0
- package/chunks/{chunk-RYFZCUJO.js → chunk-6QKT5VNZ.js} +14 -6
- package/chunks/{chunk-SD4N3QJ2.js → chunk-6ZPSVWLF.js} +61 -17
- package/chunks/{chunk-X265R5C6.js → chunk-7YGSDQ5J.js} +2 -2
- package/chunks/{chunk-PRDFOIZF.js → chunk-A6KEUFJO.js} +32 -5
- package/chunks/{chunk-OWVIH4HY.js → chunk-B5OAMPJ5.js} +389 -87
- package/chunks/{chunk-ME3YSROJ.js → chunk-CV2AT2WJ.js} +22 -10
- package/chunks/{chunk-U4FRHCLA.js → chunk-DDKUYKHA.js} +1912 -201
- package/chunks/{chunk-YDSYD7UI.js → chunk-E3SA2LY4.js} +2 -2
- package/chunks/{chunk-6IAWPIQ6.js → chunk-EDM5O3SX.js} +2 -2
- package/chunks/{chunk-CISB3IQF.js → chunk-FONJQQWI.js} +65 -6
- package/chunks/{chunk-FRFFNYUY.js → chunk-G3WIMNL4.js} +3 -3
- package/chunks/{chunk-B34OV7K2.js → chunk-GGQQA4JW.js} +13 -0
- package/chunks/chunk-GLE2YUPU.js +34 -0
- package/chunks/{chunk-MJI36HER.js → chunk-GOTMC3BX.js} +1 -1
- package/chunks/{chunk-RFIL6REB.js → chunk-GRB4QSBD.js} +168 -31
- package/chunks/chunk-GVVY7GSP.js +38 -0
- package/chunks/{chunk-7JGISHHZ.js → chunk-HDEUQRAR.js} +14 -156
- package/chunks/{chunk-NZEGNV4V.js → chunk-HPRI22FZ.js} +6 -6
- package/chunks/{chunk-STAZRKOT.js → chunk-I34IHZFJ.js} +117 -459
- package/chunks/{chunk-JF7DFPQ5.js → chunk-I3MBKL6Z.js} +12 -2
- package/chunks/{chunk-DNV4FSN5.js → chunk-I5XN6KDI.js} +21 -4
- package/chunks/{chunk-VZ7HY3YU.js → chunk-IAMRWMFU.js} +1 -1
- package/chunks/{chunk-44NROQYV.js → chunk-JOQMY62N.js} +1 -1
- package/chunks/{chunk-VQWAZSXN.js → chunk-JW4IKIZ2.js} +57 -35
- package/chunks/{chunk-SAIILPQ3.js → chunk-KJMYXFUR.js} +3 -1
- package/chunks/{chunk-AFOLR6YL.js → chunk-KQ6MKCFE.js} +102 -16
- package/chunks/{chunk-X3YGAX7V.js → chunk-KS2FRTYI.js} +2 -0
- package/chunks/{chunk-IUE7YWC3.js → chunk-LE7EF36E.js} +7 -7
- package/chunks/{chunk-B4U2M63D.js → chunk-LRY7HD3Q.js} +2101 -11
- package/chunks/{chunk-PUQLHSQ2.js → chunk-ME7E6WZB.js} +6 -8
- package/chunks/{chunk-LEIJKM7Q.js → chunk-MEK7ZRJ3.js} +1 -1
- package/chunks/{chunk-AJBEAUIS.js → chunk-MG2TNCRX.js} +4 -3
- package/chunks/{chunk-GL5TV7B5.js → chunk-MSMQURDV.js} +21 -5
- package/chunks/{chunk-6BN7NZ5Z.js → chunk-NXDJLKKX.js} +4 -6
- package/chunks/{chunk-FEJ2FZ3U.js → chunk-NY2ZOFMM.js} +1 -1
- package/chunks/{chunk-QZF5U5KA.js → chunk-NY5BE643.js} +8 -8
- package/chunks/{chunk-4RQIB5UZ.js → chunk-O2YT7VB4.js} +0 -34
- package/chunks/{chunk-4KJ2BPIT.js → chunk-OACJLMLD.js} +2 -38
- package/chunks/chunk-PCWSPWXZ.js +168 -0
- package/chunks/{chunk-XPJH4PKR.js → chunk-PJ74K3DH.js} +1 -1
- package/chunks/{chunk-FTFXDZYI.js → chunk-PW7VWRLX.js} +45 -29
- package/chunks/chunk-R3SLDK6Y.js +468 -0
- package/chunks/{chunk-4O344UEE.js → chunk-SDJOZOYY.js} +38 -18
- package/chunks/{chunk-ALZ75L2X.js → chunk-SMYIBRAA.js} +412 -376
- package/chunks/{chunk-CCGOFQV3.js → chunk-SS5P6JM6.js} +6 -5
- package/chunks/{chunk-AIY5UTFI.js → chunk-T3XHYGMG.js} +925 -2872
- package/chunks/{chunk-Q6OEPOOC.js → chunk-TB6GWNV4.js} +1 -1
- package/chunks/{chunk-24XYI5EI.js → chunk-TERKDCOZ.js} +3 -3
- package/chunks/chunk-TVO5C767.js +159 -0
- package/chunks/{chunk-TBAZMRW3.js → chunk-TVW53EK7.js} +1 -1
- package/chunks/chunk-TX5QZYK6.js +296 -0
- package/chunks/{chunk-JD33UY7E.js → chunk-TZRVTPJ6.js} +15 -9
- package/chunks/{chunk-65CFHNSE.js → chunk-UAFB2DNB.js} +59 -59
- package/chunks/{chunk-QAKFYMJI.js → chunk-UOXLB2LY.js} +152 -17
- package/chunks/chunk-V35MD7KN.js +13 -0
- package/chunks/{chunk-XSAFNANZ.js → chunk-VWDJHVXM.js} +12 -12
- package/chunks/{chunk-XISQIIT7.js → chunk-W77ZLCSX.js} +1 -1
- package/chunks/{chunk-BWVQN2HV.js → chunk-WTEIUA2V.js} +4 -4
- package/chunks/{chunk-TDGF35EN.js → chunk-XOHNA2S6.js} +1 -1
- package/chunks/{chunk-HJ3GX3Y3.js → chunk-XZVUZSDG.js} +25 -11
- package/chunks/{chunk-ADZG46HR.js → chunk-YHGCTQG3.js} +1 -1
- package/chunks/{chunk-2NPS2UDH.js → chunk-YUNPEB3Q.js} +478 -43
- package/chunks/chunk-Z3I3QJK3.js +47 -0
- package/chunks/{chunk-P7I3D7FM.js → chunk-Z466FBSA.js} +1 -1
- package/chunks/{chunk-YEGT55NW.js → chunk-ZDAZSR2O.js} +3009 -1220
- package/chunks/{chunk-VEB3NYSO.js → chunk-ZJQBTFJ6.js} +6 -1
- package/chunks/chunk-ZL5HN75Q.js +61 -0
- package/chunks/{computer-use-X4KUU3NM.js → computer-use-IW5XBECT.js} +10 -10
- package/chunks/{contextCommand-LAYJZF7H.js → contextCommand-4QPLK2SH.js} +14 -14
- package/chunks/create-sub-session-7JK3EYWA.js +212 -0
- package/chunks/create-sub-session-EVYZYAE3.js +364 -0
- package/chunks/{cron-create-JSXEIPVS.js → cron-create-2CCO2PW6.js} +2 -2
- package/chunks/{cron-delete-OIFVEPGU.js → cron-delete-ETVTP5IV.js} +2 -2
- package/chunks/{cron-list-D4ZX4IOE.js → cron-list-FS3KWOY5.js} +2 -2
- package/chunks/{daemon-F3I2RXP6.js → daemon-NNUYIBWA.js} +461 -0
- package/chunks/{daemon-status-provider-XSAFKVDS.js → daemon-status-provider-3EPG6BXX.js} +21 -19
- package/chunks/{de-PLLFDERI.js → de-QRG6J2CM.js} +89 -5
- package/chunks/{dist-YTRKAVUB.js → dist-3EIIFOJV.js} +1 -1
- package/chunks/{dist-PKFTNUHO.js → dist-7F5GWZDZ.js} +2 -1
- package/chunks/{dist-FQ5WRJPL.js → dist-CBJ7OJ5R.js} +2 -2
- package/chunks/{dist-OT7G2WNM.js → dist-LIFJ2YAI.js} +1 -1
- package/chunks/{dist-573HNSVO.js → dist-OKXOQ63L.js} +2 -1
- package/chunks/{dist-IMFFBMAT.js → dist-SU5LY5R4.js} +3 -1
- package/chunks/{earlyInputCapture-AERYYGXE.js → earlyInputCapture-HP5XAS7A.js} +10 -10
- package/chunks/{edit-WZTZDGCI.js → edit-MDICC6KH.js} +11 -11
- package/chunks/{en-GA2RMXY5.js → en-HF3KFWZG.js} +91 -5
- package/chunks/{enter-worktree-DEPXBJEL.js → enter-worktree-JWTRNEN4.js} +10 -10
- package/chunks/{enterPlanMode-JFGXZHHJ.js → enterPlanMode-GMRZMTBQ.js} +10 -10
- package/chunks/environment-2CJAFOFN.js +88 -0
- package/chunks/{errors-GMZL4QV7.js → errors-UZOVFD2U.js} +13 -13
- package/chunks/{exit-worktree-Y7XBK3VV.js → exit-worktree-QQGEG343.js} +10 -10
- package/chunks/{exitPlanMode-WQQER65F.js → exitPlanMode-YK2JVAAB.js} +10 -10
- package/chunks/{fast-path-W2U6XDNO.js → fast-path-6SD4JNQW.js} +12 -3
- package/chunks/{fast-path-settings-RCRXH2JG.js → fast-path-settings-RAQGCIT7.js} +3 -2
- package/chunks/{fr-GWNQG4XH.js → fr-RSCO6HHD.js} +89 -5
- package/chunks/{gemini-T4WX6SRW.js → gemini-TFQXPUZB.js} +436 -140
- package/chunks/{geminiContentGenerator-MKQACXEJ.js → geminiContentGenerator-LJ2BNXHX.js} +1 -1
- package/chunks/{glob-4KKSHZDF.js → glob-3IJ6JR5W.js} +10 -10
- package/chunks/{grep-GHRYXSLZ.js → grep-UFZ2RFQZ.js} +10 -10
- package/chunks/{handleAutoUpdate-HN7ZOSXY.js → handleAutoUpdate-TEZC5ZIR.js} +17 -13
- package/chunks/i18n-5QEODTJV.js +84 -0
- package/chunks/{initializer-SRN3IM42.js → initializer-222MPCLQ.js} +18 -16
- package/chunks/installationInfo-OZ62OHZ2.js +65 -0
- package/chunks/{ja-2HOTA47X.js → ja-RRFGG2DC.js} +89 -5
- package/chunks/{list-INTVXUPA.js → list-BN5VBIIE.js} +20 -18
- package/chunks/{loadedSettingsAdapter-QVHHQPGM.js → loadedSettingsAdapter-EHTUJRFB.js} +18 -16
- package/chunks/{loop-wakeup-OHWEMFP5.js → loop-wakeup-SR2KWT4B.js} +3 -3
- package/chunks/{ls-L654WOAT.js → ls-RUBQK5Q2.js} +2 -2
- package/chunks/{lsp-M35KE54Y.js → lsp-DUTVY2ZA.js} +3 -5
- package/chunks/{mcp-7V4T46RG.js → mcp-OPGHD26Y.js} +18 -16
- package/chunks/{monitor-464OY2UE.js → monitor-WXBDVYYV.js} +10 -10
- package/chunks/{nonInteractiveCli-LJEEODU2.js → nonInteractiveCli-CWIBGJ4U.js} +54 -49
- package/chunks/{notebook-edit-BLJYCNDO.js → notebook-edit-T7P7M73F.js} +11 -11
- package/chunks/{openaiContentGenerator-PFF6HYB2.js → openaiContentGenerator-OES264C3.js} +7 -7
- package/chunks/{pidfile-LIBUENIV.js → pidfile-LJ3NLS2P.js} +10 -10
- package/chunks/{pt-2THT3YHA.js → pt-D4CG46JM.js} +89 -5
- package/chunks/{qwenContentGenerator-SUUHZ6CR.js → qwenContentGenerator-QJ67LAJ5.js} +12 -12
- package/chunks/{read-file-L7TBQVX7.js → read-file-KZD7TLU7.js} +5 -5
- package/chunks/{read-mcp-resource-CNQHBSJM.js → read-mcp-resource-Q56IMYOH.js} +1 -1
- package/chunks/{record-artifact-PP3LKHTS.js → record-artifact-GZ5D5HZX.js} +4 -4
- package/chunks/{ripGrep-CKKX3GRB.js → ripGrep-KUJLX75U.js} +10 -10
- package/chunks/{ru-Z67YJHBG.js → ru-O2QUEL22.js} +89 -5
- package/chunks/{run-qwen-serve-5OKADVLE.js → run-qwen-serve-M52KVRGI.js} +664 -153
- package/chunks/{scheduler-ZRW3AIDU.js → scheduler-FFATTAYZ.js} +10 -10
- package/chunks/{send-message-OA6MV4EU.js → send-message-HAGK3VTV.js} +2 -2
- package/chunks/{serve-36WS32W6.js → serve-B5S32524.js} +21 -18
- package/chunks/{server-M372UENX.js → server-6HK5FJMR.js} +3301 -665
- package/chunks/{session-F5KSNP2N.js → session-3WB76VTQ.js} +55 -50
- package/chunks/{settings-WFLNS3WT.js → settings-W3IX7NHK.js} +27 -23
- package/chunks/{shell-DEDSWN56.js → shell-HZIU2ZG7.js} +10 -10
- package/chunks/{skill-A2TL2NPC.js → skill-34OUFB65.js} +5 -5
- package/chunks/{spawnChannel-RQHUWTCL.js → spawnChannel-FTZJ3I5O.js} +12 -12
- package/chunks/{src-XKZMNHXS.js → src-NELBIIGI.js} +48 -10
- package/chunks/standalone-update-LICI2VSK.js +79 -0
- package/chunks/{startInteractiveUI-REKSTOHU.js → startInteractiveUI-LZEV5YI2.js} +2203 -1764
- package/chunks/stdioHelpers-CA7MG65Z.js +14 -0
- package/chunks/{syntheticOutput-F7LSDCAR.js → syntheticOutput-XFFJVCGV.js} +2 -2
- package/chunks/{task-create-RPFZNB4B.js → task-create-VINUSVBF.js} +3 -3
- package/chunks/{task-list-TGGJX7EA.js → task-list-YZ2AWQEG.js} +1 -1
- package/chunks/{task-stop-W7NGTMYQ.js → task-stop-PEXPKUW3.js} +1 -1
- package/chunks/{task-update-5WUG5MVQ.js → task-update-BHIX57YH.js} +3 -3
- package/chunks/{team-create-TBQVWAG7.js → team-create-2JS2OYSF.js} +10 -10
- package/chunks/{team-delete-UHQQ2QQX.js → team-delete-2OHXSBVS.js} +1 -1
- package/chunks/{team-plan-approval-FZPGUSHJ.js → team-plan-approval-PHLGYUY7.js} +10 -10
- package/chunks/{theme-manager-DQZVNSOC.js → theme-manager-UYXLX37P.js} +10 -10
- package/chunks/{todoWrite-C4ZAMSR3.js → todoWrite-7Q4ELT4F.js} +1 -1
- package/chunks/{tool-search-FDQ3SLNJ.js → tool-search-2MWA3GWE.js} +6 -6
- package/chunks/total-session-admission-PRZK35X4.js +72 -0
- package/chunks/{trustedFolders-Z475EIHL.js → trustedFolders-IT4JBNPG.js} +12 -12
- package/chunks/{updateCheck-E2ZX7RL7.js → updateCheck-X3ZWDO3Z.js} +17 -13
- package/chunks/updateEventEmitter-NXWTRHXY.js +10 -0
- package/chunks/{validateNonInterActiveAuth-O4ECBHQL.js → validateNonInterActiveAuth-IAOL7CM3.js} +51 -45
- package/chunks/{version-CEDD6ZZR.js → version-25QF6A5H.js} +1 -1
- package/chunks/{web-fetch-UYGMOHW4.js → web-fetch-I7FOWHGA.js} +2 -2
- package/chunks/{workflow-CQQ4J4I6.js → workflow-LZZ5U3IT.js} +11 -11
- package/chunks/{workspace-providers-status-MVYXMYDG.js → workspace-providers-status-7DTOAWEL.js} +21 -18
- package/chunks/workspace-registry-BBIPESIZ.js +76 -0
- package/chunks/{workspace-service-OMBR6ZLG.js → workspace-service-SY3P3FUY.js} +25 -23
- package/chunks/{workspace-skills-status-IMMQ7CAY.js → workspace-skills-status-GTT2A4WN.js} +20 -18
- package/chunks/{write-file-VWGY7AJP.js → write-file-M6IHNW3V.js} +11 -11
- package/chunks/{zh-7XVVRTDH.js → zh-K2EH6BDD.js} +91 -5
- package/chunks/{zh-TW-DPH554OG.js → zh-TW-4GPXJ7ZY.js} +91 -5
- package/cli.js +13 -12
- package/locales/ca.js +115 -7
- package/locales/de.js +114 -7
- package/locales/en.js +118 -7
- package/locales/fr.js +115 -7
- package/locales/ja.js +116 -6
- package/locales/pt.js +114 -7
- package/locales/ru.js +114 -7
- package/locales/zh-TW.js +114 -6
- package/locales/zh.js +114 -6
- package/package.json +3 -6
- package/web-shell/assets/{arc-C7hjaa7g.js → arc-G3HZaqaL.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-pm9KtMZY.js → architectureDiagram-3BPJPVTR-DhBrwwch.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-CApElKsU.js → blockDiagram-GPEHLZMM-16JbbF0N.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BeDe0-9N.js → c4Diagram-AAUBKEIU-DQ3-pKgc.js} +1 -1
- package/web-shell/assets/channel-CX7ZHuuL.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-DJEkmLdl.js → chunk-2J33WTMH-ERCn30sp.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-DXX8gdpe.js → chunk-4BX2VUAB-DTysfbFi.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DORmk1kQ.js → chunk-55IACEB6-BFGrbTBi.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-DWmO4mCZ.js → chunk-727SXJPM-DCX4Oar-.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-C7LRaYw2.js → chunk-AQP2D5EJ-CgT6sBr3.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CCdXgyC5.js → chunk-FMBD7UC4-C1Uuk1KV.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-SyL_xvWc.js → chunk-ND2GUHAM-DajgESiu.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-BzOuCKxa.js → chunk-QZHKN3VN-DLJSvy9X.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-B-oT3UI8.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B-oT3UI8.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BMPWyDKc.js → cose-bilkent-S5V4N54A-CH3w3qs7.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-B_GnPWik.js → dagre-BM42HDAG-BloXan9B.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-fJqMc3S_.js → diagram-2AECGRRQ-BbZiGcmK.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-ximV3O9D.js → diagram-5GNKFQAL-GQlYvLJv.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-2vVyjzqw.js → diagram-KO2AKTUF-CtIBvVq3.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-Dckcx1sT.js → diagram-LMA3HP47-D5TBo9a2.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BAVv47ga.js → diagram-OG6HWLK6-N0gQhw6R.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-Bn3nf5J0.js → erDiagram-TEJ5UH35-zab9vDj3.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BIbGF9JT.js → flowDiagram-I6XJVG4X-BnnjtWJa.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CDbhb3AH.js → ganttDiagram-6RSMTGT7-2T0SQU4f.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CbKG1a_w.js → gitGraphDiagram-PVQCEYII-DAD6_que.js} +1 -1
- package/web-shell/assets/index-XLkWfLja.css +5 -0
- package/web-shell/assets/index-srlTR1Jg.js +786 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DUFxTy8m.js → infoDiagram-5YYISTIA-C-j8d0xO.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-D69hrBG8.js → ishikawaDiagram-YF4QCWOH-D97bAKoT.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-DsvEw51Y.js → journeyDiagram-JHISSGLW-BJAHfJmm.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-lFFjZEYd.js → kanban-definition-UN3LZRKU-CZgR5aac.js} +1 -1
- package/web-shell/assets/{linear-Bo5bWzvo.js → linear-DOd4kYhA.js} +1 -1
- package/web-shell/assets/{mermaid.core-C_HKMJx5.js → mermaid.core-BBaplnXA.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DlV-NUTs.js → mindmap-definition-RKZ34NQL-IhBF_BR5.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-B2e6FH2a.js → pieDiagram-4H26LBE5-B4R4sYyH.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-D75kSk-b.js → quadrantDiagram-W4KKPZXB-DKd1SJ61.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-CQ6xakhM.js → requirementDiagram-4Y6WPE33-Cw96V0Xb.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-J_XTKrcY.js → sankeyDiagram-5OEKKPKP-C6ne_yWi.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-D7jTcBtf.js → sequenceDiagram-3UESZ5HK-CCyp4PDp.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CrlM_OT3.js → stateDiagram-AJRCARHV-DHvIqTmx.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DvFhmpwA.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-5oZi76Ef.js → timeline-definition-PNZ67QCA-amb3n9zH.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DO5YptPK.js → vennDiagram-CIIHVFJN-Abf2qRFJ.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-4t1eJDvM.js → wardley-L42UT6IY-BBlOp1av.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-DKZc661S.js → wardleyDiagram-YWT4CUSO-gE_sZ0Ak.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-su9hp08G.js → xychartDiagram-2RQKCTM6-BwOni53i.js} +1 -1
- package/web-shell/index.html +16 -4
- package/chunks/chunk-6SHO7WFF.js +0 -79
- package/chunks/chunk-IFEWJXFS.js +0 -37
- 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-BNf1dW-j.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-uOIGlzgi.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-uOIGlzgi.js +0 -1
- package/web-shell/assets/index-CnE2ur2L.js +0 -779
- package/web-shell/assets/index-hSKXrlSE.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Bs4TK_84.js +0 -1
- /package/chunks/{chunk-Y6Z2O3WR.js → chunk-JM7BYJO5.js} +0 -0
|
@@ -64,7 +64,7 @@ Command hooks execute commands via child processes. Input JSON is passed through
|
|
|
64
64
|
"hooks": {
|
|
65
65
|
"PreToolUse": [
|
|
66
66
|
{
|
|
67
|
-
"matcher": "
|
|
67
|
+
"matcher": "write_file",
|
|
68
68
|
"hooks": [
|
|
69
69
|
{
|
|
70
70
|
"type": "command",
|
|
@@ -215,7 +215,7 @@ When `ok` is `false`, Qwen Code will continue working and use the `reason` as co
|
|
|
215
215
|
"hooks": {
|
|
216
216
|
"PreToolUse": [
|
|
217
217
|
{
|
|
218
|
-
"matcher": "
|
|
218
|
+
"matcher": "run_shell_command",
|
|
219
219
|
"hooks": [
|
|
220
220
|
{
|
|
221
221
|
"type": "prompt",
|
|
@@ -235,43 +235,45 @@ When `ok` is `false`, Qwen Code will continue working and use the `reason` as co
|
|
|
235
235
|
|
|
236
236
|
Hooks fire at specific points during a Qwen Code session. Different events support different matchers to filter trigger conditions.
|
|
237
237
|
|
|
238
|
-
| Event | Triggered When | Matcher Target
|
|
239
|
-
| :------------------- | :---------------------------------------- |
|
|
240
|
-
| `PreToolUse` | Before tool execution | Tool
|
|
241
|
-
| `PostToolUse` | After successful tool execution | Tool
|
|
242
|
-
| `PostToolUseFailure` | After tool execution fails | Tool
|
|
243
|
-
| `UserPromptSubmit` | After user submits prompt | None (always fires)
|
|
244
|
-
| `SessionStart` | When session starts or resumes | Source (`startup`, `resume`, `clear`, `compact`)
|
|
245
|
-
| `SessionEnd` | When session ends | Reason (`clear`, `logout`, `prompt_input_exit`, etc.)
|
|
246
|
-
| `Stop` | When Claude prepares to conclude response | None (always fires)
|
|
247
|
-
| `SubagentStart` | When subagent starts | Agent type (`Bash`, `Explorer`, `Plan`, etc.)
|
|
248
|
-
| `SubagentStop` | When subagent stops | Agent type
|
|
249
|
-
| `PreCompact` | Before conversation compaction | Trigger (`manual`, `auto`)
|
|
250
|
-
| `Notification` | When notifications are sent | Type (`permission_prompt`, `idle_prompt`, `auth_success`)
|
|
251
|
-
| `PermissionRequest` | When permission dialog is shown | Tool
|
|
252
|
-
| `
|
|
253
|
-
| `
|
|
238
|
+
| Event | Triggered When | Matcher Target |
|
|
239
|
+
| :------------------- | :---------------------------------------- | :------------------------------------------------------------- |
|
|
240
|
+
| `PreToolUse` | Before tool execution | Tool id (`write_file`, `read_file`, `run_shell_command`, etc.) |
|
|
241
|
+
| `PostToolUse` | After successful tool execution | Tool id |
|
|
242
|
+
| `PostToolUseFailure` | After tool execution fails | Tool id |
|
|
243
|
+
| `UserPromptSubmit` | After user submits prompt | None (always fires) |
|
|
244
|
+
| `SessionStart` | When session starts or resumes | Source (`startup`, `resume`, `clear`, `compact`) |
|
|
245
|
+
| `SessionEnd` | When session ends | Reason (`clear`, `logout`, `prompt_input_exit`, etc.) |
|
|
246
|
+
| `Stop` | When Claude prepares to conclude response | None (always fires) |
|
|
247
|
+
| `SubagentStart` | When subagent starts | Agent type (`Bash`, `Explorer`, `Plan`, etc.) |
|
|
248
|
+
| `SubagentStop` | When subagent stops | Agent type |
|
|
249
|
+
| `PreCompact` | Before conversation compaction | Trigger (`manual`, `auto`) |
|
|
250
|
+
| `Notification` | When notifications are sent | Type (`permission_prompt`, `idle_prompt`, `auth_success`) |
|
|
251
|
+
| `PermissionRequest` | When permission dialog is shown | Tool id |
|
|
252
|
+
| `PermissionDenied` | When tool permission is denied | Tool id |
|
|
253
|
+
| `TodoCreated` | When a new todo item is created | None (always fires) |
|
|
254
|
+
| `TodoCompleted` | When a todo item is marked as completed | None (always fires) |
|
|
254
255
|
|
|
255
256
|
### Matcher Patterns
|
|
256
257
|
|
|
257
258
|
`matcher` is a regular expression used to filter trigger conditions.
|
|
258
259
|
|
|
259
|
-
| Event Type | Events
|
|
260
|
-
| :------------------ |
|
|
261
|
-
| Tool Events | `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest` | ✅ Regex | Tool
|
|
262
|
-
| Subagent Events | `SubagentStart`, `SubagentStop`
|
|
263
|
-
| Session Events | `SessionStart`
|
|
264
|
-
| Session Events | `SessionEnd`
|
|
265
|
-
| Notification Events | `Notification`
|
|
266
|
-
| Compact Events | `PreCompact`
|
|
267
|
-
| Todo Events | `TodoCreated`, `TodoCompleted`
|
|
268
|
-
| Prompt Events | `UserPromptSubmit`
|
|
269
|
-
| Stop Events | `Stop`
|
|
260
|
+
| Event Type | Events | Matcher Support | Matcher Target |
|
|
261
|
+
| :------------------ | :----------------------------------------------------------------------------------------- | :-------------- | :------------------------------------------------------------ |
|
|
262
|
+
| Tool Events | `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `PermissionDenied` | ✅ Regex | Tool id: `write_file`, `read_file`, `run_shell_command`, etc. |
|
|
263
|
+
| Subagent Events | `SubagentStart`, `SubagentStop` | ✅ Regex | Agent type: `Bash`, `Explorer`, etc. |
|
|
264
|
+
| Session Events | `SessionStart` | ✅ Regex | Source: `startup`, `resume`, `clear`, `compact` |
|
|
265
|
+
| Session Events | `SessionEnd` | ✅ Regex | Reason: `clear`, `logout`, `prompt_input_exit`, etc. |
|
|
266
|
+
| Notification Events | `Notification` | ✅ Exact match | Type: `permission_prompt`, `idle_prompt`, `auth_success` |
|
|
267
|
+
| Compact Events | `PreCompact` | ✅ Exact match | Trigger: `manual`, `auto` |
|
|
268
|
+
| Todo Events | `TodoCreated`, `TodoCompleted` | ❌ No | N/A |
|
|
269
|
+
| Prompt Events | `UserPromptSubmit` | ❌ No | N/A |
|
|
270
|
+
| Stop Events | `Stop` | ❌ No | N/A |
|
|
270
271
|
|
|
271
272
|
**Matcher Syntax:**
|
|
272
273
|
|
|
273
274
|
- Empty string `""` or `"*"` matches all events of that type
|
|
274
|
-
- Standard regex syntax supported (e.g., `^
|
|
275
|
+
- Standard regex syntax supported (e.g., `^run_shell_command$`, `read_.*`, `(write_file|edit)`)
|
|
276
|
+
- Tool hooks receive the runtime tool id in `tool_name` (for example, `write_file`). Built-in display names such as `WriteFile` and `ReadFile` are also accepted as matcher aliases for compatibility, but new configs should prefer runtime ids.
|
|
275
277
|
|
|
276
278
|
**Examples:**
|
|
277
279
|
|
|
@@ -280,7 +282,7 @@ Hooks fire at specific points during a Qwen Code session. Different events suppo
|
|
|
280
282
|
"hooks": {
|
|
281
283
|
"PreToolUse": [
|
|
282
284
|
{
|
|
283
|
-
"matcher": "^
|
|
285
|
+
"matcher": "^run_shell_command$",
|
|
284
286
|
"hooks": [
|
|
285
287
|
{
|
|
286
288
|
"type": "command",
|
|
@@ -289,7 +291,7 @@ Hooks fire at specific points during a Qwen Code session. Different events suppo
|
|
|
289
291
|
]
|
|
290
292
|
},
|
|
291
293
|
{
|
|
292
|
-
"matcher": "
|
|
294
|
+
"matcher": "write_.*",
|
|
293
295
|
"hooks": [
|
|
294
296
|
{
|
|
295
297
|
"type": "command",
|
|
@@ -1075,7 +1077,7 @@ Hooks are configured in Qwen Code settings, typically in `.qwen/settings.json` o
|
|
|
1075
1077
|
"hooks": {
|
|
1076
1078
|
"PreToolUse": [
|
|
1077
1079
|
{
|
|
1078
|
-
"matcher": "^
|
|
1080
|
+
"matcher": "^run_shell_command$",
|
|
1079
1081
|
"sequential": false,
|
|
1080
1082
|
"hooks": [
|
|
1081
1083
|
{
|
|
@@ -1128,7 +1130,7 @@ Only `command` type supports asynchronous execution. Setting `"async": true` run
|
|
|
1128
1130
|
"hooks": {
|
|
1129
1131
|
"PostToolUse": [
|
|
1130
1132
|
{
|
|
1131
|
-
"matcher": "
|
|
1133
|
+
"matcher": "write_file|edit",
|
|
1132
1134
|
"hooks": [
|
|
1133
1135
|
{
|
|
1134
1136
|
"type": "command",
|
|
@@ -91,7 +91,7 @@ Qwen doesn't save everything — only things that would actually be useful next
|
|
|
91
91
|
|
|
92
92
|
### Where it's stored
|
|
93
93
|
|
|
94
|
-
Auto-memory files live at `~/.qwen/projects/<project>/memory/`. All branches
|
|
94
|
+
Auto-memory files live at `~/.qwen/projects/<project>/memory/`. All branches of the same checkout share the same memory folder, so what Qwen learns in one branch is available in others. Each linked git worktree gets its own memory folder, matching the per-worktree isolation of chats and other session state — repository-wide conventions you want in every worktree belong in [team memory](#team-memory-shared-with-collaborators).
|
|
95
95
|
|
|
96
96
|
Everything saved is plain markdown — you can open, edit, or delete any file at any time.
|
|
97
97
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Tool-Use Summaries
|
|
2
2
|
|
|
3
|
-
Qwen Code can generate a short, git-commit-subject-style label after each tool batch completes, summarizing what the batch accomplished. The label appears inline in the
|
|
3
|
+
Qwen Code can generate a short, git-commit-subject-style label after each tool batch completes, summarizing what the batch accomplished. The label appears inline: for a completed tool group in the main view it replaces the generic `Tool × N` header; when the group is force-expanded (in the `Ctrl+O` full-detail transcript, or for error / user-initiated batches) it appears as a dim `● <label>` line below the group.
|
|
4
4
|
|
|
5
5
|
This is a UX aid for parallel tool calls: when the model fans out into several `Read` + `Grep` + `Bash` calls at once, the summary tells you the intent at a glance instead of forcing you to scan the tool list.
|
|
6
6
|
|
|
@@ -8,33 +8,32 @@ The feature is enabled by default and runs silently in the background. It requir
|
|
|
8
8
|
|
|
9
9
|
## What You See
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Main view (completed group)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
In the main transcript, a completed collapsible batch folds into a single labeled row — the summary replaces the generic `Tool × N` header:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
16
|
╭──────────────────────────────────────────────╮
|
|
17
|
-
|
|
18
|
-
│ ✓ ReadFile b.txt │
|
|
19
|
-
│ ✓ ReadFile c.txt │
|
|
20
|
-
│ ✓ ReadFile d.txt │
|
|
17
|
+
│✓ Read 4 text files │
|
|
21
18
|
╰──────────────────────────────────────────────╯
|
|
22
|
-
|
|
23
|
-
● Read 4 text files
|
|
24
19
|
```
|
|
25
20
|
|
|
26
|
-
|
|
21
|
+
The full per-tool output is a keystroke away: press `Ctrl+O` to open the full-detail transcript.
|
|
22
|
+
|
|
23
|
+
### Full-detail transcript (`Ctrl+O`) and force-expanded groups
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
When a group is force-expanded — in the `Ctrl+O` transcript, or for error / user-initiated batches in the main view — each tool renders individually and the summary appears as a dim badge line below the group:
|
|
29
26
|
|
|
30
27
|
```
|
|
31
28
|
╭──────────────────────────────────────────────╮
|
|
32
|
-
|
|
33
|
-
│
|
|
29
|
+
│ ✓ ReadFile a.txt │
|
|
30
|
+
│ ✓ ReadFile b.txt │
|
|
31
|
+
│ ✓ ReadFile c.txt │
|
|
32
|
+
│ ✓ ReadFile d.txt │
|
|
34
33
|
╰──────────────────────────────────────────────╯
|
|
35
|
-
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
● Read 4 text files
|
|
36
|
+
```
|
|
38
37
|
|
|
39
38
|
## How It Works
|
|
40
39
|
|
|
@@ -123,7 +122,7 @@ These settings can be configured in `settings.json`:
|
|
|
123
122
|
|
|
124
123
|
Three points that tend to trip up a first read of this feature:
|
|
125
124
|
|
|
126
|
-
1. **One generation per batch, shared by both display modes.** The fast-model call happens exactly once in `handleCompletedTools` when a tool batch finalizes.
|
|
125
|
+
1. **One generation per batch, shared by both display modes.** The fast-model call happens exactly once in `handleCompletedTools` when a tool batch finalizes. Opening the `Ctrl+O` transcript afterwards does **not** trigger a new call — both the main view and the full-detail transcript read from the same `tool_use_summary` history entry that was captured the first time.
|
|
127
126
|
2. **No backfill on toggle or on session resume.** A `tool_group` that completed before the feature was enabled (or before you flipped the setting on, or in a resumed session — `ChatRecordingService` does not persist summary entries) will never get a label. There is no "sweep existing history" pass. If you turn this setting on mid-session, only _future_ batches will show a label; older groups keep the default rendering with no indicator that a label is missing.
|
|
128
127
|
3. **Main-agent batches only.** The trigger lives in the main session's turn loop (`useGeminiStream`), so:
|
|
129
128
|
- ✅ Shell, MCP, file operations, and the `Task` / subagent tool _call itself_ (as it appears in the main batch) are summarized.
|
|
@@ -131,23 +130,20 @@ Three points that tend to trip up a first read of this feature:
|
|
|
131
130
|
|
|
132
131
|
An outer batch that _contains_ a `Task` tool will still be labeled, but the fast model sees only the subagent tool call and its aggregated output — not the individual tool calls inside the subagent. Expect labels like `Ran research-agent` or `Delegated file search` rather than `Searched 14 files`. This is intentional — summarizing subagent internals would multiply the fast-model cost and surface noise that never shows up in the primary UI.
|
|
133
132
|
|
|
134
|
-
##
|
|
133
|
+
## Display behavior
|
|
135
134
|
|
|
136
|
-
|
|
135
|
+
The main view already folds a completed collapsible batch into a single labeled row (`✓ Read 4 text files`) — the summary does the work of the old per-tool list. For full per-tool detail, press `Ctrl+O` to open the full-detail transcript, where each tool renders individually with the summary as a trailing `● <label>` line below the group.
|
|
137
136
|
|
|
138
137
|
```json
|
|
139
138
|
{
|
|
140
139
|
"fastModel": "qwen3-coder-flash",
|
|
141
|
-
"ui": {
|
|
142
|
-
"compactMode": true
|
|
143
|
-
},
|
|
144
140
|
"experimental": {
|
|
145
141
|
"emitToolUseSummaries": true
|
|
146
142
|
}
|
|
147
143
|
}
|
|
148
144
|
```
|
|
149
145
|
|
|
150
|
-
|
|
146
|
+
For small same-type batches (e.g. `Read × 3`) the expanded `● <label>` line can read as a restatement of the visible tool lines; if that matches your usual workflow you can turn the summary off entirely via `experimental.emitToolUseSummaries: false`.
|
|
151
147
|
|
|
152
148
|
## Monitoring
|
|
153
149
|
|
|
@@ -174,5 +170,5 @@ If you do not want the extra cost, turn the feature off via `experimental.emitTo
|
|
|
174
170
|
|
|
175
171
|
## Related
|
|
176
172
|
|
|
177
|
-
- [
|
|
173
|
+
- [Full-detail transcript](../configuration/settings#ui) — press `Ctrl+O` to open the frozen full-detail transcript; the summary replaces the generic tool-group header for completed groups in the main view.
|
|
178
174
|
- [Followup Suggestions](./followup-suggestions) — another fast-model-driven UX enhancement that shares the same `fastModel` setting.
|
|
@@ -15,7 +15,7 @@ Run Qwen Code as a local HTTP daemon so multiple clients (IDE plugins, web UIs,
|
|
|
15
15
|
- **Reconnect-safe streaming** — SSE with `Last-Event-ID` reconnect lets a client drop and pick up exactly where it left off (within the ring's replay window).
|
|
16
16
|
- **First-responder permissions** — when the agent asks for permission to run a tool, every connected client sees the request; whichever client answers first wins.
|
|
17
17
|
- **One daemon, one workspace** — each `qwen serve` process binds to exactly one workspace at boot (per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02). Multi-workspace deployments run one daemon per workspace on separate ports (or behind an orchestrator).
|
|
18
|
-
- **Experimental daemon-managed channels** — `qwen serve --channel <name>` starts a channel worker owned by the daemon lifecycle. The worker is a separate process, connects back to the daemon through the SDK, and reports its state in `GET /daemon/status`.
|
|
18
|
+
- **Experimental daemon-managed channels** — `qwen serve --channel <name>` starts a channel worker owned by the daemon lifecycle. The worker is a separate process, connects back to the daemon through the SDK, and reports its state in `GET /daemon/status`. After editing channel settings, reload it in place with `POST /workspace/channel/reload` (or `qwen channel reload`) — no full daemon restart needed.
|
|
19
19
|
- **Remote runtime control** ([#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 17) — change a session's approval mode (`POST /session/:id/approval-mode`), toggle a tool per workspace (`POST /workspace/tools/:name/enable`), scaffold an empty `QWEN.md` (`POST /workspace/init`, mechanical only — does NOT call the model; for AI-fill, follow up with `POST /session/:id/prompt`), restart a single MCP server with a budget pre-check (`POST /workspace/mcp/:server/restart`), or add/remove MCP servers at runtime without a daemon restart (`POST /workspace/mcp/servers`, `DELETE /workspace/mcp/servers/:name`). All strict-gated — configure `--token` first.
|
|
20
20
|
- **Session recap** ([#4175](https://github.com/QwenLM/qwen-code/issues/4175) follow-up) — fetch a one-sentence "where did I leave off" summary of an active session (`POST /session/:id/recap`). Wraps core's `generateSessionRecap` as a side-query against the fast model; pollutes neither the main chat history nor the SSE stream. Non-strict gate (same posture as `/prompt`); SDK helper `client.recapSession(sessionId)`.
|
|
21
21
|
- **Known limit — token-cost amplification:** the route is a pure-cost endpoint (each call is an LLM side-query, no state benefit) and the daemon has no per-route rate limit in v1. On a no-token loopback default a buggy or malicious local client can spam it to burn tokens. Configure `--token` (and optionally `--require-auth`) on shared dev hosts before exposing the daemon.
|
|
@@ -81,7 +81,7 @@ curl http://127.0.0.1:4170/daemon/status
|
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
The `workspaceCwd` field surfaces the bound workspace so clients can pre-flight check + omit `cwd` on `POST /session`.
|
|
84
|
-
The `limits.maxPendingPromptsPerSession` field advertises the active per-session prompt admission cap; `null` means the cap is disabled.
|
|
84
|
+
The `limits.maxPendingPromptsPerSession` field advertises the active per-session prompt admission cap; `null` means the cap is disabled. `limits.maxTotalSessions` advertises the optional daemon-wide fresh-session cap; `null` means unlimited.
|
|
85
85
|
|
|
86
86
|
### Run channels from the daemon
|
|
87
87
|
|
|
@@ -96,7 +96,9 @@ qwen serve --channel telegram --channel feishu
|
|
|
96
96
|
qwen serve --channel all
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
This mode is experimental and daemon-managed. It does not replace the standalone `qwen channel start` command: standalone channels still use the ACP-backed `AcpBridge` service. With `qwen serve --channel`, the daemon launches one channel worker process after the HTTP runtime is ready. If the worker
|
|
99
|
+
This mode is experimental and daemon-managed. It does not replace the standalone `qwen channel start` command: standalone channels still use the ACP-backed `AcpBridge` service. With `qwen serve --channel`, the daemon launches one channel worker process after the HTTP runtime is ready. If the worker crashes after startup, the daemon keeps running, relaunches it under a bounded restart policy, and reports its state (including `channel_worker_exited` warnings) in `GET /daemon/status`.
|
|
100
|
+
|
|
101
|
+
The daemon reads each channel's settings (tokens, `proxy`, per-channel `model`) from `settings.json` once, when the worker starts. To apply changes without restarting the whole daemon, call `POST /workspace/channel/reload` (strict-gated; SDK `client.reloadChannelWorker()`, or `qwen channel reload`). The daemon stops and relaunches the channel worker, which re-reads `settings.json`; every selected channel briefly disconnects and reconnects, and persisted threads are restored from disk. The route is advertised as the `channel_reload` capability only when the daemon was started with `--channel`. Adding a brand-new channel name to a `--channel <names>` selection still requires a daemon restart (or use `--channel all`, which picks up newly-configured channels on reload).
|
|
100
102
|
|
|
101
103
|
The daemon is bound to one workspace, so every selected channel's `cwd` must resolve to the daemon workspace. `--channel all` cannot be combined with named channels.
|
|
102
104
|
|
|
@@ -303,11 +305,13 @@ Notes:
|
|
|
303
305
|
| `--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. |
|
|
304
306
|
| `--tls-key <path>` | — | Path to a PEM private key file. Must be paired with `--tls-cert`. |
|
|
305
307
|
| `--max-sessions <n>` | `20` | Cap on concurrent live sessions. New `POST /session` requests that would spawn a fresh child return `503` (with `Retry-After: 5`) when the cap is hit; attaches to existing sessions are NOT counted. Set to `0` to disable. Sized for single-user / small-team usage; raise it if your deployment has the RAM/FD headroom (~30–50 MB per session). |
|
|
308
|
+
| `--max-total-sessions <n>` | unlimited | Optional non-negative integer daemon-wide cap on fresh session creation across the runtime. It applies to new child sessions, session restore, and branch/fork-created sessions; attaching to an existing live session does not consume a slot. Set to `0` or omit the flag for unlimited. This is a guardrail for future multi-workspace sessions and does not enable multi-workspace serving by itself. |
|
|
306
309
|
| `--max-pending-prompts-per-session <n>` | `5` | Per-session cap on prompts accepted by `POST /session/:id/prompt` but not yet settled, including queued prompts and the active prompt. The bridge rejects overflow synchronously with `503`, `Retry-After: 5`, and `code: "prompt_queue_full"` before returning a `promptId`. Set to `0` to disable. `branchSession` serializes on the same FIFO but does not count against this prompt cap. |
|
|
307
310
|
| `--workspace <path>` | `process.cwd()` | Absolute workspace path this daemon binds to (per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02 — 1 daemon = 1 workspace). `POST /session` requests with a mismatched `cwd` return `400 workspace_mismatch`. For multi-workspace deployments, run one `qwen serve` per workspace on separate ports. |
|
|
308
311
|
| `--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 the daemon workspace. The worker is owned by `qwen serve`; stop the daemon to stop serve-managed channels. |
|
|
309
312
|
| `--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. |
|
|
310
313
|
| `--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`. |
|
|
314
|
+
| `--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` remains uncapped. 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. |
|
|
311
315
|
| `--mcp-client-budget <n>` | — | Positive integer cap on live MCP clients **per ACP session** (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14 v1; PR 23 graduates this to per-workspace via the shared MCP pool). Combine with `--mcp-budget-mode`. When unset, no accounting-driven enforcement (but `GET /workspace/mcp` still reports `clientCount`). Distinct from claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` which gates startup concurrency, not the total client count. Pre-flight `caps.features.mcp_guardrails`. |
|
|
312
316
|
| `--mcp-budget-mode <m>` | `warn` / `off` | How `--mcp-client-budget` is enforced. `warn` (default when budget set): no refusal, snapshot's `budgets[0].status` flips to `warning` at ≥75% of budget. `enforce`: connects past the cap are refused, per-server cell shows `disabledReason: 'budget'`, deterministic by `mcpServers` declaration order. `off` (default when budget unset): pure observability. Boot rejects `enforce` without a budget. |
|
|
313
317
|
| `--http-bridge` | `true` | Stage 1 mode: one `qwen --acp` child per daemon (bound to one workspace at boot, per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02); N sessions multiplex onto that child via ACP `newSession()`. Stage 2 native in-process becomes available later. |
|
|
@@ -315,7 +319,7 @@ Notes:
|
|
|
315
319
|
| `--web` / `--no-web` | `true` | Serve the built Web Shell SPA at the daemon root (`GET /`, `/assets/*`, and SPA deep-link fallback). The static shell is registered **before** the bearer-auth gate — a browser can't attach a token to a `<script>` subresource or an address-bar navigation, the shell carries no secrets, and every API route stays token-gated regardless. 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). |
|
|
316
320
|
| `--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. |
|
|
317
321
|
|
|
318
|
-
> **Sizing the load knobs.** `--max-sessions` is the **new-child** cap.
|
|
322
|
+
> **Sizing the load knobs.** `--max-sessions` is the per-workspace **new-child** cap. `--max-total-sessions`, when set, is the daemon-wide fresh-session cap.
|
|
319
323
|
> Three other layers also limit load — when sizing for a high-concurrency
|
|
320
324
|
> deployment, tune them together:
|
|
321
325
|
>
|
|
@@ -327,11 +331,16 @@ Notes:
|
|
|
327
331
|
> - **per-session prompt admissions**:
|
|
328
332
|
> `--max-pending-prompts-per-session=5` bounds queued + active prompts
|
|
329
333
|
> accepted for one session. Overflow gets `503` with `Retry-After: 5`.
|
|
334
|
+
> - **daemon-wide fresh sessions**: `--max-total-sessions=N` bounds fresh
|
|
335
|
+
> session creation across the daemon. Overflow gets the same
|
|
336
|
+
> `session_limit_exceeded` shape with `scope: "total"`.
|
|
330
337
|
> - **per-subscriber backlog**: a 256-frame queue per SSE client; an
|
|
331
338
|
> over-capacity client gets a terminal `client_evicted` frame and is
|
|
332
339
|
> closed (one slow consumer can't pin the daemon).
|
|
333
340
|
>
|
|
334
|
-
> These caps interact: `--max-sessions
|
|
341
|
+
> These caps interact: the lower of `--max-sessions` and
|
|
342
|
+
> `--max-total-sessions` bounds fresh sessions in today's single-workspace
|
|
343
|
+
> daemon. `--max-sessions × 64 subscribers × 256 frames`
|
|
335
344
|
> is the worst-case in-flight memory at the EventBus layer, while
|
|
336
345
|
> `--max-sessions × --max-pending-prompts-per-session` bounds accepted
|
|
337
346
|
> prompt work at the admission layer. Default sizing assumes single-user /
|
|
@@ -359,6 +368,7 @@ Notes:
|
|
|
359
368
|
- **`LOOPBACK_BINDS` includes IPv6** — `::1` and `[::1]` count as loopback for the no-token rule.
|
|
360
369
|
- **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.
|
|
361
370
|
- **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.
|
|
371
|
+
- **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.
|
|
362
372
|
- **Spawned `qwen --acp` child inherits the daemon's environment** with one explicit scrub: `QWEN_SERVER_TOKEN` is removed before the child starts (the daemon's own bearer; the agent doesn't need it). Everything else — `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `QWEN_*` / `DASHSCOPE_API_KEY` / your custom `modelProviders[].envKey` / etc. — passes through, because the agent legitimately needs those to authenticate to the LLM. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc` / `~/.aws/credentials` / `~/.npmrc` is reachable by prompt injection regardless. The env passthrough is not the security boundary; the user-as-trust-root is. Don't run `qwen serve` under an identity that has env-resident credentials you wouldn't trust the agent with.
|
|
363
373
|
- **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.
|
|
364
374
|
- **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.
|
|
@@ -415,10 +425,10 @@ To handle multiple **users** (each with their own quota, audit log, sandbox) or
|
|
|
415
425
|
|
|
416
426
|
The daemon exposes ACP's `session/load` and resume flow over HTTP via two routes:
|
|
417
427
|
|
|
418
|
-
| Route | Use when
|
|
419
|
-
| -------------------------- |
|
|
420
|
-
| `POST /session/:id/load` | The client has **no** history rendered (cold reconnect, picker-then-open).
|
|
421
|
-
| `POST /session/:id/resume` | The client already has the turns on screen and only needs the daemon-side handle back. Model context is restored on the agent side without UI replay — the SSE stream stays clean. Capability tag: `session_resume` (`unstable_session_resume` remains a deprecated alias for older clients).
|
|
428
|
+
| Route | Use when |
|
|
429
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
430
|
+
| `POST /session/:id/load` | The client has **no** useful local history rendered (cold reconnect, picker-then-open). For a live session, the daemon returns and injects the current bounded replay snapshot window; if older replay was dropped, the snapshot begins with `history_truncated`. Capability tag: `session_load`. |
|
|
431
|
+
| `POST /session/:id/resume` | The client already has the turns on screen and only needs the daemon-side handle back. Model context is restored on the agent side without UI replay — the SSE stream stays clean. Capability tag: `session_resume` (`unstable_session_resume` remains a deprecated alias for older clients). |
|
|
422
432
|
|
|
423
433
|
The TypeScript SDK exposes both as static factories on `DaemonSessionClient`:
|
|
424
434
|
|
|
@@ -427,7 +437,7 @@ import { DaemonClient, DaemonSessionClient } from '@qwen-code/sdk';
|
|
|
427
437
|
|
|
428
438
|
const client = new DaemonClient({ baseUrl: 'http://127.0.0.1:4170' });
|
|
429
439
|
|
|
430
|
-
// Cold reconnect — daemon will replay
|
|
440
|
+
// Cold reconnect — daemon will replay the bounded snapshot window through SSE.
|
|
431
441
|
const session = await DaemonSessionClient.load(client, 'persisted-id');
|
|
432
442
|
|
|
433
443
|
// Or, if your UI already has the history, skip the replay:
|
|
@@ -441,7 +451,7 @@ for await (const event of session.events()) {
|
|
|
441
451
|
|
|
442
452
|
Pre-flight `caps.features.session_load` / `caps.features.session_resume` before calling — 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.
|
|
443
453
|
|
|
444
|
-
Note: history replay is bounded by the SSE ring
|
|
454
|
+
Note: live-session history replay is bounded twice: by the SSE ring for `Last-Event-ID` reconnects and by `--compacted-replay-max-bytes` for the snapshot returned by `POST /session/:id/load`. Long histories with chatty turns can exceed either bound. The daemon surfaces snapshot truncation with `history_truncated`; full transcript access is intentionally not a one-shot array response in this API. For very long sessions, prefer `resume` and rely on the client's local persisted UI until a paginated or streaming transcript endpoint is available.
|
|
445
455
|
|
|
446
456
|
## Durability model
|
|
447
457
|
|
|
@@ -449,7 +459,7 @@ Note: history replay is bounded by the SSE ring (default 8000 frames). Long hist
|
|
|
449
459
|
|
|
450
460
|
- A child process crash publishes `session_died` and removes the live session from the daemon's maps. The persisted on-disk session **can** be reloaded via `POST /session/:id/load` if a fresh agent child is spawnable.
|
|
451
461
|
- A daemon restart loses every in-flight live session. The persisted sessions remain on disk and can be loaded against a new daemon process, subject to the same workspace binding rules.
|
|
452
|
-
- Long client disconnects (>5 min on a chatty turn) can outrun the SSE replay ring (default 8000 frames) — `Last-Event-ID` reconnect
|
|
462
|
+
- Long client disconnects (>5 min on a chatty turn) can outrun the SSE replay ring (default 8000 frames) — `Last-Event-ID` reconnect triggers `state_resync_required`. For mobile / flaky-network clients, plan to re-open SSE on long drops or call `POST /session/:id/load` to recover the current bounded replay snapshot; do not assume that route returns the full transcript.
|
|
453
463
|
- File operations (`writeTextFile`) are atomic across crashes (write-then-rename); they aren't atomic across daemon restarts in the sense of replaying — the file write either landed or it didn't.
|
|
454
464
|
|
|
455
465
|
If your integration needs server-side cross-restart durability beyond what `session/load` covers (e.g. server-managed retry queues), you still need application-level state recovery. Don't hold long-running, restart-sensitive state inside the daemon's session.
|
|
@@ -10,7 +10,7 @@ This document lists the available keyboard shortcuts in Qwen Code.
|
|
|
10
10
|
| `Ctrl+C` | Cancel the ongoing request and clear the input. Press twice to exit the application. |
|
|
11
11
|
| `Ctrl+D` | Exit the application if the input is empty. Press twice to confirm. |
|
|
12
12
|
| `Ctrl+L` | Clear the screen. |
|
|
13
|
-
| `Ctrl+O` |
|
|
13
|
+
| `Ctrl+O` | Open/close the full-detail transcript view (a scrollable, frozen snapshot showing every tool's complete output and full thinking). Press again, or `Esc`/`q`, to close. |
|
|
14
14
|
| `Ctrl+S` | Allows long responses to print fully, disabling truncation. Use your terminal's scrollback to view the entire output. |
|
|
15
15
|
| `Ctrl+T` | Toggle the display of tool descriptions. |
|
|
16
16
|
| `Ctrl+B` | While a foreground shell command is running: promote it to a background task. The child keeps running, the agent's turn unblocks, and the shell appears in `/tasks` + the Background tasks dialog. No-op when no shell is executing — Ctrl+B then falls through to its prompt-area binding (cursor-left). |
|
package/bundled/review/DESIGN.md
CHANGED
|
@@ -228,28 +228,29 @@ Key implementation detail: Step 7 must use the owner/repo extracted from the URL
|
|
|
228
228
|
|
|
229
229
|
**Decision:** Auto-discovery. Every project already defines its tool chain in CI config. Reading those files leverages existing knowledge without asking users to duplicate it. The LLM is capable of parsing YAML workflow files and extracting the relevant commands. Falls back gracefully: if no CI config exists, the build/test discovery is simply skipped and LLM agents still review the diff.
|
|
230
230
|
|
|
231
|
-
## Why Suggestion-level findings
|
|
231
|
+
## Why Suggestion-level findings are posted as inline comments, like Critical
|
|
232
232
|
|
|
233
233
|
**Considered:**
|
|
234
234
|
|
|
235
|
-
- **
|
|
236
|
-
- **Critical inline, Suggestion in
|
|
237
|
-
- **
|
|
235
|
+
- **Critical inline, Suggestion in the review `body`:** splits by severity, but the review body is a frozen artifact of one review submission — every new /review run appends a new review with its own body, so Suggestion lists accumulate across runs and never converge.
|
|
236
|
+
- **Critical inline, Suggestion in one updatable issue comment:** Suggestion findings go to a single PR issue comment located by author + embedded marker and PATCHed in place on every run, so the list refreshes rather than grows. Shipped for a while; reverted for the reasons below.
|
|
237
|
+
- **Both severities inline, distinguished by a `**[Critical]**`/`**[Suggestion]**` body prefix (chosen):** every high-confidence finding is pinned to its code line and carries a one-click ` ```suggestion ` block. Severity is communicated in the comment text, not by the channel it arrives on.
|
|
238
238
|
|
|
239
|
-
**Decision:**
|
|
239
|
+
**Decision:** Both inline. The updatable-summary design optimized for a convergence problem, but it paid for that with two costs that turned out to dominate:
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
1. **A summary comment can never collapse.** GitHub marks an inline review thread **Outdated** and folds it away as soon as the author edits the line it is anchored to. So an addressed inline finding removes itself from the page. An issue comment has no such lifecycle — it sits in the PR conversation permanently, one extra comment whether or not its rows still apply. PATCHing it to "all suggestions addressed" replaces the content but not the comment. The very mechanism intended to prevent clutter _was_ the clutter.
|
|
242
|
+
2. **A Markdown table cannot carry a one-click fix.** GitHub renders a ` ```suggestion ` fence as an applicable change only inside a review comment on a diff line; in an issue comment it degrades to a plain code block. Suggestion-level findings — mechanical, localized cleanups — are precisely the class that benefits most from one-click apply, so the split withheld the feature from the findings that most needed it. The table's cramped "Suggested fix" column also degraded badly as the suggestion count grew.
|
|
242
243
|
|
|
243
|
-
|
|
244
|
+
The convergence concern that motivated the summary is real but narrower than it looked: GitHub's Outdated-collapse handles every suggestion the author actually acts on, which is the common case. What remains is a suggestion the author declines and leaves untouched — its line does not change, so the thread stays open and a later run can post a near-duplicate. That residue is bounded by the presubmit Overlap check (`blockOnExistingComments`), which blocks submission when a new finding lands on the same `(path, line)` as a live Qwen comment on the same commit.
|
|
244
245
|
|
|
245
246
|
**Trade-off:**
|
|
246
247
|
|
|
247
|
-
- ✅
|
|
248
|
-
- ✅
|
|
249
|
-
- ✅
|
|
250
|
-
- ❌
|
|
251
|
-
-
|
|
252
|
-
- ❌ Pattern-aggregated Suggestion findings (the multi-occurrence `Pattern:` form)
|
|
248
|
+
- ✅ Suggestion findings regain one-click ` ```suggestion ` apply and sit next to the code in "Files changed."
|
|
249
|
+
- ✅ Addressed findings self-collapse via GitHub's Outdated mechanism; no permanent extra comment on the PR page.
|
|
250
|
+
- ✅ One posting path for both severities — the `comments` array — instead of a review submission plus a second issue-comment API call.
|
|
251
|
+
- ❌ Suggestions now share the atomic `POST /pulls/{n}/reviews` call with Criticals. That call is all-or-nothing: one entry anchored to a line outside the diff 422s the whole review, so a mis-anchored Suggestion can suppress a Critical blocker. Previously Suggestions travelled on a separate, line-agnostic issue-comment call where a bad anchor was impossible. Step 7 mitigates with a 422 fallback rather than pre-validating every anchor up front: GitHub's 422 does not identify the offending entry, so the fallback has the model recheck each anchor against the diff, relocate failing Criticals into `body` (failing Suggestions are discarded — Suggestion text must stay off the `body` channel, which `qwen-autofix.yml` does not filter), and resubmit — degrading to an all-prose review of the blockers rather than posting nothing.
|
|
252
|
+
- ❌ A declined suggestion on an unchanged line can be re-posted by a later run on a new commit: the presubmit Overlap check only compares against comments whose `commit_id` matches the commit under review, so prior comments are bucketed `stale` after any push. Closing this fully needs a resolve/minimize step (GraphQL `resolveReviewThread` / `minimizeComment`) that folds our own superseded threads before submitting a new review.
|
|
253
|
+
- ❌ Pattern-aggregated Suggestion findings (the multi-occurrence `Pattern:` form) must pick a representative line to anchor to; the full structured aggregation remains visible in the terminal output.
|
|
253
254
|
|
|
254
255
|
## Rejected alternatives
|
|
255
256
|
|