@qwen-code/qwen-code 0.19.9 → 0.19.10-nightly.20260716.506ce0a1a
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/docs/configuration/settings.md +14 -6
- package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +33 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +64 -20
- package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
- package/bundled/qc-helper/docs/features/code-review.md +88 -44
- package/bundled/qc-helper/docs/features/commands.md +6 -6
- package/bundled/qc-helper/docs/features/hooks.md +29 -0
- package/bundled/qc-helper/docs/features/sandbox.md +2 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
- package/bundled/qc-helper/docs/qwen-serve.md +49 -20
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +219 -33
- package/bundled/review/SKILL.md +429 -382
- package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-WOC3YDWA.js} +31 -32
- package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-H5HZCAFD.js} +49 -48
- package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-55YDJDNM.js} +922 -550
- package/chunks/{agent-HOLHB3RT.js → agent-H6VE5W3L.js} +26 -27
- package/chunks/{agent-headless-SXL6H56A.js → agent-headless-T4XJOCRU.js} +26 -27
- package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-HBRXJSP4.js} +78 -16
- package/chunks/{artifact-tool-U7IRTLIV.js → artifact-tool-MIZLXBLF.js} +2 -2
- package/chunks/{askUserQuestion-2DLUUZZG.js → askUserQuestion-XMJVPNWM.js} +2 -2
- package/chunks/{bridge-BCJQ7BBB.js → bridge-FTB6ZP3R.js} +31 -34
- package/chunks/{ca-UJ6HC4H2.js → ca-CODEN7TD.js} +9 -1
- package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
- package/chunks/channel-worker-manager-CUDPU4CN.js +418 -0
- package/chunks/channel-worker-supervisor-4XTO2ZD3.js +20 -0
- package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
- package/chunks/{chunk-VA4KQY6V.js → chunk-2JNR4VP2.js} +3 -3
- package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
- package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
- package/chunks/{chunk-CUMMSHH6.js → chunk-3DWIFU7L.js} +1 -1
- package/chunks/chunk-3MX7D6QN.js +516 -0
- package/chunks/{chunk-SJHDYNHF.js → chunk-4BJVSIS3.js} +3 -3
- package/chunks/{chunk-TO6QE22P.js → chunk-5CNYZ7TN.js} +26 -22
- package/chunks/{chunk-N3EMS75V.js → chunk-5DEJ4T6C.js} +1333 -1232
- package/chunks/chunk-5HBA2Z7V.js +28 -0
- package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
- package/chunks/{chunk-SCGXUJBT.js → chunk-6LI3L22E.js} +3 -3
- package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
- package/chunks/{chunk-YAUFFXDS.js → chunk-7GM2RWCR.js} +12 -11
- package/chunks/{chunk-OQ4DRIOA.js → chunk-7HWE2W74.js} +2 -2
- package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
- package/chunks/{chunk-MC23XKFE.js → chunk-A2HWMJVO.js} +37 -3
- package/chunks/{chunk-3G7CIHVV.js → chunk-ABNYOMDG.js} +4 -4
- package/chunks/{chunk-3AHXV67U.js → chunk-AGZLXLBY.js} +1 -1
- package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
- package/chunks/{chunk-Q4YQW46J.js → chunk-AMRZVQUY.js} +43 -40
- package/chunks/{chunk-W3JHSWRP.js → chunk-AN6C2U46.js} +4 -4
- package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
- package/chunks/{chunk-5SFOMFG4.js → chunk-AVEOWVOM.js} +36 -2
- package/chunks/{chunk-34MW4KTI.js → chunk-BA5JGE5F.js} +2 -2
- package/chunks/{chunk-5HOMWMCL.js → chunk-BSJAQUFD.js} +5492 -1336
- package/chunks/{chunk-L6P4KPHR.js → chunk-BWJKL5DB.js} +58 -38
- package/chunks/{chunk-PVZM22CK.js → chunk-C32JFRGV.js} +5 -5
- package/chunks/{chunk-AKIVHSJR.js → chunk-CZIHPO7L.js} +163 -782
- package/chunks/chunk-DL7RCO6V.js +493 -0
- package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
- package/chunks/{chunk-5VXNZWGF.js → chunk-ENUQSKEY.js} +1 -1
- package/chunks/{chunk-PDZ7MBDG.js → chunk-EWILX3BM.js} +27 -6
- package/chunks/{chunk-BMGVRZN4.js → chunk-EZWX232B.js} +1 -1
- package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
- package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
- package/chunks/chunk-FEOZBUMT.js +77 -0
- package/chunks/{chunk-5U27BZ72.js → chunk-FKEGVMPX.js} +269 -83
- package/chunks/chunk-FNX3LGAK.js +34 -0
- package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
- package/chunks/{chunk-PODM4SZ4.js → chunk-G3BIBPI7.js} +5 -5
- package/chunks/{chunk-A3XKDTSH.js → chunk-GA65O2TB.js} +4 -4
- package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
- package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-GXGIM7QP.js} +67 -35
- package/chunks/{chunk-6PESIEKJ.js → chunk-GXUWGPYX.js} +68 -6
- package/chunks/chunk-GYTKQYDB.js +23 -0
- package/chunks/{chunk-GZRTYZ2R.js → chunk-H3XMJV7T.js} +218 -1
- package/chunks/{chunk-WQUQVGTF.js → chunk-HGRXW4HQ.js} +467 -106
- package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
- package/chunks/{chunk-ECNYL4AA.js → chunk-HUEWOHKV.js} +1 -1
- package/chunks/chunk-IDS7MSUP.js +74 -0
- package/chunks/{chunk-KHUQZZJ6.js → chunk-IHDRJLLR.js} +382 -36
- package/chunks/{chunk-CLFKOZEK.js → chunk-J4SEAF4X.js} +114 -4
- package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
- package/chunks/{chunk-P67PFTUT.js → chunk-KEYEYCHZ.js} +4 -4
- package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
- package/chunks/{chunk-7PU4FYLG.js → chunk-KOXFAG6P.js} +4 -18
- package/chunks/{chunk-EGYZ275M.js → chunk-KWLVWNF5.js} +55 -7
- package/chunks/{chunk-XLA62MYB.js → chunk-KXECVZPD.js} +2 -2
- package/chunks/{chunk-IAVB3HM3.js → chunk-L4Y55KIS.js} +33 -1
- package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
- package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
- package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
- package/chunks/chunk-LXXMOYPL.js +22 -0
- package/chunks/{chunk-Q6I5QHMH.js → chunk-MFNKBXYH.js} +1 -1
- package/chunks/chunk-MR3PXB6E.js +48 -0
- package/chunks/{chunk-JZETEN3Z.js → chunk-N45S36AH.js} +3 -3
- package/chunks/{chunk-GWLSNBG4.js → chunk-NA3IG6XG.js} +748 -27
- package/chunks/{chunk-D5SKC4YG.js → chunk-O3M25JXE.js} +213 -29
- package/chunks/{chunk-EAXLGSFP.js → chunk-O6XGHDS5.js} +11 -11
- package/chunks/{chunk-WL4L7EZH.js → chunk-OA4JVLSA.js} +27 -1
- package/chunks/{chunk-X4NKFGFJ.js → chunk-OJAMDVF5.js} +0 -15
- package/chunks/{chunk-BZIFY5TF.js → chunk-OKAIGAYW.js} +3 -3
- package/chunks/{chunk-CNEIYWSA.js → chunk-OVIV236K.js} +5 -5
- package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
- package/chunks/{chunk-E2IY465S.js → chunk-PWNOAWXB.js} +59 -12
- package/chunks/{chunk-B4G2WOFA.js → chunk-Q5MKHNIR.js} +28 -5
- package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
- package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
- package/chunks/{chunk-HKMAENAO.js → chunk-QDTGDM2T.js} +14 -9
- package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
- package/chunks/{chunk-W2UIXQDL.js → chunk-RTV5TUYB.js} +12 -4
- package/chunks/chunk-RW7DUKFO.js +91 -0
- package/chunks/{chunk-NVYTCB5Z.js → chunk-SA6QVLWI.js} +17325 -16259
- package/chunks/chunk-SJSI7PXU.js +59 -0
- package/chunks/{chunk-HVY356M2.js → chunk-SMGBWLNU.js} +3 -3
- package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
- package/chunks/{chunk-CC2ITGCF.js → chunk-STZQCNN3.js} +49 -6
- package/chunks/{chunk-HPDUL5MF.js → chunk-T2ZDAER2.js} +1 -1
- package/chunks/{chunk-XUOOWUZS.js → chunk-T3TQ3ACP.js} +1 -1
- package/chunks/{chunk-4C5BQ2D2.js → chunk-TIKDHS6V.js} +100 -17
- package/chunks/chunk-TV6K2FB4.js +224 -0
- package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
- package/chunks/{chunk-D2GFWEXB.js → chunk-UCUUH2JV.js} +6 -6
- package/chunks/{chunk-BAPGSC7U.js → chunk-UZP7K33Y.js} +23 -9
- package/chunks/{chunk-77XJ3SWN.js → chunk-VDAR6UO2.js} +8 -6
- package/chunks/{chunk-XYQSMABS.js → chunk-VKLVGA2D.js} +4 -4
- package/chunks/{chunk-JSG7ZSBC.js → chunk-VRR65QYW.js} +251 -3
- package/chunks/{chunk-U2NNEY4R.js → chunk-VT5AWJN4.js} +1 -1
- package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
- package/chunks/{chunk-X6TJ3YZV.js → chunk-WKEO3GLZ.js} +160 -60
- package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
- package/chunks/{chunk-VWPVHAMO.js → chunk-XIWQ5QST.js} +8 -1
- package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
- package/chunks/{chunk-3VAGG5T5.js → chunk-YYBZUIPL.js} +1015 -100
- package/chunks/{chunk-CCDMCZPP.js → chunk-YZ3SBNP7.js} +1 -1
- package/chunks/{chunk-ATAKVRIF.js → chunk-Z3XA2TNG.js} +7 -7
- package/chunks/{chunk-EMDMPBJ4.js → chunk-Z7SVC7PJ.js} +10 -3
- package/chunks/{chunk-AURZZYMD.js → chunk-ZIVSSTUG.js} +4 -4
- package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
- package/chunks/{chunk-34Z3U5RQ.js → chunk-ZQIYGQCG.js} +765 -168
- package/chunks/{computer-use-HM37RX6A.js → computer-use-NADT7ULB.js} +26 -27
- package/chunks/{config-utils-NV2SVGPB.js → config-utils-IQQT3GCI.js} +3 -2
- package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-U7NEJYJ7.js} +28 -29
- package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
- package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-SUN33INC.js} +26 -27
- package/chunks/{cron-create-AMBKGZX6.js → cron-create-GMVKSXZT.js} +4 -4
- package/chunks/{cron-delete-LRU4OJYG.js → cron-delete-VDZKUAVK.js} +4 -4
- package/chunks/{cron-list-WVP2JXER.js → cron-list-UG7C7RAR.js} +4 -4
- package/chunks/{daemon-ARHTSTXP.js → daemon-SJXEKP3H.js} +773 -126
- package/chunks/daemon-status-provider-WIIYLGZJ.js +74 -0
- package/chunks/{de-EBJN3OVN.js → de-NOXPCSYN.js} +9 -1
- package/chunks/{dist-XKU3ABM5.js → dist-4WCQEZIN.js} +4 -51
- package/chunks/{dist-QYCAEZIT.js → dist-DOPL5LSQ.js} +5 -1
- package/chunks/{dist-WKPOYU7O.js → dist-GXJVCOS7.js} +1 -1
- package/chunks/{dist-R7LN5AZE.js → dist-PX2ERZ6I.js} +2 -2
- package/chunks/{dist-PNVLTKTL.js → dist-V2YVLYOW.js} +215 -33
- package/chunks/{dist-VHV4EVHG.js → dist-VYWUKURL.js} +1 -1
- package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-6FRM6UMU.js} +27 -28
- package/chunks/{edit-VNI4NJ73.js → edit-7GOIQTCZ.js} +27 -28
- package/chunks/{en-5A6LA7RK.js → en-JFVULHTB.js} +11 -1
- package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-476E6WIK.js} +26 -27
- package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-IRJM6W3C.js} +42 -28
- package/chunks/{environment-5HSSRMJ7.js → environment-ROMULS2X.js} +30 -30
- package/chunks/{errors-HMFCJJ7P.js → errors-OUIWPUDY.js} +28 -29
- package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-PPSFK753.js} +26 -27
- package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-YKQMD4D7.js} +26 -27
- package/chunks/{fast-path-FRDMDVHG.js → fast-path-CNK2HHKH.js} +3 -3
- package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
- package/chunks/{fr-YXRABLYZ.js → fr-HVFNU42H.js} +9 -1
- package/chunks/{gemini-QYSEGHAX.js → gemini-WQNFT6TR.js} +216 -90
- package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-4QJH2JDP.js} +4 -4
- package/chunks/{glob-BRCSGFOT.js → glob-36TVLBWW.js} +28 -28
- package/chunks/{grep-EE2DUOSY.js → grep-QTYLNO2M.js} +26 -27
- package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-36FQFODK.js} +30 -31
- package/chunks/{i18n-BASPENNQ.js → i18n-JUGYPVSP.js} +27 -28
- package/chunks/initializer-OBBJUS25.js +72 -0
- package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-MCKTPX64.js} +27 -28
- package/chunks/{ja-7VQOANVG.js → ja-PY5AF544.js} +10 -2
- package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
- package/chunks/list-VW5QY4VJ.js +75 -0
- package/chunks/loadedSettingsAdapter-IELOOXG6.js +69 -0
- package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-QXWZSCYM.js} +5 -5
- package/chunks/{ls-ZB2BDP6T.js → ls-2OUTG3IZ.js} +4 -4
- package/chunks/{lsp-V5DN4YUJ.js → lsp-4VMNXZW6.js} +2 -2
- package/chunks/mcp-Q3EC37ZS.js +69 -0
- package/chunks/{monitor-X5Z3H4FY.js → monitor-DCZ27AFR.js} +26 -27
- package/chunks/nonInteractiveCli-KXD7PFO4.js +128 -0
- package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-YU4XF5LI.js} +27 -28
- package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KL5WER2D.js} +13 -13
- package/chunks/{pidfile-D4I4FTVA.js → pidfile-WBOD7EJV.js} +27 -28
- package/chunks/processUtils-AOV4R34M.js +29 -0
- package/chunks/{pt-2C6YCSHL.js → pt-A3PRQXMU.js} +9 -1
- package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-YIGBHYE3.js} +28 -29
- package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
- package/chunks/{read-file-7SZSIZOL.js → read-file-WVL4Y76X.js} +9 -9
- package/chunks/{read-mcp-resource-SM5DA4RG.js → read-mcp-resource-JUFHCKSC.js} +2 -2
- package/chunks/{record-artifact-4XKZX3UW.js → record-artifact-DWSMBXYY.js} +2 -2
- package/chunks/{ripGrep-YNPFVCZP.js → ripGrep-6GSWJERP.js} +26 -27
- package/chunks/{ru-6BBHVZZV.js → ru-IBCWUTOC.js} +9 -1
- package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-QYUQMEDT.js} +1233 -371
- package/chunks/{runtime-57WWRVHN.js → runtime-K2YZCNB3.js} +42 -38
- package/chunks/{scheduler-YBLGWSIL.js → scheduler-EQCSN7QV.js} +26 -27
- package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
- package/chunks/{serve-R63NK3CV.js → serve-DX5UGZD4.js} +36 -35
- package/chunks/{server-Z22GCAXP.js → server-T6HJH3DR.js} +5869 -1398
- package/chunks/{session-HKAAI7BN.js → session-SNU6ACY6.js} +299 -100
- package/chunks/{settings-3EYN66GK.js → settings-AKHZZNEL.js} +34 -33
- package/chunks/{shell-6YXINTWJ.js → shell-EY74IEZK.js} +28 -27
- package/chunks/{skill-OO57P4X6.js → skill-DPU62O3H.js} +11 -11
- package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-RQZRWJ2V.js} +28 -30
- package/chunks/{src-G5UPLZSZ.js → src-7FITDSVC.js} +164 -52
- package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-XO3RK6DO.js} +28 -29
- package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-DVWZRHYQ.js} +728 -382
- package/chunks/{syntheticOutput-34H7LGA7.js → syntheticOutput-LELY6HAI.js} +3 -3
- package/chunks/{task-create-FRGOEIKY.js → task-create-QY3BIMNM.js} +8 -7
- package/chunks/{task-list-OW766BXZ.js → task-list-D2U47WBJ.js} +6 -5
- package/chunks/{task-stop-SIR5SNBN.js → task-stop-N6E5IYLH.js} +2 -2
- package/chunks/{task-update-YRA532MT.js → task-update-HJCQILLB.js} +8 -7
- package/chunks/{team-create-PECAAPXK.js → team-create-FOSRT62K.js} +26 -27
- package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
- package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-6VUDV27J.js} +26 -27
- package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-6UT6IO5T.js} +27 -28
- package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
- package/chunks/{tool-search-THVIWAPB.js → tool-search-ASSFMMN5.js} +10 -10
- package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-YYWUO23H.js} +32 -35
- package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
- package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-4BWV2IBK.js} +29 -29
- package/chunks/types-ML3TRJQ5.js +16 -0
- package/chunks/update-relaunch-74DLGH73.js +87 -0
- package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-CRFCGFO5.js} +31 -30
- package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-BTTEPBGQ.js} +76 -73
- package/chunks/{version-3UEA6ZIR.js → version-Y5JE5Q63.js} +1 -1
- package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-CFCWTCAP.js} +5 -6
- package/chunks/{workflow-QCCCMYP3.js → workflow-6WC7VPQN.js} +27 -28
- package/chunks/workspace-providers-status-RVG2C5ZS.js +72 -0
- package/chunks/workspace-registration-store-SLEU3D3X.js +27 -0
- package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-QMWGVOTF.js} +32 -35
- package/chunks/workspace-service-G572JSEU.js +84 -0
- package/chunks/workspace-skills-status-VSSMSMNK.js +71 -0
- package/chunks/{write-file-I3MUDRIE.js → write-file-5XVDRORP.js} +27 -28
- package/chunks/{zh-RQE7I22T.js → zh-PAUNIMHQ.js} +12 -2
- package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-GNEUIUFF.js} +12 -2
- package/cli-entry.js +92 -8
- package/cli.js +11 -11
- package/locales/ca.js +16 -0
- package/locales/de.js +16 -0
- package/locales/en.js +19 -0
- package/locales/fr.js +16 -0
- package/locales/ja.js +17 -1
- package/locales/pt.js +16 -0
- package/locales/ru.js +16 -0
- package/locales/zh-TW.js +20 -1
- package/locales/zh.js +20 -1
- package/package.json +3 -3
- package/web-shell/assets/{arc-C15hqnJe.js → arc-vx1tRwnX.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-DBi6iUA1.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-Ga9JJ4Ak.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-D8Vi5FYw.js} +1 -1
- package/web-shell/assets/channel-B29zQDTL.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-CSV6yQpU.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-toYlppdI.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-DbjzuyAr.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-IkkSjSkk.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-D5wUL6Zm.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-C3o2DXG0.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CutIi14T.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-DZ0NRHH-.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BNGI2SvC.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BNGI2SvC.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-B3Dl88UJ.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-DfTxfF6-.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-CJyH98yO.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-EbOiJNmW.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-AYNqpqqA.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BY5VPa4H.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-BhMYAKlk.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-Bp8S_F9l.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-az3TE9PU.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-CfkAEpCe.js} +3 -3
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-D1QmjMCy.js} +1 -1
- package/web-shell/assets/index-C8sDwQUv.js +1130 -0
- package/web-shell/assets/index-CaBoc5bb.js +3 -0
- package/web-shell/assets/index-Dpg5Wymg.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-D3ompLrG.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-D3MRWp9I.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-DVkKCa44.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-BLif81wF.js} +1 -1
- package/web-shell/assets/{linear-C8wKCbIC.js → linear-BDU96EGS.js} +1 -1
- package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-B-CwC26B.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-CS1WOJ4G.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-BzgtNXVP.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-BRfGC8MA.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-CPBZkC7g.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-nqNvinIk.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-CM_Wdjh3.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-L0y-48VE.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BX1DdF8s.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-B_n5rb3A.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-C9NmLV5e.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-CrefK9gt.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BUccf-bC.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-DM6ef92l.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-524RQP4Q.js +0 -305
- package/chunks/chunk-CARU2RR2.js +0 -24
- package/chunks/chunk-CU3L64TP.js +0 -93
- package/chunks/chunk-OCPBI7J5.js +0 -18
- package/chunks/chunk-TEGEBB2I.js +0 -122
- package/chunks/chunk-VTU57BWZ.js +0 -30
- package/chunks/daemon-status-provider-B2UTZUJ2.js +0 -76
- package/chunks/initializer-UTQ7FB7G.js +0 -71
- package/chunks/list-DEICDL65.js +0 -74
- package/chunks/loadedSettingsAdapter-NOWEGDYJ.js +0 -68
- package/chunks/mcp-L5JXEEIA.js +0 -68
- package/chunks/nonInteractiveCli-LS2K4X6A.js +0 -124
- package/chunks/types-JNKGKUJT.js +0 -12
- package/chunks/workspace-providers-status-4KMGETOJ.js +0 -71
- package/chunks/workspace-service-RVLBMSMZ.js +0 -80
- package/chunks/workspace-skills-status-DS4ZVFTO.js +0 -70
- package/web-shell/assets/channel-CLiQD50f.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-D3sYqow5.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-D3sYqow5.js +0 -1
- package/web-shell/assets/index-D5IWFVk1.css +0 -5
- package/web-shell/assets/index-KFJRDhX7.js +0 -783
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BhQMwgpl.js +0 -1
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import {
|
|
4
4
|
formatHistoryGapNotice,
|
|
5
5
|
indexGapsByChild
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VT5AWJN4.js";
|
|
7
|
+
import {
|
|
8
|
+
sanitizeTerminalText
|
|
9
|
+
} from "./chunk-MFNKBXYH.js";
|
|
7
10
|
import {
|
|
8
11
|
require_undici
|
|
9
12
|
} from "./chunk-L573Z2QZ.js";
|
|
@@ -12,13 +15,18 @@ import {
|
|
|
12
15
|
} from "./chunk-YUZI3WAC.js";
|
|
13
16
|
import {
|
|
14
17
|
getActiveGoal
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-SA6QVLWI.js";
|
|
19
|
+
import {
|
|
20
|
+
apiActivityTracker,
|
|
21
|
+
formatVisionBridgeNoticeDisplay,
|
|
22
|
+
isVisionBridgeNoticeDisplay
|
|
23
|
+
} from "./chunk-YYBZUIPL.js";
|
|
16
24
|
import {
|
|
17
25
|
ToolNames
|
|
18
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JGUT3LWZ.js";
|
|
19
27
|
import {
|
|
20
28
|
createDebugLogger
|
|
21
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-7NFB7LBQ.js";
|
|
22
30
|
import {
|
|
23
31
|
init_esbuild_shims
|
|
24
32
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -27,1435 +35,1516 @@ import {
|
|
|
27
35
|
__toESM
|
|
28
36
|
} from "./chunk-J2S4EL5Y.js";
|
|
29
37
|
|
|
30
|
-
// packages/cli/src/
|
|
31
|
-
init_esbuild_shims();
|
|
32
|
-
|
|
33
|
-
// packages/cli/src/acp-integration/session/emitters/MessageEmitter.ts
|
|
38
|
+
// packages/cli/src/services/setup-github.ts
|
|
34
39
|
init_esbuild_shims();
|
|
40
|
+
var import_undici2 = __toESM(require_undici(), 1);
|
|
41
|
+
import { promises as fsp } from "node:fs";
|
|
42
|
+
import * as path from "node:path";
|
|
35
43
|
|
|
36
|
-
// packages/cli/src/
|
|
44
|
+
// packages/cli/src/utils/gitUtils.ts
|
|
37
45
|
init_esbuild_shims();
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
var import_undici = __toESM(require_undici(), 1);
|
|
47
|
+
import * as childProcess from "node:child_process";
|
|
48
|
+
var debugLogger = createDebugLogger("GIT");
|
|
49
|
+
async function runGit(args, opts = {}) {
|
|
50
|
+
return await new Promise((resolve2, reject) => {
|
|
51
|
+
childProcess.execFile(
|
|
52
|
+
"git",
|
|
53
|
+
args,
|
|
54
|
+
{
|
|
55
|
+
encoding: "utf-8",
|
|
56
|
+
...opts.cwd ? { cwd: opts.cwd } : {}
|
|
57
|
+
},
|
|
58
|
+
(err, stdout) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
reject(err);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
resolve2(String(stdout ?? "").trim());
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
__name(runGit, "runGit");
|
|
69
|
+
var isGitHubRepositoryAsync = /* @__PURE__ */ __name(async (opts = {}) => {
|
|
70
|
+
try {
|
|
71
|
+
const remotes = await runGit(["remote", "-v"], opts);
|
|
72
|
+
return remotes.split("\n").some((line) => {
|
|
73
|
+
const remoteUrl = line.trim().split(/\s+/)[1];
|
|
74
|
+
return remoteUrl ? isGitHubRemoteUrl(remoteUrl) : false;
|
|
75
|
+
});
|
|
76
|
+
} catch (_error) {
|
|
77
|
+
debugLogger.debug(`Failed to get git remote:`, _error);
|
|
78
|
+
return false;
|
|
41
79
|
}
|
|
42
|
-
|
|
43
|
-
|
|
80
|
+
}, "isGitHubRepositoryAsync");
|
|
81
|
+
function isGitHubRemoteUrl(remoteUrl) {
|
|
82
|
+
if (remoteUrl.startsWith("git@github.com:")) {
|
|
83
|
+
return true;
|
|
44
84
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
85
|
+
if (remoteUrl.startsWith("git@")) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
return new URL(remoteUrl).hostname === "github.com";
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
__name(isGitHubRemoteUrl, "isGitHubRemoteUrl");
|
|
95
|
+
var getGitRepoRootAsync = /* @__PURE__ */ __name(async (opts = {}) => {
|
|
96
|
+
const gitRepoRoot = await runGit(["rev-parse", "--show-toplevel"], opts);
|
|
97
|
+
if (!gitRepoRoot) {
|
|
98
|
+
throw new Error(`Git repo returned empty value`);
|
|
99
|
+
}
|
|
100
|
+
return gitRepoRoot;
|
|
101
|
+
}, "getGitRepoRootAsync");
|
|
102
|
+
var getLatestGitHubRelease = /* @__PURE__ */ __name(async (proxy) => {
|
|
103
|
+
try {
|
|
104
|
+
const controller = new AbortController();
|
|
105
|
+
const endpoint = `https://api.github.com/repos/QwenLM/qwen-code-action/releases/latest`;
|
|
106
|
+
const response = await fetch(endpoint, {
|
|
107
|
+
method: "GET",
|
|
108
|
+
headers: {
|
|
109
|
+
Accept: "application/vnd.github+json",
|
|
110
|
+
"Content-Type": "application/json",
|
|
111
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
112
|
+
},
|
|
113
|
+
dispatcher: proxy ? new import_undici.ProxyAgent(proxy) : void 0,
|
|
114
|
+
signal: AbortSignal.any([AbortSignal.timeout(3e4), controller.signal])
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Invalid response code: ${response.status} - ${response.statusText}`
|
|
119
|
+
);
|
|
52
120
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
121
|
+
const releaseTag = (await response.json()).tag_name;
|
|
122
|
+
if (!releaseTag) {
|
|
123
|
+
throw new Error(`Response did not include tag_name field`);
|
|
56
124
|
}
|
|
57
|
-
return
|
|
125
|
+
return releaseTag;
|
|
126
|
+
} catch (_error) {
|
|
127
|
+
debugLogger.debug(
|
|
128
|
+
`Failed to determine latest qwen-code-action release:`,
|
|
129
|
+
_error
|
|
130
|
+
);
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Unable to determine the latest qwen-code-action release on GitHub.`
|
|
133
|
+
);
|
|
58
134
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
135
|
+
}, "getLatestGitHubRelease");
|
|
136
|
+
async function getGitHubRepoInfoAsync(opts = {}) {
|
|
137
|
+
return parseGitHubRepoInfo(
|
|
138
|
+
await runGit(["remote", "get-url", "origin"], opts)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
__name(getGitHubRepoInfoAsync, "getGitHubRepoInfoAsync");
|
|
142
|
+
function parseGitHubRepoInfo(remoteUrl) {
|
|
143
|
+
let urlToParse = remoteUrl;
|
|
144
|
+
if (remoteUrl.startsWith("git@github.com:")) {
|
|
145
|
+
urlToParse = remoteUrl.replace("git@github.com:", "");
|
|
146
|
+
} else if (remoteUrl.startsWith("git@")) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
149
|
+
);
|
|
69
150
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
151
|
+
let parsedUrl;
|
|
152
|
+
try {
|
|
153
|
+
parsedUrl = new URL(urlToParse, "https://github.com");
|
|
154
|
+
} catch {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
157
|
+
);
|
|
75
158
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return this.ctx.sessionId;
|
|
159
|
+
if (parsedUrl.hostname !== "github.com") {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
162
|
+
);
|
|
81
163
|
}
|
|
82
|
-
|
|
164
|
+
const parts = parsedUrl.pathname.split("/").filter((part) => part !== "");
|
|
165
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return { owner: parts[0], repo: parts[1].replace(/\.git$/, "") };
|
|
171
|
+
}
|
|
172
|
+
__name(parseGitHubRepoInfo, "parseGitHubRepoInfo");
|
|
83
173
|
|
|
84
|
-
// packages/cli/src/
|
|
85
|
-
var
|
|
174
|
+
// packages/cli/src/services/setup-github.ts
|
|
175
|
+
var debugLogger2 = createDebugLogger("SETUP_GITHUB");
|
|
176
|
+
var GITHUB_WORKFLOW_PATHS = [
|
|
177
|
+
"qwen-dispatch/qwen-dispatch.yml",
|
|
178
|
+
"qwen-assistant/qwen-invoke.yml",
|
|
179
|
+
"issue-triage/qwen-triage.yml",
|
|
180
|
+
"issue-triage/qwen-scheduled-triage.yml",
|
|
181
|
+
"pr-review/qwen-review.yml"
|
|
182
|
+
];
|
|
183
|
+
var GITIGNORE_ENTRIES = [".qwen/", "gha-creds-*.json"];
|
|
184
|
+
var MAX_WORKFLOW_DOWNLOAD_BYTES = 5 * 1024 * 1024;
|
|
185
|
+
var SetupGithubError = class extends Error {
|
|
86
186
|
static {
|
|
87
|
-
__name(this, "
|
|
187
|
+
__name(this, "SetupGithubError");
|
|
88
188
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
sessionUpdate: "agent_message_chunk",
|
|
101
|
-
content: { type: "text", text: "" },
|
|
102
|
-
_meta: {
|
|
103
|
-
stopHookLoop: {
|
|
104
|
-
iterationCount,
|
|
105
|
-
reasons,
|
|
106
|
-
stopHookCount,
|
|
107
|
-
...activeGoal ? {
|
|
108
|
-
goal: {
|
|
109
|
-
condition: activeGoal.condition,
|
|
110
|
-
iterations: activeGoal.iterations,
|
|
111
|
-
setAt: activeGoal.setAt,
|
|
112
|
-
lastReason: activeGoal.lastReason
|
|
113
|
-
}
|
|
114
|
-
} : {}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
189
|
+
code;
|
|
190
|
+
status;
|
|
191
|
+
partial;
|
|
192
|
+
partialResult;
|
|
193
|
+
constructor(code, message, status, partialResult) {
|
|
194
|
+
super(message);
|
|
195
|
+
this.name = "SetupGithubError";
|
|
196
|
+
this.code = code;
|
|
197
|
+
this.status = status;
|
|
198
|
+
this.partial = partialResult !== void 0;
|
|
199
|
+
this.partialResult = partialResult;
|
|
118
200
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
201
|
+
};
|
|
202
|
+
var nodeFileOps = {
|
|
203
|
+
assertCanWrite() {
|
|
204
|
+
},
|
|
205
|
+
async ensureWorkflowDirectory(gitRepoRoot) {
|
|
206
|
+
await fsp.mkdir(path.join(gitRepoRoot, ".github", "workflows"), {
|
|
207
|
+
recursive: true
|
|
126
208
|
});
|
|
127
|
-
}
|
|
128
|
-
async
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
209
|
+
},
|
|
210
|
+
async writeTextFile(gitRepoRoot, relativePath, content) {
|
|
211
|
+
const target = path.join(gitRepoRoot, relativePath);
|
|
212
|
+
await fsp.writeFile(target, content, { mode: 420 });
|
|
213
|
+
return { sizeBytes: Buffer.byteLength(content, "utf8") };
|
|
214
|
+
},
|
|
215
|
+
async readTextFile(gitRepoRoot, relativePath) {
|
|
216
|
+
try {
|
|
217
|
+
return await fsp.readFile(path.join(gitRepoRoot, relativePath), "utf8");
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (error.code === "ENOENT") {
|
|
220
|
+
return void 0;
|
|
134
221
|
}
|
|
135
|
-
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
136
224
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
...epochMs != null ? { timestamp: epochMs } : {},
|
|
147
|
-
...options.source ? { source: options.source } : {}
|
|
148
|
-
};
|
|
149
|
-
await this.sendUpdate({
|
|
150
|
-
sessionUpdate: "user_message_chunk",
|
|
151
|
-
content: { type: "text", text },
|
|
152
|
-
...Object.keys(_meta).length > 0 ? { _meta } : {}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Emits an agent thought chunk.
|
|
157
|
-
*
|
|
158
|
-
* @param text - The thought text content
|
|
159
|
-
* @param timestamp - Optional server-side timestamp (ISO string or ms) for message ordering
|
|
160
|
-
*/
|
|
161
|
-
async emitAgentThought(text, timestamp, subagentMeta) {
|
|
162
|
-
const _meta = this.buildChunkMeta(
|
|
163
|
-
BaseEmitter.toEpochMs(timestamp),
|
|
164
|
-
subagentMeta
|
|
225
|
+
};
|
|
226
|
+
async function setupGithub(options = {}) {
|
|
227
|
+
const cwd = options.cwd ?? process.cwd();
|
|
228
|
+
const fileOps = options.fileOps ?? nodeFileOps;
|
|
229
|
+
if (!await isGitHubRepositoryAsync({ cwd })) {
|
|
230
|
+
throw new SetupGithubError(
|
|
231
|
+
"github_repository_not_found",
|
|
232
|
+
"Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
|
|
233
|
+
400
|
|
165
234
|
);
|
|
166
|
-
await this.sendUpdate({
|
|
167
|
-
sessionUpdate: "agent_thought_chunk",
|
|
168
|
-
content: { type: "text", text },
|
|
169
|
-
..._meta ? { _meta } : {}
|
|
170
|
-
});
|
|
171
235
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
subagentMeta
|
|
236
|
+
let gitRepoRoot;
|
|
237
|
+
try {
|
|
238
|
+
gitRepoRoot = await getGitRepoRootAsync({ cwd });
|
|
239
|
+
} catch (error) {
|
|
240
|
+
debugLogger2.debug("Failed to get git repo root:", error);
|
|
241
|
+
throw new SetupGithubError(
|
|
242
|
+
"github_repository_not_found",
|
|
243
|
+
"Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
|
|
244
|
+
400
|
|
182
245
|
);
|
|
183
|
-
await this.sendUpdate({
|
|
184
|
-
sessionUpdate: "agent_message_chunk",
|
|
185
|
-
content: { type: "text", text },
|
|
186
|
-
..._meta ? { _meta } : {}
|
|
187
|
-
});
|
|
188
246
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
};
|
|
200
|
-
const cumulative = this.ctx.cumulativeUsage;
|
|
201
|
-
if (cumulative) {
|
|
202
|
-
const addFinite = /* @__PURE__ */ __name((total, value) => typeof value === "number" && Number.isFinite(value) ? total + value : total, "addFinite");
|
|
203
|
-
cumulative.promptTokens = addFinite(
|
|
204
|
-
cumulative.promptTokens,
|
|
205
|
-
usage.inputTokens
|
|
247
|
+
if (options.workspaceRoot) {
|
|
248
|
+
const [gitRootReal, workspaceReal] = await Promise.all([
|
|
249
|
+
realpathOrResolve(gitRepoRoot),
|
|
250
|
+
realpathOrResolve(options.workspaceRoot)
|
|
251
|
+
]);
|
|
252
|
+
if (gitRootReal !== workspaceReal) {
|
|
253
|
+
throw new SetupGithubError(
|
|
254
|
+
"github_git_root_mismatch",
|
|
255
|
+
"The Git repository root must match the daemon workspace root.",
|
|
256
|
+
400
|
|
206
257
|
);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
fileOps.assertCanWrite?.();
|
|
261
|
+
let releaseTag;
|
|
262
|
+
try {
|
|
263
|
+
releaseTag = await getLatestGitHubRelease(options.proxy);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
writeStderrLine(
|
|
266
|
+
`qwen setup-github: failed to determine latest qwen-code-action release: ${error instanceof Error ? error.message : String(error)}`
|
|
267
|
+
);
|
|
268
|
+
debugLogger2.debug(
|
|
269
|
+
"Failed to determine latest qwen-code-action release:",
|
|
270
|
+
error
|
|
271
|
+
);
|
|
272
|
+
throw new SetupGithubError(
|
|
273
|
+
"github_release_lookup_failed",
|
|
274
|
+
"Unable to determine the latest qwen-code-action release on GitHub.",
|
|
275
|
+
502
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
const readmeUrl = `https://github.com/QwenLM/qwen-code-action/blob/${releaseTag}/README.md#quick-start`;
|
|
279
|
+
const secretsUrl = await resolveSecretsUrl(cwd);
|
|
280
|
+
const downloads = await downloadWorkflows({
|
|
281
|
+
releaseTag,
|
|
282
|
+
proxy: options.proxy,
|
|
283
|
+
abortSignal: options.abortSignal,
|
|
284
|
+
fetchImpl: options.fetchImpl ?? fetch
|
|
285
|
+
});
|
|
286
|
+
const result = {
|
|
287
|
+
kind: "github_setup",
|
|
288
|
+
workspaceCwd: options.workspaceRoot ?? gitRepoRoot,
|
|
289
|
+
gitRepoRoot,
|
|
290
|
+
releaseTag,
|
|
291
|
+
readmeUrl,
|
|
292
|
+
...secretsUrl ? { secretsUrl } : {},
|
|
293
|
+
workflows: [],
|
|
294
|
+
gitignore: { path: ".gitignore", status: "skipped" },
|
|
295
|
+
warnings: []
|
|
296
|
+
};
|
|
297
|
+
result.gitignore = await updateGitignore(gitRepoRoot, fileOps);
|
|
298
|
+
if (result.gitignore.status === "failed") {
|
|
299
|
+
result.warnings.push("Failed to update .gitignore.");
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
await fileOps.ensureWorkflowDirectory(gitRepoRoot);
|
|
303
|
+
for (const workflow of downloads) {
|
|
304
|
+
const relativePath = path.posix.join(
|
|
305
|
+
".github",
|
|
306
|
+
"workflows",
|
|
307
|
+
path.posix.basename(workflow.sourcePath)
|
|
210
308
|
);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
309
|
+
try {
|
|
310
|
+
const write = await fileOps.writeTextFile(
|
|
311
|
+
gitRepoRoot,
|
|
312
|
+
relativePath,
|
|
313
|
+
workflow.content
|
|
314
|
+
);
|
|
315
|
+
result.workflows.push({
|
|
316
|
+
sourcePath: workflow.sourcePath,
|
|
317
|
+
path: relativePath,
|
|
318
|
+
status: "written",
|
|
319
|
+
sizeBytes: write.sizeBytes
|
|
320
|
+
});
|
|
321
|
+
} catch (error) {
|
|
322
|
+
result.partial = true;
|
|
323
|
+
result.workflows.push({
|
|
324
|
+
sourcePath: workflow.sourcePath,
|
|
325
|
+
path: relativePath,
|
|
326
|
+
status: "failed",
|
|
327
|
+
error: error instanceof Error ? error.message : String(error)
|
|
328
|
+
});
|
|
329
|
+
throw new SetupGithubError(
|
|
330
|
+
"github_workflow_write_failed",
|
|
331
|
+
`Unable to write ${relativePath}.`,
|
|
332
|
+
500,
|
|
333
|
+
result
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (error instanceof SetupGithubError) throw error;
|
|
339
|
+
throw new SetupGithubError(
|
|
340
|
+
"github_workflow_write_failed",
|
|
341
|
+
"Unable to create .github/workflows.",
|
|
342
|
+
500,
|
|
343
|
+
result
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
__name(setupGithub, "setupGithub");
|
|
349
|
+
async function updateGitignore(gitRepoRoot, fileOps = nodeFileOps) {
|
|
350
|
+
try {
|
|
351
|
+
const existingContent = await fileOps.readTextFile(
|
|
352
|
+
gitRepoRoot,
|
|
353
|
+
".gitignore"
|
|
354
|
+
);
|
|
355
|
+
if (existingContent === void 0) {
|
|
356
|
+
const content = GITIGNORE_ENTRIES.join("\n") + "\n";
|
|
357
|
+
await fileOps.writeTextFile(gitRepoRoot, ".gitignore", content);
|
|
358
|
+
return {
|
|
359
|
+
path: ".gitignore",
|
|
360
|
+
status: "created",
|
|
361
|
+
added: [...GITIGNORE_ENTRIES]
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const missingEntries = GITIGNORE_ENTRIES.filter(
|
|
365
|
+
(entry) => !existingContent.split(/\r?\n/).some((line) => line.split("#")[0].trim() === entry)
|
|
366
|
+
);
|
|
367
|
+
if (missingEntries.length === 0) {
|
|
368
|
+
return { path: ".gitignore", status: "unchanged" };
|
|
369
|
+
}
|
|
370
|
+
const nextContent = existingContent + "\n" + missingEntries.join("\n") + "\n";
|
|
371
|
+
await fileOps.writeTextFile(gitRepoRoot, ".gitignore", nextContent);
|
|
372
|
+
return {
|
|
373
|
+
path: ".gitignore",
|
|
374
|
+
status: "updated",
|
|
375
|
+
added: missingEntries
|
|
376
|
+
};
|
|
377
|
+
} catch (error) {
|
|
378
|
+
debugLogger2.debug("Failed to update .gitignore:", error);
|
|
379
|
+
return {
|
|
380
|
+
path: ".gitignore",
|
|
381
|
+
status: "failed",
|
|
382
|
+
error: error instanceof Error ? error.message : String(error)
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
__name(updateGitignore, "updateGitignore");
|
|
387
|
+
async function downloadWorkflows(options) {
|
|
388
|
+
const internalAbort = new AbortController();
|
|
389
|
+
try {
|
|
390
|
+
const dispatcher = options.proxy ? new import_undici2.ProxyAgent(options.proxy) : void 0;
|
|
391
|
+
return await Promise.all(
|
|
392
|
+
GITHUB_WORKFLOW_PATHS.map(async (workflow) => {
|
|
393
|
+
const endpoint = `https://raw.githubusercontent.com/QwenLM/qwen-code-action/refs/tags/${options.releaseTag}/examples/workflows/${workflow}`;
|
|
394
|
+
const response = await options.fetchImpl(endpoint, {
|
|
395
|
+
method: "GET",
|
|
396
|
+
dispatcher,
|
|
397
|
+
signal: AbortSignal.any([
|
|
398
|
+
AbortSignal.timeout(3e4),
|
|
399
|
+
internalAbort.signal,
|
|
400
|
+
...options.abortSignal ? [options.abortSignal] : []
|
|
401
|
+
])
|
|
402
|
+
});
|
|
403
|
+
if (!response.ok) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
`Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
sourcePath: workflow,
|
|
410
|
+
content: await readResponseTextWithLimit(response, workflow)
|
|
411
|
+
};
|
|
412
|
+
})
|
|
413
|
+
);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
internalAbort.abort();
|
|
416
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
417
|
+
debugLogger2.debug("Failed to download qwen-code-action workflows:", error);
|
|
418
|
+
throw new SetupGithubError(
|
|
419
|
+
"github_workflow_download_failed",
|
|
420
|
+
`Unable to download qwen-code-action workflows from GitHub. ${message}`,
|
|
421
|
+
502
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
__name(downloadWorkflows, "downloadWorkflows");
|
|
426
|
+
async function readResponseTextWithLimit(response, sourcePath) {
|
|
427
|
+
const contentLength = response.headers.get("content-length");
|
|
428
|
+
if (contentLength !== null) {
|
|
429
|
+
const parsedLength = Number(contentLength);
|
|
430
|
+
if (Number.isFinite(parsedLength) && parsedLength > MAX_WORKFLOW_DOWNLOAD_BYTES) {
|
|
431
|
+
throw new Error(
|
|
432
|
+
`${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
|
|
214
433
|
);
|
|
215
|
-
cumulative.apiTimeMs = addFinite(cumulative.apiTimeMs, durationMs);
|
|
216
434
|
}
|
|
217
|
-
const meta = typeof durationMs === "number" ? { usage, durationMs, ...subagentMeta } : { usage, ...subagentMeta };
|
|
218
|
-
await this.sendUpdate({
|
|
219
|
-
sessionUpdate: "agent_message_chunk",
|
|
220
|
-
content: { type: "text", text },
|
|
221
|
-
_meta: meta
|
|
222
|
-
});
|
|
223
435
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
436
|
+
if (!response.body) return "";
|
|
437
|
+
const reader = response.body.getReader();
|
|
438
|
+
const chunks = [];
|
|
439
|
+
let totalBytes = 0;
|
|
440
|
+
try {
|
|
441
|
+
while (true) {
|
|
442
|
+
const { done, value } = await reader.read();
|
|
443
|
+
if (done) break;
|
|
444
|
+
if (!value) continue;
|
|
445
|
+
totalBytes += value.byteLength;
|
|
446
|
+
if (totalBytes > MAX_WORKFLOW_DOWNLOAD_BYTES) {
|
|
447
|
+
await reader.cancel().catch(() => {
|
|
448
|
+
});
|
|
449
|
+
throw new Error(
|
|
450
|
+
`${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
chunks.push(value);
|
|
236
454
|
}
|
|
237
|
-
|
|
455
|
+
} finally {
|
|
456
|
+
reader.releaseLock();
|
|
238
457
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
245
|
-
return Object.keys(meta).length > 0 ? meta : void 0;
|
|
458
|
+
const body = new Uint8Array(totalBytes);
|
|
459
|
+
let offset = 0;
|
|
460
|
+
for (const chunk of chunks) {
|
|
461
|
+
body.set(chunk, offset);
|
|
462
|
+
offset += chunk.byteLength;
|
|
246
463
|
}
|
|
247
|
-
|
|
464
|
+
return new TextDecoder().decode(body);
|
|
465
|
+
}
|
|
466
|
+
__name(readResponseTextWithLimit, "readResponseTextWithLimit");
|
|
467
|
+
async function resolveSecretsUrl(cwd) {
|
|
468
|
+
try {
|
|
469
|
+
const repoInfo = await getGitHubRepoInfoAsync({ cwd });
|
|
470
|
+
return `https://github.com/${repoInfo.owner}/${repoInfo.repo}/settings/secrets/actions`;
|
|
471
|
+
} catch {
|
|
472
|
+
return void 0;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
__name(resolveSecretsUrl, "resolveSecretsUrl");
|
|
476
|
+
async function realpathOrResolve(input) {
|
|
477
|
+
try {
|
|
478
|
+
return await fsp.realpath(input);
|
|
479
|
+
} catch {
|
|
480
|
+
return path.resolve(input);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
__name(realpathOrResolve, "realpathOrResolve");
|
|
248
484
|
|
|
249
|
-
// packages/cli/src/acp-integration/session/emitters/
|
|
485
|
+
// packages/cli/src/acp-integration/session/emitters/MessageEmitter.ts
|
|
250
486
|
init_esbuild_shims();
|
|
251
487
|
|
|
252
|
-
// packages/cli/src/acp-integration/session/emitters/
|
|
488
|
+
// packages/cli/src/acp-integration/session/emitters/base-emitter.ts
|
|
253
489
|
init_esbuild_shims();
|
|
254
|
-
var
|
|
255
|
-
|
|
256
|
-
|
|
490
|
+
var BaseEmitter = class {
|
|
491
|
+
constructor(ctx) {
|
|
492
|
+
this.ctx = ctx;
|
|
257
493
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
*
|
|
261
|
-
* @param todos - Array of todo items to send as plan entries
|
|
262
|
-
*/
|
|
263
|
-
async emitPlan(todos) {
|
|
264
|
-
const entries = todos.map((todo) => ({
|
|
265
|
-
content: todo.content,
|
|
266
|
-
priority: "medium",
|
|
267
|
-
// Default priority since todos don't have priority
|
|
268
|
-
status: todo.status
|
|
269
|
-
}));
|
|
270
|
-
const cumulative = this.ctx.cumulativeUsage;
|
|
271
|
-
await this.sendUpdate({
|
|
272
|
-
sessionUpdate: "plan",
|
|
273
|
-
entries,
|
|
274
|
-
...cumulative ? { _meta: { stats: { ...cumulative } } } : {}
|
|
275
|
-
});
|
|
494
|
+
static {
|
|
495
|
+
__name(this, "BaseEmitter");
|
|
276
496
|
}
|
|
277
497
|
/**
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* 1. Result display object with type 'todo_list'
|
|
281
|
-
* 2. Result display as JSON string
|
|
282
|
-
* 3. Args with 'todos' array
|
|
283
|
-
*
|
|
284
|
-
* @param resultDisplay - The tool result display (object, string, or undefined)
|
|
285
|
-
* @param args - The tool call arguments (fallback source)
|
|
286
|
-
* @returns Array of todos if found, null otherwise
|
|
498
|
+
* Converts an ISO timestamp string or epoch ms to epoch ms number.
|
|
499
|
+
* Returns undefined if the input is not a valid timestamp.
|
|
287
500
|
*/
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (args && Array.isArray(args["todos"])) {
|
|
292
|
-
return args["todos"];
|
|
501
|
+
static toEpochMs(ts) {
|
|
502
|
+
if (typeof ts === "number") {
|
|
503
|
+
return Number.isFinite(ts) ? ts : void 0;
|
|
293
504
|
}
|
|
294
|
-
|
|
505
|
+
if (typeof ts === "string") {
|
|
506
|
+
const ms = new Date(ts).getTime();
|
|
507
|
+
return Number.isFinite(ms) ? ms : void 0;
|
|
508
|
+
}
|
|
509
|
+
return void 0;
|
|
295
510
|
}
|
|
296
511
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
512
|
+
* Sends a session update to the ACP client.
|
|
513
|
+
* If a message rewriter is configured, updates pass through it first
|
|
514
|
+
* (original messages are sent as-is, rewritten versions are appended).
|
|
299
515
|
*/
|
|
300
|
-
|
|
301
|
-
if (
|
|
302
|
-
|
|
303
|
-
const obj = resultDisplay;
|
|
304
|
-
if (obj["type"] === "todo_list" && Array.isArray(obj["todos"])) {
|
|
305
|
-
return obj["todos"];
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
if (typeof resultDisplay === "string") {
|
|
309
|
-
try {
|
|
310
|
-
const parsed = JSON.parse(resultDisplay);
|
|
311
|
-
if (parsed?.["type"] === "todo_list" && Array.isArray(parsed["todos"])) {
|
|
312
|
-
return parsed["todos"];
|
|
313
|
-
}
|
|
314
|
-
} catch {
|
|
315
|
-
}
|
|
516
|
+
async sendUpdate(update) {
|
|
517
|
+
if (this.ctx.messageRewriter) {
|
|
518
|
+
return this.ctx.messageRewriter.interceptUpdate(update);
|
|
316
519
|
}
|
|
317
|
-
return
|
|
520
|
+
return this.ctx.sendUpdate(update);
|
|
318
521
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const fileName = typeof display["fileName"] === "string" ? display["fileName"] : "the edited file";
|
|
325
|
-
const fileDiffLength = typeof display["fileDiffLength"] === "number" ? ` Original fileDiff length: ${display["fileDiffLength"]} chars.` : "";
|
|
326
|
-
if (display["fileDiffTruncated"] === true) {
|
|
327
|
-
return `Full diff omitted from saved session history for ${fileName}.${fileDiffLength}`;
|
|
522
|
+
/**
|
|
523
|
+
* Gets the session ID.
|
|
524
|
+
*/
|
|
525
|
+
get sessionId() {
|
|
526
|
+
return this.ctx.sessionId;
|
|
328
527
|
}
|
|
329
|
-
return `Saved session preview only for ${fileName}; full original and new file contents are unavailable.`;
|
|
330
|
-
}
|
|
331
|
-
__name(buildTruncatedDiffPreviewText, "buildTruncatedDiffPreviewText");
|
|
332
|
-
|
|
333
|
-
// packages/cli/src/acp-integration/session/emitters/ToolCallEmitter.ts
|
|
334
|
-
var KIND_MAP = {
|
|
335
|
-
["read" /* Read */]: "read",
|
|
336
|
-
["edit" /* Edit */]: "edit",
|
|
337
|
-
["delete" /* Delete */]: "delete",
|
|
338
|
-
["move" /* Move */]: "move",
|
|
339
|
-
["search" /* Search */]: "search",
|
|
340
|
-
["execute" /* Execute */]: "execute",
|
|
341
|
-
["think" /* Think */]: "think",
|
|
342
|
-
["fetch" /* Fetch */]: "fetch",
|
|
343
|
-
// ACP defines no 'agent' ToolKind (verified through @agentclientprotocol/sdk
|
|
344
|
-
// 0.25.1). The daemon's ClientSideConnection Zod-validates every session/update
|
|
345
|
-
// and session/request_permission from the `qwen --acp` child before fanning out
|
|
346
|
-
// to SSE clients, so emitting 'agent' is rejected at that hop and the frame is
|
|
347
|
-
// dropped. Map the internal Kind.Agent to 'other' on the wire to stay
|
|
348
|
-
// protocol-valid; dedicated agent UI is delivered out-of-band (via _meta.toolName)
|
|
349
|
-
// in a follow-up rather than via a kind the protocol can't carry.
|
|
350
|
-
["agent" /* Agent */]: "other",
|
|
351
|
-
["other" /* Other */]: "other"
|
|
352
528
|
};
|
|
353
|
-
|
|
529
|
+
|
|
530
|
+
// packages/cli/src/acp-integration/session/emitters/MessageEmitter.ts
|
|
531
|
+
var MessageEmitter = class extends BaseEmitter {
|
|
354
532
|
static {
|
|
355
|
-
__name(this, "
|
|
356
|
-
}
|
|
357
|
-
planEmitter;
|
|
358
|
-
constructor(ctx) {
|
|
359
|
-
super(ctx);
|
|
360
|
-
this.planEmitter = new PlanEmitter(ctx);
|
|
533
|
+
__name(this, "MessageEmitter");
|
|
361
534
|
}
|
|
362
535
|
/**
|
|
363
|
-
* Emits a
|
|
536
|
+
* Emits a StopHookLoop event when Stop hooks create a loop.
|
|
537
|
+
* This informs the client that Stop hooks have been executed multiple times.
|
|
364
538
|
*
|
|
365
|
-
* @param
|
|
366
|
-
* @
|
|
539
|
+
* @param iterationCount - The current iteration count
|
|
540
|
+
* @param reasons - Array of reasons from each Stop hook execution
|
|
541
|
+
* @param stopHookCount - Number of Stop hooks that were executed
|
|
367
542
|
*/
|
|
368
|
-
async
|
|
369
|
-
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
const { title, locations, kind } = this.resolveToolMetadata(
|
|
373
|
-
params.toolName,
|
|
374
|
-
params.args
|
|
375
|
-
);
|
|
376
|
-
const provenance = _ToolCallEmitter.resolveToolProvenance(
|
|
377
|
-
params.toolName,
|
|
378
|
-
params.subagentMeta
|
|
379
|
-
);
|
|
543
|
+
async emitStopHookLoop(iterationCount, reasons, stopHookCount) {
|
|
544
|
+
const activeGoal = getActiveGoal(this.sessionId);
|
|
380
545
|
await this.sendUpdate({
|
|
381
|
-
sessionUpdate: "
|
|
382
|
-
|
|
383
|
-
status: params.status || "pending",
|
|
384
|
-
title,
|
|
385
|
-
content: [],
|
|
386
|
-
locations,
|
|
387
|
-
kind,
|
|
388
|
-
rawInput: params.args ?? {},
|
|
546
|
+
sessionUpdate: "agent_message_chunk",
|
|
547
|
+
content: { type: "text", text: "" },
|
|
389
548
|
_meta: {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
549
|
+
stopHookLoop: {
|
|
550
|
+
iterationCount,
|
|
551
|
+
reasons,
|
|
552
|
+
stopHookCount,
|
|
553
|
+
...activeGoal ? {
|
|
554
|
+
goal: {
|
|
555
|
+
condition: activeGoal.condition,
|
|
556
|
+
iterations: activeGoal.iterations,
|
|
557
|
+
setAt: activeGoal.setAt,
|
|
558
|
+
lastReason: activeGoal.lastReason
|
|
559
|
+
}
|
|
560
|
+
} : {}
|
|
396
561
|
}
|
|
397
562
|
}
|
|
398
563
|
});
|
|
399
|
-
return true;
|
|
400
564
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
async emitResult(params) {
|
|
408
|
-
if (this.isTodoWriteTool(params.toolName)) {
|
|
409
|
-
const todos = this.planEmitter.extractTodos(
|
|
410
|
-
params.resultDisplay,
|
|
411
|
-
params.args
|
|
412
|
-
);
|
|
413
|
-
if (todos && todos.length > 0) {
|
|
414
|
-
await this.planEmitter.emitPlan(todos);
|
|
415
|
-
} else if (params.args && Array.isArray(params.args["todos"])) {
|
|
416
|
-
await this.planEmitter.emitPlan([]);
|
|
565
|
+
async emitGoalTerminal(event) {
|
|
566
|
+
await this.sendUpdate({
|
|
567
|
+
sessionUpdate: "agent_message_chunk",
|
|
568
|
+
content: { type: "text", text: "" },
|
|
569
|
+
_meta: {
|
|
570
|
+
goalTerminal: event
|
|
417
571
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
} else if (params.error) {
|
|
425
|
-
contentArray = [
|
|
426
|
-
{
|
|
427
|
-
type: "content",
|
|
428
|
-
content: { type: "text", text: params.error.message }
|
|
429
|
-
}
|
|
430
|
-
];
|
|
431
|
-
} else {
|
|
432
|
-
contentArray = this.transformPartsToToolCallContent(params.message);
|
|
433
|
-
}
|
|
434
|
-
const provenance = _ToolCallEmitter.resolveToolProvenance(
|
|
435
|
-
params.toolName,
|
|
436
|
-
params.subagentMeta
|
|
437
|
-
);
|
|
438
|
-
const update = {
|
|
439
|
-
sessionUpdate: "tool_call_update",
|
|
440
|
-
toolCallId: params.callId,
|
|
441
|
-
status: params.success ? "completed" : "failed",
|
|
442
|
-
content: contentArray,
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
async emitGoalStatus(status) {
|
|
575
|
+
await this.sendUpdate({
|
|
576
|
+
sessionUpdate: "agent_message_chunk",
|
|
577
|
+
content: { type: "text", text: "" },
|
|
443
578
|
_meta: {
|
|
444
|
-
|
|
445
|
-
...params.subagentMeta,
|
|
446
|
-
provenance: provenance.provenance,
|
|
447
|
-
...provenance.serverId ? { serverId: provenance.serverId } : {},
|
|
448
|
-
...BaseEmitter.toEpochMs(params.timestamp) != null && {
|
|
449
|
-
timestamp: BaseEmitter.toEpochMs(params.timestamp)
|
|
450
|
-
},
|
|
451
|
-
...params.artifacts && params.artifacts.length > 0 ? { artifacts: params.artifacts } : {}
|
|
579
|
+
goalStatus: status
|
|
452
580
|
}
|
|
453
|
-
};
|
|
454
|
-
if (params.resultDisplay !== void 0 && !this.isTruncatedSessionDiffDisplay(params.resultDisplay)) {
|
|
455
|
-
update["rawOutput"] = params.resultDisplay;
|
|
456
|
-
}
|
|
457
|
-
await this.sendUpdate(update);
|
|
581
|
+
});
|
|
458
582
|
}
|
|
459
583
|
/**
|
|
460
|
-
* Emits a
|
|
461
|
-
* Use this for explicit error handling when not using emitResult.
|
|
584
|
+
* Emits a user message chunk.
|
|
462
585
|
*
|
|
463
|
-
* @param
|
|
464
|
-
* @param
|
|
465
|
-
* @param error - The error that occurred
|
|
466
|
-
* @param subagentMeta - Optional subagent metadata
|
|
586
|
+
* @param text - The user message text content
|
|
587
|
+
* @param timestamp - Optional server-side timestamp (ISO string or ms) for message ordering
|
|
467
588
|
*/
|
|
468
|
-
async
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
589
|
+
async emitUserMessage(text, timestamp, options = {}) {
|
|
590
|
+
const epochMs = BaseEmitter.toEpochMs(timestamp);
|
|
591
|
+
const _meta = {
|
|
592
|
+
...epochMs != null ? { timestamp: epochMs } : {},
|
|
593
|
+
...options.source ? { source: options.source } : {}
|
|
594
|
+
};
|
|
473
595
|
await this.sendUpdate({
|
|
474
|
-
sessionUpdate: "
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
content: [
|
|
478
|
-
{ type: "content", content: { type: "text", text: error.message } }
|
|
479
|
-
],
|
|
480
|
-
_meta: {
|
|
481
|
-
toolName,
|
|
482
|
-
...subagentMeta,
|
|
483
|
-
provenance: provenance.provenance,
|
|
484
|
-
...provenance.serverId ? { serverId: provenance.serverId } : {}
|
|
485
|
-
}
|
|
596
|
+
sessionUpdate: "user_message_chunk",
|
|
597
|
+
content: { type: "text", text },
|
|
598
|
+
...Object.keys(_meta).length > 0 ? { _meta } : {}
|
|
486
599
|
});
|
|
487
600
|
}
|
|
488
601
|
/**
|
|
489
|
-
*
|
|
490
|
-
* The SDK reads `_meta.
|
|
491
|
-
* provenance` + `_meta.serverId` to render builtin / MCP-server-badge /
|
|
492
|
-
* subagent-block differently. Without this stamping, the SDK falls
|
|
493
|
-
* back to string-matching the toolName which can't reliably
|
|
494
|
-
* distinguish builtin from subagent.
|
|
495
|
-
*
|
|
496
|
-
* Resolution rules:
|
|
497
|
-
* - `subagentMeta` present → `'subagent'` (a Task tool / Codex
|
|
498
|
-
* subagent / etc. wrapping its own tool calls)
|
|
499
|
-
* - toolName matches `mcp__<server>__<tool>` → `'mcp'` with
|
|
500
|
-
* `serverId: <server>`. Naming convention from
|
|
501
|
-
* `packages/core/src/tools/mcp-tool.ts` in the
|
|
502
|
-
* `@qwen-code/qwen-code-core` package — mirrors the SDK's same
|
|
503
|
-
* heuristic fallback so SDK consumers stay consistent with
|
|
504
|
-
* daemon classification.
|
|
505
|
-
* - everything else → `'builtin'`
|
|
602
|
+
* Emits an agent thought chunk.
|
|
506
603
|
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
604
|
+
* @param text - The thought text content
|
|
605
|
+
* @param timestamp - Optional server-side timestamp (ISO string or ms) for message ordering
|
|
509
606
|
*/
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return { provenance: "builtin" };
|
|
607
|
+
async emitAgentThought(text, timestamp, subagentMeta) {
|
|
608
|
+
const _meta = this.buildChunkMeta(
|
|
609
|
+
BaseEmitter.toEpochMs(timestamp),
|
|
610
|
+
subagentMeta
|
|
611
|
+
);
|
|
612
|
+
await this.sendUpdate({
|
|
613
|
+
sessionUpdate: "agent_thought_chunk",
|
|
614
|
+
content: { type: "text", text },
|
|
615
|
+
..._meta ? { _meta } : {}
|
|
616
|
+
});
|
|
521
617
|
}
|
|
522
|
-
// ==================== Public Utilities ====================
|
|
523
618
|
/**
|
|
524
|
-
*
|
|
525
|
-
*
|
|
619
|
+
* Emits an agent message chunk.
|
|
620
|
+
*
|
|
621
|
+
* @param text - The agent message text content
|
|
622
|
+
* @param timestamp - Optional server-side timestamp (ISO string or ms) for message ordering
|
|
526
623
|
*/
|
|
527
|
-
|
|
528
|
-
|
|
624
|
+
async emitAgentMessage(text, timestamp, subagentMeta) {
|
|
625
|
+
const _meta = this.buildChunkMeta(
|
|
626
|
+
BaseEmitter.toEpochMs(timestamp),
|
|
627
|
+
subagentMeta
|
|
628
|
+
);
|
|
629
|
+
await this.sendUpdate({
|
|
630
|
+
sessionUpdate: "agent_message_chunk",
|
|
631
|
+
content: { type: "text", text },
|
|
632
|
+
..._meta ? { _meta } : {}
|
|
633
|
+
});
|
|
529
634
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
635
|
+
async emitSlashCommandOutput(text, timestamp) {
|
|
636
|
+
const epochMs = BaseEmitter.toEpochMs(timestamp);
|
|
637
|
+
await this.sendUpdate({
|
|
638
|
+
sessionUpdate: "agent_message_chunk",
|
|
639
|
+
content: { type: "text", text },
|
|
640
|
+
_meta: {
|
|
641
|
+
source: "slash_command",
|
|
642
|
+
...epochMs != null ? { timestamp: epochMs } : {}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
535
645
|
}
|
|
536
646
|
/**
|
|
537
|
-
*
|
|
647
|
+
* Emits usage metadata.
|
|
538
648
|
*/
|
|
539
|
-
|
|
540
|
-
|
|
649
|
+
async emitUsageMetadata(usageMetadata, text = "", durationMs, subagentMeta) {
|
|
650
|
+
const usage = {
|
|
651
|
+
inputTokens: usageMetadata.promptTokenCount ?? 0,
|
|
652
|
+
outputTokens: usageMetadata.candidatesTokenCount ?? 0,
|
|
653
|
+
totalTokens: usageMetadata.totalTokenCount ?? 0,
|
|
654
|
+
thoughtTokens: usageMetadata.thoughtsTokenCount,
|
|
655
|
+
cachedReadTokens: usageMetadata.cachedContentTokenCount
|
|
656
|
+
};
|
|
657
|
+
const cumulative = this.ctx.cumulativeUsage;
|
|
658
|
+
if (cumulative) {
|
|
659
|
+
const addFinite = /* @__PURE__ */ __name((total, value) => typeof value === "number" && Number.isFinite(value) ? total + value : total, "addFinite");
|
|
660
|
+
cumulative.promptTokens = addFinite(
|
|
661
|
+
cumulative.promptTokens,
|
|
662
|
+
usage.inputTokens
|
|
663
|
+
);
|
|
664
|
+
cumulative.candidateTokens = addFinite(
|
|
665
|
+
cumulative.candidateTokens,
|
|
666
|
+
usage.outputTokens
|
|
667
|
+
);
|
|
668
|
+
cumulative.cachedTokens = addFinite(
|
|
669
|
+
cumulative.cachedTokens,
|
|
670
|
+
usage.cachedReadTokens
|
|
671
|
+
);
|
|
672
|
+
cumulative.apiTimeMs = addFinite(cumulative.apiTimeMs, durationMs);
|
|
673
|
+
}
|
|
674
|
+
let meta;
|
|
675
|
+
if (typeof durationMs === "number") {
|
|
676
|
+
const activity = apiActivityTracker.drain();
|
|
677
|
+
meta = {
|
|
678
|
+
usage,
|
|
679
|
+
durationMs,
|
|
680
|
+
...activity.errors > 0 ? { apiErrors: activity.errors } : {},
|
|
681
|
+
...activity.retries > 0 ? { apiRetries: activity.retries } : {},
|
|
682
|
+
...subagentMeta
|
|
683
|
+
};
|
|
684
|
+
} else {
|
|
685
|
+
meta = { usage, ...subagentMeta };
|
|
686
|
+
}
|
|
687
|
+
await this.sendUpdate({
|
|
688
|
+
sessionUpdate: "agent_message_chunk",
|
|
689
|
+
content: { type: "text", text },
|
|
690
|
+
_meta: meta
|
|
691
|
+
});
|
|
541
692
|
}
|
|
542
693
|
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
694
|
+
* Emits a message chunk based on role and thought flag.
|
|
695
|
+
* This is the unified method that handles all message types.
|
|
545
696
|
*
|
|
546
|
-
* @param
|
|
547
|
-
* @param
|
|
697
|
+
* @param text - The message text content
|
|
698
|
+
* @param role - Whether this is a user or assistant message
|
|
699
|
+
* @param isThought - Whether this is an assistant thought (only applies to assistant role)
|
|
700
|
+
* @param timestamp - Optional server-side timestamp (ISO string or ms) for message ordering
|
|
548
701
|
*/
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
let title = tool?.displayName ?? toolName;
|
|
553
|
-
let locations = [];
|
|
554
|
-
let kind = "other";
|
|
555
|
-
if (tool && args) {
|
|
556
|
-
try {
|
|
557
|
-
const invocation = tool.build(args);
|
|
558
|
-
title = `${title}: ${invocation.getDescription()}`;
|
|
559
|
-
locations = invocation.toolLocations().map((loc) => ({
|
|
560
|
-
path: loc.path,
|
|
561
|
-
line: loc.line ?? null
|
|
562
|
-
}));
|
|
563
|
-
kind = this.mapToolKind(tool.kind, toolName);
|
|
564
|
-
} catch {
|
|
565
|
-
if (typeof args["description"] === "string") {
|
|
566
|
-
title = `${title}: ${args["description"]}`;
|
|
567
|
-
}
|
|
568
|
-
if (tool.kind) {
|
|
569
|
-
kind = this.mapToolKind(tool.kind, toolName);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
702
|
+
async emitMessage(text, role, isThought = false, timestamp, subagentMeta) {
|
|
703
|
+
if (role === "user") {
|
|
704
|
+
return this.emitUserMessage(text, timestamp);
|
|
572
705
|
}
|
|
573
|
-
return
|
|
706
|
+
return isThought ? this.emitAgentThought(text, timestamp, subagentMeta) : this.emitAgentMessage(text, timestamp, subagentMeta);
|
|
707
|
+
}
|
|
708
|
+
buildChunkMeta(epochMs, subagentMeta) {
|
|
709
|
+
const meta = {
|
|
710
|
+
...subagentMeta?.parentToolCallId ? { parentToolCallId: subagentMeta.parentToolCallId } : {},
|
|
711
|
+
...subagentMeta?.subagentType ? { subagentType: subagentMeta.subagentType } : {},
|
|
712
|
+
...epochMs != null ? { timestamp: epochMs } : {}
|
|
713
|
+
};
|
|
714
|
+
return Object.keys(meta).length > 0 ? meta : void 0;
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
// packages/cli/src/acp-integration/session/emitters/PlanEmitter.ts
|
|
719
|
+
init_esbuild_shims();
|
|
720
|
+
var PlanEmitter = class extends BaseEmitter {
|
|
721
|
+
static {
|
|
722
|
+
__name(this, "PlanEmitter");
|
|
574
723
|
}
|
|
575
724
|
/**
|
|
576
|
-
*
|
|
725
|
+
* Emits a plan update with the given todo items.
|
|
577
726
|
*
|
|
578
|
-
* @param
|
|
579
|
-
* @param toolName - Optional tool name to handle special cases like exit_plan_mode
|
|
727
|
+
* @param todos - Array of todo items to send as plan entries
|
|
580
728
|
*/
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
729
|
+
async emitPlan(todos) {
|
|
730
|
+
const entries = todos.map((todo) => ({
|
|
731
|
+
content: todo.content,
|
|
732
|
+
priority: "medium",
|
|
733
|
+
// Default priority since todos don't have priority
|
|
734
|
+
status: todo.status
|
|
735
|
+
}));
|
|
736
|
+
const cumulative = this.ctx.cumulativeUsage;
|
|
737
|
+
await this.sendUpdate({
|
|
738
|
+
sessionUpdate: "plan",
|
|
739
|
+
entries,
|
|
740
|
+
...cumulative ? { _meta: { stats: { ...cumulative } } } : {}
|
|
741
|
+
});
|
|
586
742
|
}
|
|
587
|
-
// ==================== Private Helpers ====================
|
|
588
743
|
/**
|
|
589
|
-
* Extracts
|
|
590
|
-
*
|
|
744
|
+
* Extracts todos from tool result display or args.
|
|
745
|
+
* Tries multiple sources in priority order:
|
|
746
|
+
* 1. Result display object with type 'todo_list'
|
|
747
|
+
* 2. Result display as JSON string
|
|
748
|
+
* 3. Args with 'todos' array
|
|
749
|
+
*
|
|
750
|
+
* @param resultDisplay - The tool result display (object, string, or undefined)
|
|
751
|
+
* @param args - The tool call arguments (fallback source)
|
|
752
|
+
* @returns Array of todos if found, null otherwise
|
|
591
753
|
*/
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
return {
|
|
598
|
-
type: "content",
|
|
599
|
-
content: {
|
|
600
|
-
type: "text",
|
|
601
|
-
text: buildTruncatedDiffPreviewText(obj)
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
return {
|
|
606
|
-
type: "diff",
|
|
607
|
-
path: obj["fileName"],
|
|
608
|
-
oldText: obj["originalContent"] ?? "",
|
|
609
|
-
newText: obj["newContent"]
|
|
610
|
-
};
|
|
754
|
+
extractTodos(resultDisplay, args) {
|
|
755
|
+
const fromDisplay = this.extractFromResultDisplay(resultDisplay);
|
|
756
|
+
if (fromDisplay) return fromDisplay;
|
|
757
|
+
if (args && Array.isArray(args["todos"])) {
|
|
758
|
+
return args["todos"];
|
|
611
759
|
}
|
|
612
760
|
return null;
|
|
613
761
|
}
|
|
614
|
-
isTruncatedSessionDiffDisplay(resultDisplay) {
|
|
615
|
-
if (!resultDisplay || typeof resultDisplay !== "object") return false;
|
|
616
|
-
const obj = resultDisplay;
|
|
617
|
-
return obj["truncatedForSession"] === true && "fileName" in obj && "newContent" in obj;
|
|
618
|
-
}
|
|
619
762
|
/**
|
|
620
|
-
*
|
|
621
|
-
*
|
|
763
|
+
* Extracts todos from a result display value.
|
|
764
|
+
* Handles both object and JSON string formats.
|
|
622
765
|
*/
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
content: { type: "text", text: part.text }
|
|
630
|
-
});
|
|
766
|
+
extractFromResultDisplay(resultDisplay) {
|
|
767
|
+
if (!resultDisplay) return null;
|
|
768
|
+
if (typeof resultDisplay === "object") {
|
|
769
|
+
const obj = resultDisplay;
|
|
770
|
+
if (obj["type"] === "todo_list" && Array.isArray(obj["todos"])) {
|
|
771
|
+
return obj["todos"];
|
|
631
772
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
result.push({
|
|
639
|
-
type: "content",
|
|
640
|
-
content: { type: "text", text: responseText }
|
|
641
|
-
});
|
|
642
|
-
} catch {
|
|
773
|
+
}
|
|
774
|
+
if (typeof resultDisplay === "string") {
|
|
775
|
+
try {
|
|
776
|
+
const parsed = JSON.parse(resultDisplay);
|
|
777
|
+
if (parsed?.["type"] === "todo_list" && Array.isArray(parsed["todos"])) {
|
|
778
|
+
return parsed["todos"];
|
|
643
779
|
}
|
|
780
|
+
} catch {
|
|
644
781
|
}
|
|
645
782
|
}
|
|
646
|
-
return
|
|
783
|
+
return null;
|
|
647
784
|
}
|
|
648
785
|
};
|
|
649
786
|
|
|
650
|
-
// packages/cli/src/
|
|
787
|
+
// packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
|
|
651
788
|
init_esbuild_shims();
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const resultCallId = record.toolCallResult?.callId;
|
|
658
|
-
if (typeof resultCallId === "string" && resultCallId.length > 0) {
|
|
659
|
-
return resultCallId;
|
|
660
|
-
}
|
|
661
|
-
return extractFunctionResponseId(record);
|
|
789
|
+
|
|
790
|
+
// packages/cli/src/acp-integration/session/types.ts
|
|
791
|
+
init_esbuild_shims();
|
|
792
|
+
function hasFullSessionContext(context) {
|
|
793
|
+
return "config" in context;
|
|
662
794
|
}
|
|
663
|
-
__name(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
795
|
+
__name(hasFullSessionContext, "hasFullSessionContext");
|
|
796
|
+
|
|
797
|
+
// packages/cli/src/utils/truncatedDiffPreview.ts
|
|
798
|
+
init_esbuild_shims();
|
|
799
|
+
function buildTruncatedDiffPreviewText(display) {
|
|
800
|
+
const fileName = typeof display["fileName"] === "string" ? display["fileName"] : "the edited file";
|
|
801
|
+
const fileDiffLength = typeof display["fileDiffLength"] === "number" ? ` Original fileDiff length: ${display["fileDiffLength"]} chars.` : "";
|
|
802
|
+
if (display["fileDiffTruncated"] === true) {
|
|
803
|
+
return `Full diff omitted from saved session history for ${fileName}.${fileDiffLength}`;
|
|
673
804
|
}
|
|
674
|
-
return
|
|
805
|
+
return `Saved session preview only for ${fileName}; full original and new file contents are unavailable.`;
|
|
675
806
|
}
|
|
676
|
-
__name(
|
|
807
|
+
__name(buildTruncatedDiffPreviewText, "buildTruncatedDiffPreviewText");
|
|
677
808
|
|
|
678
|
-
// packages/cli/src/acp-integration/session/
|
|
679
|
-
var
|
|
680
|
-
|
|
809
|
+
// packages/cli/src/acp-integration/session/emitters/tool-call-emitter.ts
|
|
810
|
+
var KIND_MAP = {
|
|
811
|
+
["read" /* Read */]: "read",
|
|
812
|
+
["edit" /* Edit */]: "edit",
|
|
813
|
+
["delete" /* Delete */]: "delete",
|
|
814
|
+
["move" /* Move */]: "move",
|
|
815
|
+
["search" /* Search */]: "search",
|
|
816
|
+
["execute" /* Execute */]: "execute",
|
|
817
|
+
["think" /* Think */]: "think",
|
|
818
|
+
["fetch" /* Fetch */]: "fetch",
|
|
819
|
+
// ACP defines no 'agent' ToolKind (verified through @agentclientprotocol/sdk
|
|
820
|
+
// 0.25.1). The daemon's ClientSideConnection Zod-validates every session/update
|
|
821
|
+
// and session/request_permission from the `qwen --acp` child before fanning out
|
|
822
|
+
// to SSE clients, so emitting 'agent' is rejected at that hop and the frame is
|
|
823
|
+
// dropped. Map the internal Kind.Agent to 'other' on the wire to stay
|
|
824
|
+
// protocol-valid; dedicated agent UI is delivered out-of-band (via _meta.toolName)
|
|
825
|
+
// in a follow-up rather than via a kind the protocol can't carry.
|
|
826
|
+
["agent" /* Agent */]: "other",
|
|
827
|
+
["other" /* Other */]: "other"
|
|
828
|
+
};
|
|
829
|
+
var ToolCallEmitter = class _ToolCallEmitter extends BaseEmitter {
|
|
681
830
|
static {
|
|
682
|
-
__name(this, "
|
|
831
|
+
__name(this, "ToolCallEmitter");
|
|
683
832
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
toolCallEmitter;
|
|
687
|
-
pendingReplayToolCalls = /* @__PURE__ */ new Map();
|
|
833
|
+
planEmitter;
|
|
834
|
+
preparedCallIds = /* @__PURE__ */ new Set();
|
|
688
835
|
constructor(ctx) {
|
|
689
|
-
|
|
690
|
-
this.
|
|
691
|
-
this.toolCallEmitter = new ToolCallEmitter(ctx);
|
|
836
|
+
super(ctx);
|
|
837
|
+
this.planEmitter = new PlanEmitter(ctx);
|
|
692
838
|
}
|
|
693
839
|
/**
|
|
694
|
-
*
|
|
840
|
+
* Emits a tool call start event.
|
|
695
841
|
*
|
|
696
|
-
* @param
|
|
697
|
-
* @
|
|
698
|
-
* immediately before each gap's child record so the user sees that an
|
|
699
|
-
* earlier segment was lost rather than assuming the halves are contiguous.
|
|
842
|
+
* @param params - Tool call start parameters
|
|
843
|
+
* @returns true if event was emitted, false if skipped (e.g., TodoWriteTool)
|
|
700
844
|
*/
|
|
701
|
-
async
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
} finally {
|
|
705
|
-
this.pendingReplayToolCalls.clear();
|
|
706
|
-
this.setActiveRecordId(null);
|
|
845
|
+
async emitStart(params) {
|
|
846
|
+
if (this.isTodoWriteTool(params.toolName)) {
|
|
847
|
+
return false;
|
|
707
848
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
this.pendingReplayToolCalls.clear();
|
|
711
|
-
for (const pending of options.pendingToolCalls ?? []) {
|
|
712
|
-
this.pendingReplayToolCalls.set(pending.callId, pending);
|
|
849
|
+
if (params.phase === "preparing" && this.preparedCallIds.has(params.callId)) {
|
|
850
|
+
return false;
|
|
713
851
|
}
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
852
|
+
const { title, locations, kind } = this.resolveToolMetadata(
|
|
853
|
+
params.toolName,
|
|
854
|
+
params.args
|
|
855
|
+
);
|
|
856
|
+
const provenance = _ToolCallEmitter.resolveToolProvenance(
|
|
857
|
+
params.toolName,
|
|
858
|
+
params.subagentMeta
|
|
859
|
+
);
|
|
860
|
+
const updatesPreparedCall = params.phase !== "preparing" && this.preparedCallIds.delete(params.callId);
|
|
861
|
+
const update = {
|
|
862
|
+
toolCallId: params.callId,
|
|
863
|
+
status: params.status || "pending",
|
|
864
|
+
title,
|
|
865
|
+
content: [],
|
|
866
|
+
locations,
|
|
867
|
+
kind,
|
|
868
|
+
rawInput: params.args ?? {},
|
|
869
|
+
_meta: {
|
|
870
|
+
toolName: params.toolName,
|
|
871
|
+
...params.phase ? { phase: params.phase } : {},
|
|
872
|
+
...params.subagentMeta,
|
|
873
|
+
provenance: provenance.provenance,
|
|
874
|
+
...provenance.serverId ? { serverId: provenance.serverId } : {},
|
|
875
|
+
...BaseEmitter.toEpochMs(params.timestamp) != null && {
|
|
876
|
+
timestamp: BaseEmitter.toEpochMs(params.timestamp)
|
|
721
877
|
}
|
|
722
|
-
await this.replayRecord(record);
|
|
723
|
-
}
|
|
724
|
-
} catch (error) {
|
|
725
|
-
replayError = error;
|
|
726
|
-
}
|
|
727
|
-
let danglingError;
|
|
728
|
-
if (options.finalizeDangling === true) {
|
|
729
|
-
try {
|
|
730
|
-
await this.failDanglingToolCalls();
|
|
731
|
-
} catch (error) {
|
|
732
|
-
danglingError = error;
|
|
733
878
|
}
|
|
734
|
-
}
|
|
735
|
-
const state = {
|
|
736
|
-
pendingToolCalls: options.finalizeDangling === true ? [] : Array.from(this.pendingReplayToolCalls.values())
|
|
737
879
|
};
|
|
738
|
-
this.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
if (replayError) {
|
|
746
|
-
throw replayError;
|
|
747
|
-
}
|
|
748
|
-
if (danglingError) {
|
|
749
|
-
throw danglingError;
|
|
880
|
+
await this.sendUpdate(
|
|
881
|
+
updatesPreparedCall ? { sessionUpdate: "tool_call_update", ...update } : { sessionUpdate: "tool_call", ...update }
|
|
882
|
+
);
|
|
883
|
+
if (params.phase === "preparing") {
|
|
884
|
+
this.preparedCallIds.add(params.callId);
|
|
750
885
|
}
|
|
751
|
-
return
|
|
886
|
+
return true;
|
|
752
887
|
}
|
|
753
|
-
|
|
754
|
-
|
|
888
|
+
/**
|
|
889
|
+
* Emits a terminal frame when a prepared tool call is discarded before
|
|
890
|
+
* execution. TodoWrite remains represented exclusively by plan updates.
|
|
891
|
+
*
|
|
892
|
+
* @param callId - ID of the prepared tool call
|
|
893
|
+
* @param toolName - Name of the prepared tool
|
|
894
|
+
*/
|
|
895
|
+
async emitPreparationDiscarded(callId, toolName) {
|
|
896
|
+
if (this.isTodoWriteTool(toolName)) return;
|
|
897
|
+
this.preparedCallIds.delete(callId);
|
|
898
|
+
const provenance = _ToolCallEmitter.resolveToolProvenance(toolName);
|
|
899
|
+
await this.sendUpdate({
|
|
900
|
+
sessionUpdate: "tool_call_update",
|
|
901
|
+
toolCallId: callId,
|
|
902
|
+
status: "failed",
|
|
903
|
+
content: [],
|
|
904
|
+
_meta: {
|
|
905
|
+
toolName,
|
|
906
|
+
phase: "preparing",
|
|
907
|
+
preparationDiscarded: true,
|
|
908
|
+
provenance: provenance.provenance,
|
|
909
|
+
...provenance.serverId ? { serverId: provenance.serverId } : {}
|
|
910
|
+
}
|
|
911
|
+
});
|
|
755
912
|
}
|
|
756
913
|
/**
|
|
757
|
-
*
|
|
914
|
+
* Emits a tool call result event.
|
|
915
|
+
* Handles TodoWriteTool specially by routing to plan updates.
|
|
916
|
+
*
|
|
917
|
+
* @param params - Tool call result parameters
|
|
758
918
|
*/
|
|
759
|
-
async
|
|
760
|
-
this.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
record.timestamp,
|
|
770
|
-
record.subtype === "cron" ? { source: "cron" } : void 0
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
break;
|
|
774
|
-
}
|
|
775
|
-
if (record.subtype === "mid_turn_user_message") {
|
|
776
|
-
const displayText = record.systemPayload?.displayText;
|
|
777
|
-
if (displayText) {
|
|
778
|
-
await this.messageEmitter.emitUserMessage(
|
|
779
|
-
displayText,
|
|
780
|
-
record.timestamp
|
|
781
|
-
);
|
|
782
|
-
} else if (record.message) {
|
|
783
|
-
await this.replayContent(
|
|
784
|
-
record.message,
|
|
785
|
-
"user",
|
|
786
|
-
record.timestamp,
|
|
787
|
-
record.uuid
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
break;
|
|
791
|
-
}
|
|
792
|
-
if (record.message) {
|
|
793
|
-
await this.replayContent(
|
|
794
|
-
record.message,
|
|
795
|
-
"user",
|
|
796
|
-
record.timestamp,
|
|
797
|
-
record.uuid
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
break;
|
|
801
|
-
case "assistant":
|
|
802
|
-
if (record.message) {
|
|
803
|
-
await this.replayContent(
|
|
804
|
-
record.message,
|
|
805
|
-
"assistant",
|
|
806
|
-
record.timestamp,
|
|
807
|
-
record.uuid
|
|
808
|
-
);
|
|
809
|
-
}
|
|
810
|
-
if (record.usageMetadata) {
|
|
811
|
-
await this.replayUsageMetadata(record.usageMetadata);
|
|
812
|
-
}
|
|
813
|
-
break;
|
|
814
|
-
case "tool_result":
|
|
815
|
-
await this.replayToolResult(record);
|
|
816
|
-
break;
|
|
817
|
-
case "system":
|
|
818
|
-
if (record.subtype === "slash_command") {
|
|
819
|
-
await this.replaySlashCommandResult(record);
|
|
820
|
-
}
|
|
821
|
-
break;
|
|
822
|
-
default:
|
|
823
|
-
break;
|
|
919
|
+
async emitResult(params) {
|
|
920
|
+
if (this.isTodoWriteTool(params.toolName)) {
|
|
921
|
+
const todos = this.planEmitter.extractTodos(
|
|
922
|
+
params.resultDisplay,
|
|
923
|
+
params.args
|
|
924
|
+
);
|
|
925
|
+
if (todos && todos.length > 0) {
|
|
926
|
+
await this.planEmitter.emitPlan(todos);
|
|
927
|
+
} else if (params.args && Array.isArray(params.args["todos"])) {
|
|
928
|
+
await this.planEmitter.emitPlan([]);
|
|
824
929
|
}
|
|
825
|
-
|
|
826
|
-
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
this.preparedCallIds.delete(params.callId);
|
|
933
|
+
let contentArray = [];
|
|
934
|
+
const diffContent = this.extractDiffContent(params.resultDisplay);
|
|
935
|
+
if (diffContent) {
|
|
936
|
+
contentArray = [diffContent];
|
|
937
|
+
} else if (params.error) {
|
|
938
|
+
contentArray = [
|
|
939
|
+
{
|
|
940
|
+
type: "content",
|
|
941
|
+
content: { type: "text", text: params.error.message }
|
|
942
|
+
}
|
|
943
|
+
];
|
|
944
|
+
} else {
|
|
945
|
+
contentArray = this.transformPartsToToolCallContent(params.message);
|
|
946
|
+
}
|
|
947
|
+
if (isVisionBridgeNoticeDisplay(params.resultDisplay)) {
|
|
948
|
+
contentArray.unshift({
|
|
949
|
+
type: "content",
|
|
950
|
+
content: {
|
|
951
|
+
type: "text",
|
|
952
|
+
text: sanitizeTerminalText(
|
|
953
|
+
formatVisionBridgeNoticeDisplay(params.resultDisplay)
|
|
954
|
+
)
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
const provenance = _ToolCallEmitter.resolveToolProvenance(
|
|
959
|
+
params.toolName,
|
|
960
|
+
params.subagentMeta
|
|
961
|
+
);
|
|
962
|
+
const update = {
|
|
963
|
+
sessionUpdate: "tool_call_update",
|
|
964
|
+
toolCallId: params.callId,
|
|
965
|
+
status: params.success ? "completed" : "failed",
|
|
966
|
+
content: contentArray,
|
|
967
|
+
_meta: {
|
|
968
|
+
toolName: params.toolName,
|
|
969
|
+
...params.subagentMeta,
|
|
970
|
+
provenance: provenance.provenance,
|
|
971
|
+
...provenance.serverId ? { serverId: provenance.serverId } : {},
|
|
972
|
+
...BaseEmitter.toEpochMs(params.timestamp) != null && {
|
|
973
|
+
timestamp: BaseEmitter.toEpochMs(params.timestamp)
|
|
974
|
+
},
|
|
975
|
+
...params.artifacts && params.artifacts.length > 0 ? { artifacts: params.artifacts } : {}
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
if (params.resultDisplay !== void 0 && !this.isTruncatedSessionDiffDisplay(params.resultDisplay)) {
|
|
979
|
+
update["rawOutput"] = params.resultDisplay;
|
|
827
980
|
}
|
|
981
|
+
await this.sendUpdate(update);
|
|
828
982
|
}
|
|
829
983
|
/**
|
|
830
|
-
* Emits a
|
|
831
|
-
*
|
|
832
|
-
*
|
|
833
|
-
*
|
|
834
|
-
*
|
|
835
|
-
*
|
|
984
|
+
* Emits a tool call error event.
|
|
985
|
+
* Use this for explicit error handling when not using emitResult.
|
|
986
|
+
*
|
|
987
|
+
* @param callId - The tool call ID
|
|
988
|
+
* @param toolName - The tool name
|
|
989
|
+
* @param error - The error that occurred
|
|
990
|
+
* @param subagentMeta - Optional subagent metadata
|
|
836
991
|
*/
|
|
837
|
-
async
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
992
|
+
async emitError(callId, toolName, error, subagentMeta) {
|
|
993
|
+
this.preparedCallIds.delete(callId);
|
|
994
|
+
const provenance = _ToolCallEmitter.resolveToolProvenance(
|
|
995
|
+
toolName,
|
|
996
|
+
subagentMeta
|
|
841
997
|
);
|
|
998
|
+
await this.sendUpdate({
|
|
999
|
+
sessionUpdate: "tool_call_update",
|
|
1000
|
+
toolCallId: callId,
|
|
1001
|
+
status: "failed",
|
|
1002
|
+
content: [
|
|
1003
|
+
{ type: "content", content: { type: "text", text: error.message } }
|
|
1004
|
+
],
|
|
1005
|
+
_meta: {
|
|
1006
|
+
toolName,
|
|
1007
|
+
...subagentMeta,
|
|
1008
|
+
provenance: provenance.provenance,
|
|
1009
|
+
...provenance.serverId ? { serverId: provenance.serverId } : {}
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
842
1012
|
}
|
|
843
1013
|
/**
|
|
844
|
-
*
|
|
845
|
-
*
|
|
1014
|
+
* Resolve a tool's provenance for UI dispatch on tool_call events.
|
|
1015
|
+
* The SDK reads `_meta.
|
|
1016
|
+
* provenance` + `_meta.serverId` to render builtin / MCP-server-badge /
|
|
1017
|
+
* subagent-block differently. Without this stamping, the SDK falls
|
|
1018
|
+
* back to string-matching the toolName which can't reliably
|
|
1019
|
+
* distinguish builtin from subagent.
|
|
846
1020
|
*
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
1021
|
+
* Resolution rules:
|
|
1022
|
+
* - `subagentMeta` present → `'subagent'` (a Task tool / Codex
|
|
1023
|
+
* subagent / etc. wrapping its own tool calls)
|
|
1024
|
+
* - toolName matches `mcp__<server>__<tool>` → `'mcp'` with
|
|
1025
|
+
* `serverId: <server>`. Naming convention from
|
|
1026
|
+
* `packages/core/src/tools/mcp-tool.ts` in the
|
|
1027
|
+
* `@qwen-code/qwen-code-core` package — mirrors the SDK's same
|
|
1028
|
+
* heuristic fallback so SDK consumers stay consistent with
|
|
1029
|
+
* daemon classification.
|
|
1030
|
+
* - everything else → `'builtin'`
|
|
1031
|
+
*
|
|
1032
|
+
* Static + pure so it can be unit-tested without an emitter
|
|
1033
|
+
* instance. Exported via `ToolCallEmitter.resolveToolProvenance`.
|
|
850
1034
|
*/
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
timestamp
|
|
860
|
-
);
|
|
861
|
-
}
|
|
862
|
-
if ("functionCall" in part && part.functionCall) {
|
|
863
|
-
const functionName = part.functionCall.name ?? "";
|
|
864
|
-
const sourceCallId = part.functionCall.id;
|
|
865
|
-
const callId = sourceCallId ?? `${functionName}-${Date.now()}`;
|
|
866
|
-
const emitted = await this.toolCallEmitter.emitStart({
|
|
867
|
-
toolName: functionName,
|
|
868
|
-
callId,
|
|
869
|
-
args: part.functionCall.args,
|
|
870
|
-
status: "in_progress",
|
|
871
|
-
timestamp
|
|
872
|
-
});
|
|
873
|
-
if (emitted && role === "assistant" && recordId && sourceCallId) {
|
|
874
|
-
this.pendingReplayToolCalls.set(callId, {
|
|
875
|
-
callId,
|
|
876
|
-
toolName: functionName,
|
|
877
|
-
timestamp,
|
|
878
|
-
recordId
|
|
879
|
-
});
|
|
880
|
-
}
|
|
1035
|
+
static resolveToolProvenance(toolName, subagentMeta) {
|
|
1036
|
+
if (subagentMeta !== void 0) {
|
|
1037
|
+
return { provenance: "subagent" };
|
|
1038
|
+
}
|
|
1039
|
+
if (toolName.startsWith("mcp__")) {
|
|
1040
|
+
const parts = toolName.split("__");
|
|
1041
|
+
if (parts.length >= 3 && parts[1] && parts[1].length > 0) {
|
|
1042
|
+
return { provenance: "mcp", serverId: parts[1] };
|
|
881
1043
|
}
|
|
882
1044
|
}
|
|
1045
|
+
return { provenance: "builtin" };
|
|
883
1046
|
}
|
|
1047
|
+
// ==================== Public Utilities ====================
|
|
884
1048
|
/**
|
|
885
|
-
*
|
|
886
|
-
*
|
|
1049
|
+
* Checks if a tool name is the TodoWriteTool.
|
|
1050
|
+
* Exposed for external use in components that need to check this.
|
|
887
1051
|
*/
|
|
888
|
-
|
|
889
|
-
|
|
1052
|
+
isTodoWriteTool(toolName) {
|
|
1053
|
+
return toolName === ToolNames.TODO_WRITE;
|
|
890
1054
|
}
|
|
891
1055
|
/**
|
|
892
|
-
*
|
|
1056
|
+
* Checks if a tool name is the ExitPlanModeTool.
|
|
893
1057
|
*/
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
const result = record.toolCallResult;
|
|
899
|
-
const callId = getToolResultCallId(record);
|
|
900
|
-
this.pendingReplayToolCalls.delete(callId);
|
|
901
|
-
const toolName = this.extractToolNameFromRecord(record);
|
|
902
|
-
await this.toolCallEmitter.emitResult({
|
|
903
|
-
toolName,
|
|
904
|
-
callId,
|
|
905
|
-
success: !result?.error,
|
|
906
|
-
message: record.message.parts,
|
|
907
|
-
resultDisplay: result?.resultDisplay,
|
|
908
|
-
artifacts: result?.artifacts,
|
|
909
|
-
// For TodoWriteTool fallback, try to extract args from the record
|
|
910
|
-
// Note: args aren't stored in tool_result records by default
|
|
911
|
-
args: void 0,
|
|
912
|
-
timestamp: record.timestamp
|
|
913
|
-
});
|
|
914
|
-
const { resultDisplay } = result ?? {};
|
|
915
|
-
if (!!resultDisplay && typeof resultDisplay === "object" && "type" in resultDisplay && resultDisplay.type === "task_execution") {
|
|
916
|
-
await this.emitTaskUsageFromResultDisplay(
|
|
917
|
-
resultDisplay
|
|
918
|
-
);
|
|
919
|
-
}
|
|
1058
|
+
isExitPlanModeTool(toolName) {
|
|
1059
|
+
return toolName === ToolNames.EXIT_PLAN_MODE;
|
|
920
1060
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1061
|
+
/**
|
|
1062
|
+
* Checks if a tool name is the EnterPlanModeTool.
|
|
1063
|
+
*/
|
|
1064
|
+
isEnterPlanModeTool(toolName) {
|
|
1065
|
+
return toolName === ToolNames.ENTER_PLAN_MODE;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Resolves tool metadata from the registry.
|
|
1069
|
+
* Falls back to defaults if tool not found or build fails.
|
|
1070
|
+
*
|
|
1071
|
+
* @param toolName - Name of the tool
|
|
1072
|
+
* @param args - Tool call arguments (used to build invocation)
|
|
1073
|
+
*/
|
|
1074
|
+
resolveToolMetadata(toolName, args) {
|
|
1075
|
+
if (!hasFullSessionContext(this.ctx)) {
|
|
1076
|
+
const description = typeof args?.["description"] === "string" ? args["description"].trim() : "";
|
|
1077
|
+
return {
|
|
1078
|
+
title: description ? `${toolName}: ${description}` : toolName,
|
|
1079
|
+
locations: [],
|
|
1080
|
+
kind: "other"
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
const toolRegistry = this.ctx.config.getToolRegistry();
|
|
1084
|
+
const tool = toolRegistry.getTool(toolName);
|
|
1085
|
+
let title = tool?.displayName ?? toolName;
|
|
1086
|
+
let locations = [];
|
|
1087
|
+
let kind = "other";
|
|
1088
|
+
if (tool && args) {
|
|
925
1089
|
try {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1090
|
+
const invocation = tool.build(args);
|
|
1091
|
+
title = `${title}: ${invocation.getDescription()}`;
|
|
1092
|
+
locations = invocation.toolLocations().map((loc) => ({
|
|
1093
|
+
path: loc.path,
|
|
1094
|
+
line: loc.line ?? null
|
|
1095
|
+
}));
|
|
1096
|
+
kind = this.mapToolKind(tool.kind, toolName);
|
|
1097
|
+
} catch {
|
|
1098
|
+
if (typeof args["description"] === "string") {
|
|
1099
|
+
title = `${title}: ${args["description"]}`;
|
|
1100
|
+
}
|
|
1101
|
+
if (tool.kind) {
|
|
1102
|
+
kind = this.mapToolKind(tool.kind, toolName);
|
|
1103
|
+
}
|
|
938
1104
|
}
|
|
939
1105
|
}
|
|
940
|
-
|
|
941
|
-
throw firstError;
|
|
942
|
-
}
|
|
1106
|
+
return { title, locations, kind };
|
|
943
1107
|
}
|
|
944
1108
|
/**
|
|
945
|
-
*
|
|
1109
|
+
* Maps core Tool Kind enum to ACP ToolKind string literals.
|
|
1110
|
+
*
|
|
1111
|
+
* @param kind - The core Kind enum value
|
|
1112
|
+
* @param toolName - Optional tool name to handle special cases like exit_plan_mode
|
|
946
1113
|
*/
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
const usageMetadata = {};
|
|
953
|
-
if (Number.isFinite(summary.inputTokens)) {
|
|
954
|
-
usageMetadata.promptTokenCount = summary.inputTokens;
|
|
955
|
-
}
|
|
956
|
-
if (Number.isFinite(summary.outputTokens)) {
|
|
957
|
-
usageMetadata.candidatesTokenCount = summary.outputTokens;
|
|
958
|
-
}
|
|
959
|
-
if (Number.isFinite(summary.thoughtTokens)) {
|
|
960
|
-
usageMetadata.thoughtsTokenCount = summary.thoughtTokens;
|
|
961
|
-
}
|
|
962
|
-
if (Number.isFinite(summary.cachedTokens)) {
|
|
963
|
-
usageMetadata.cachedContentTokenCount = summary.cachedTokens;
|
|
964
|
-
}
|
|
965
|
-
if (Number.isFinite(summary.totalTokens)) {
|
|
966
|
-
usageMetadata.totalTokenCount = summary.totalTokens;
|
|
967
|
-
}
|
|
968
|
-
if (Object.keys(usageMetadata).length > 0) {
|
|
969
|
-
await this.messageEmitter.emitUsageMetadata(usageMetadata);
|
|
1114
|
+
mapToolKind(kind, toolName) {
|
|
1115
|
+
if (toolName && (this.isExitPlanModeTool(toolName) || this.isEnterPlanModeTool(toolName))) {
|
|
1116
|
+
return "switch_mode";
|
|
970
1117
|
}
|
|
1118
|
+
return KIND_MAP[kind] ?? "other";
|
|
971
1119
|
}
|
|
1120
|
+
// ==================== Private Helpers ====================
|
|
972
1121
|
/**
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
* structure (user → agent) on session resume without polluting model context.
|
|
1122
|
+
* Extracts diff content from resultDisplay if it's a diff type (edit tool result).
|
|
1123
|
+
* Returns null if not a diff.
|
|
976
1124
|
*/
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1125
|
+
extractDiffContent(resultDisplay) {
|
|
1126
|
+
if (!resultDisplay || typeof resultDisplay !== "object") return null;
|
|
1127
|
+
const obj = resultDisplay;
|
|
1128
|
+
if ("fileName" in obj && "newContent" in obj) {
|
|
1129
|
+
if (this.isTruncatedSessionDiffDisplay(resultDisplay)) {
|
|
1130
|
+
return {
|
|
1131
|
+
type: "content",
|
|
1132
|
+
content: {
|
|
1133
|
+
type: "text",
|
|
1134
|
+
text: buildTruncatedDiffPreviewText(obj)
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
989
1137
|
}
|
|
1138
|
+
return {
|
|
1139
|
+
type: "diff",
|
|
1140
|
+
path: obj["fileName"],
|
|
1141
|
+
oldText: obj["originalContent"] ?? "",
|
|
1142
|
+
newText: obj["newContent"]
|
|
1143
|
+
};
|
|
990
1144
|
}
|
|
1145
|
+
return null;
|
|
1146
|
+
}
|
|
1147
|
+
isTruncatedSessionDiffDisplay(resultDisplay) {
|
|
1148
|
+
if (!resultDisplay || typeof resultDisplay !== "object") return false;
|
|
1149
|
+
const obj = resultDisplay;
|
|
1150
|
+
return obj["truncatedForSession"] === true && "fileName" in obj && "newContent" in obj;
|
|
991
1151
|
}
|
|
992
1152
|
/**
|
|
993
|
-
*
|
|
1153
|
+
* Transforms Part[] to ToolCallContent[].
|
|
1154
|
+
* Extracts text from functionResponse parts and text parts.
|
|
994
1155
|
*/
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1156
|
+
transformPartsToToolCallContent(parts) {
|
|
1157
|
+
const result = [];
|
|
1158
|
+
for (const part of parts) {
|
|
1159
|
+
if ("text" in part && part.text) {
|
|
1160
|
+
result.push({
|
|
1161
|
+
type: "content",
|
|
1162
|
+
content: { type: "text", text: part.text }
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
if ("functionResponse" in part && part.functionResponse) {
|
|
1166
|
+
try {
|
|
1167
|
+
const resp = part.functionResponse.response;
|
|
1168
|
+
const outputField = resp["output"];
|
|
1169
|
+
const errorField = resp["error"];
|
|
1170
|
+
const responseText = typeof outputField === "string" ? outputField : typeof errorField === "string" ? errorField : JSON.stringify(resp);
|
|
1171
|
+
result.push({
|
|
1172
|
+
type: "content",
|
|
1173
|
+
content: { type: "text", text: responseText }
|
|
1174
|
+
});
|
|
1175
|
+
} catch {
|
|
1000
1176
|
}
|
|
1001
1177
|
}
|
|
1002
1178
|
}
|
|
1003
|
-
return
|
|
1004
|
-
}
|
|
1005
|
-
setActiveRecordId(recordId, timestamp) {
|
|
1006
|
-
const context = this.ctx;
|
|
1007
|
-
if (typeof context.setActiveRecordId === "function") {
|
|
1008
|
-
context.setActiveRecordId(recordId, timestamp);
|
|
1009
|
-
}
|
|
1179
|
+
return result;
|
|
1010
1180
|
}
|
|
1011
1181
|
};
|
|
1012
1182
|
|
|
1013
|
-
// packages/cli/src/
|
|
1183
|
+
// packages/cli/src/acp-integration/session/history-replayer.ts
|
|
1014
1184
|
init_esbuild_shims();
|
|
1015
|
-
var import_undici2 = __toESM(require_undici(), 1);
|
|
1016
|
-
import { promises as fsp } from "node:fs";
|
|
1017
|
-
import * as path from "node:path";
|
|
1018
1185
|
|
|
1019
|
-
// packages/cli/src/utils/
|
|
1186
|
+
// packages/cli/src/utils/chat-record-tool-call-id.ts
|
|
1020
1187
|
init_esbuild_shims();
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
var debugLogger = createDebugLogger("GIT");
|
|
1024
|
-
async function runGit(args, opts = {}) {
|
|
1025
|
-
return await new Promise((resolve2, reject) => {
|
|
1026
|
-
childProcess.execFile(
|
|
1027
|
-
"git",
|
|
1028
|
-
args,
|
|
1029
|
-
{
|
|
1030
|
-
encoding: "utf-8",
|
|
1031
|
-
...opts.cwd ? { cwd: opts.cwd } : {}
|
|
1032
|
-
},
|
|
1033
|
-
(err, stdout) => {
|
|
1034
|
-
if (err) {
|
|
1035
|
-
reject(err);
|
|
1036
|
-
return;
|
|
1037
|
-
}
|
|
1038
|
-
resolve2(String(stdout ?? "").trim());
|
|
1039
|
-
}
|
|
1040
|
-
);
|
|
1041
|
-
});
|
|
1188
|
+
function getToolResultCallId(record) {
|
|
1189
|
+
return getExplicitToolResultCallId(record) ?? record.uuid;
|
|
1042
1190
|
}
|
|
1043
|
-
__name(
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
return
|
|
1048
|
-
const remoteUrl = line.trim().split(/\s+/)[1];
|
|
1049
|
-
return remoteUrl ? isGitHubRemoteUrl(remoteUrl) : false;
|
|
1050
|
-
});
|
|
1051
|
-
} catch (_error) {
|
|
1052
|
-
debugLogger.debug(`Failed to get git remote:`, _error);
|
|
1053
|
-
return false;
|
|
1054
|
-
}
|
|
1055
|
-
}, "isGitHubRepositoryAsync");
|
|
1056
|
-
function isGitHubRemoteUrl(remoteUrl) {
|
|
1057
|
-
if (remoteUrl.startsWith("git@github.com:")) {
|
|
1058
|
-
return true;
|
|
1059
|
-
}
|
|
1060
|
-
if (remoteUrl.startsWith("git@")) {
|
|
1061
|
-
return false;
|
|
1062
|
-
}
|
|
1063
|
-
try {
|
|
1064
|
-
return new URL(remoteUrl).hostname === "github.com";
|
|
1065
|
-
} catch {
|
|
1066
|
-
return false;
|
|
1191
|
+
__name(getToolResultCallId, "getToolResultCallId");
|
|
1192
|
+
function getExplicitToolResultCallId(record) {
|
|
1193
|
+
const resultCallId = record.toolCallResult?.callId;
|
|
1194
|
+
if (typeof resultCallId === "string" && resultCallId.length > 0) {
|
|
1195
|
+
return resultCallId;
|
|
1067
1196
|
}
|
|
1197
|
+
return extractFunctionResponseId(record);
|
|
1068
1198
|
}
|
|
1069
|
-
__name(
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
throw new Error(`Git repo returned empty value`);
|
|
1199
|
+
__name(getExplicitToolResultCallId, "getExplicitToolResultCallId");
|
|
1200
|
+
function extractFunctionResponseId(record) {
|
|
1201
|
+
if (!record.message?.parts) {
|
|
1202
|
+
return void 0;
|
|
1074
1203
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
const controller = new AbortController();
|
|
1080
|
-
const endpoint = `https://api.github.com/repos/QwenLM/qwen-code-action/releases/latest`;
|
|
1081
|
-
const response = await fetch(endpoint, {
|
|
1082
|
-
method: "GET",
|
|
1083
|
-
headers: {
|
|
1084
|
-
Accept: "application/vnd.github+json",
|
|
1085
|
-
"Content-Type": "application/json",
|
|
1086
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
1087
|
-
},
|
|
1088
|
-
dispatcher: proxy ? new import_undici.ProxyAgent(proxy) : void 0,
|
|
1089
|
-
signal: AbortSignal.any([AbortSignal.timeout(3e4), controller.signal])
|
|
1090
|
-
});
|
|
1091
|
-
if (!response.ok) {
|
|
1092
|
-
throw new Error(
|
|
1093
|
-
`Invalid response code: ${response.status} - ${response.statusText}`
|
|
1094
|
-
);
|
|
1095
|
-
}
|
|
1096
|
-
const releaseTag = (await response.json()).tag_name;
|
|
1097
|
-
if (!releaseTag) {
|
|
1098
|
-
throw new Error(`Response did not include tag_name field`);
|
|
1204
|
+
for (const part of record.message.parts) {
|
|
1205
|
+
const id = "functionResponse" in part ? part.functionResponse?.id : void 0;
|
|
1206
|
+
if (typeof id === "string" && id.length > 0) {
|
|
1207
|
+
return id;
|
|
1099
1208
|
}
|
|
1100
|
-
return releaseTag;
|
|
1101
|
-
} catch (_error) {
|
|
1102
|
-
debugLogger.debug(
|
|
1103
|
-
`Failed to determine latest qwen-code-action release:`,
|
|
1104
|
-
_error
|
|
1105
|
-
);
|
|
1106
|
-
throw new Error(
|
|
1107
|
-
`Unable to determine the latest qwen-code-action release on GitHub.`
|
|
1108
|
-
);
|
|
1109
|
-
}
|
|
1110
|
-
}, "getLatestGitHubRelease");
|
|
1111
|
-
async function getGitHubRepoInfoAsync(opts = {}) {
|
|
1112
|
-
return parseGitHubRepoInfo(
|
|
1113
|
-
await runGit(["remote", "get-url", "origin"], opts)
|
|
1114
|
-
);
|
|
1115
|
-
}
|
|
1116
|
-
__name(getGitHubRepoInfoAsync, "getGitHubRepoInfoAsync");
|
|
1117
|
-
function parseGitHubRepoInfo(remoteUrl) {
|
|
1118
|
-
let urlToParse = remoteUrl;
|
|
1119
|
-
if (remoteUrl.startsWith("git@github.com:")) {
|
|
1120
|
-
urlToParse = remoteUrl.replace("git@github.com:", "");
|
|
1121
|
-
} else if (remoteUrl.startsWith("git@")) {
|
|
1122
|
-
throw new Error(
|
|
1123
|
-
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
1124
|
-
);
|
|
1125
1209
|
}
|
|
1126
|
-
|
|
1127
|
-
try {
|
|
1128
|
-
parsedUrl = new URL(urlToParse, "https://github.com");
|
|
1129
|
-
} catch {
|
|
1130
|
-
throw new Error(
|
|
1131
|
-
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
1132
|
-
);
|
|
1133
|
-
}
|
|
1134
|
-
if (parsedUrl.hostname !== "github.com") {
|
|
1135
|
-
throw new Error(
|
|
1136
|
-
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
1137
|
-
);
|
|
1138
|
-
}
|
|
1139
|
-
const parts = parsedUrl.pathname.split("/").filter((part) => part !== "");
|
|
1140
|
-
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
1141
|
-
throw new Error(
|
|
1142
|
-
`Owner & repo could not be extracted from remote URL: ${remoteUrl}`
|
|
1143
|
-
);
|
|
1144
|
-
}
|
|
1145
|
-
return { owner: parts[0], repo: parts[1].replace(/\.git$/, "") };
|
|
1210
|
+
return void 0;
|
|
1146
1211
|
}
|
|
1147
|
-
__name(
|
|
1212
|
+
__name(extractFunctionResponseId, "extractFunctionResponseId");
|
|
1148
1213
|
|
|
1149
|
-
// packages/cli/src/
|
|
1150
|
-
var
|
|
1151
|
-
var
|
|
1152
|
-
"qwen-dispatch/qwen-dispatch.yml",
|
|
1153
|
-
"qwen-assistant/qwen-invoke.yml",
|
|
1154
|
-
"issue-triage/qwen-triage.yml",
|
|
1155
|
-
"issue-triage/qwen-scheduled-triage.yml",
|
|
1156
|
-
"pr-review/qwen-review.yml"
|
|
1157
|
-
];
|
|
1158
|
-
var GITIGNORE_ENTRIES = [".qwen/", "gha-creds-*.json"];
|
|
1159
|
-
var MAX_WORKFLOW_DOWNLOAD_BYTES = 5 * 1024 * 1024;
|
|
1160
|
-
var SetupGithubError = class extends Error {
|
|
1214
|
+
// packages/cli/src/acp-integration/session/history-replayer.ts
|
|
1215
|
+
var MISSING_TOOL_RESULT_MESSAGE = "Tool result missing from saved history; the previous run likely ended before this tool completed.";
|
|
1216
|
+
var HistoryReplayer = class {
|
|
1161
1217
|
static {
|
|
1162
|
-
__name(this, "
|
|
1218
|
+
__name(this, "HistoryReplayer");
|
|
1163
1219
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
constructor(
|
|
1169
|
-
|
|
1170
|
-
this.
|
|
1171
|
-
this.
|
|
1172
|
-
this.status = status;
|
|
1173
|
-
this.partial = partialResult !== void 0;
|
|
1174
|
-
this.partialResult = partialResult;
|
|
1220
|
+
ctx;
|
|
1221
|
+
messageEmitter;
|
|
1222
|
+
toolCallEmitter;
|
|
1223
|
+
pendingReplayToolCalls = /* @__PURE__ */ new Map();
|
|
1224
|
+
constructor(ctx) {
|
|
1225
|
+
this.ctx = ctx;
|
|
1226
|
+
this.messageEmitter = new MessageEmitter(ctx);
|
|
1227
|
+
this.toolCallEmitter = new ToolCallEmitter(ctx);
|
|
1175
1228
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1229
|
+
/**
|
|
1230
|
+
* Replays all chat records from a loaded session.
|
|
1231
|
+
*
|
|
1232
|
+
* @param records - Array of chat records to replay
|
|
1233
|
+
* @param gaps - Optional detected history gaps; a visible notice is emitted
|
|
1234
|
+
* immediately before each gap's child record so the user sees that an
|
|
1235
|
+
* earlier segment was lost rather than assuming the halves are contiguous.
|
|
1236
|
+
*/
|
|
1237
|
+
async replay(records, gaps) {
|
|
1238
|
+
try {
|
|
1239
|
+
await this.replayPage(records, { finalizeDangling: true, gaps });
|
|
1240
|
+
} finally {
|
|
1241
|
+
this.pendingReplayToolCalls.clear();
|
|
1242
|
+
this.setActiveRecordId(null);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
async replayPage(records, options = {}) {
|
|
1246
|
+
this.pendingReplayToolCalls.clear();
|
|
1247
|
+
for (const pending of options.pendingToolCalls ?? []) {
|
|
1248
|
+
this.pendingReplayToolCalls.set(pending.callId, pending);
|
|
1249
|
+
}
|
|
1250
|
+
const gapByChildUuid = indexGapsByChild(options.gaps);
|
|
1251
|
+
let replayError;
|
|
1191
1252
|
try {
|
|
1192
|
-
|
|
1253
|
+
for (const record of records) {
|
|
1254
|
+
const gap = gapByChildUuid.get(record.uuid);
|
|
1255
|
+
if (gap) {
|
|
1256
|
+
await this.emitHistoryGapNotice(gap, record.timestamp);
|
|
1257
|
+
}
|
|
1258
|
+
await this.replayRecord(record);
|
|
1259
|
+
}
|
|
1193
1260
|
} catch (error) {
|
|
1194
|
-
|
|
1195
|
-
|
|
1261
|
+
replayError = error;
|
|
1262
|
+
}
|
|
1263
|
+
let danglingError;
|
|
1264
|
+
if (options.finalizeDangling === true) {
|
|
1265
|
+
try {
|
|
1266
|
+
await this.failDanglingToolCalls();
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
danglingError = error;
|
|
1196
1269
|
}
|
|
1197
|
-
throw error;
|
|
1198
1270
|
}
|
|
1271
|
+
const state = {
|
|
1272
|
+
pendingToolCalls: options.finalizeDangling === true ? [] : Array.from(this.pendingReplayToolCalls.values())
|
|
1273
|
+
};
|
|
1274
|
+
this.setActiveRecordId(null);
|
|
1275
|
+
if (replayError && danglingError) {
|
|
1276
|
+
throw new AggregateError(
|
|
1277
|
+
[replayError, danglingError],
|
|
1278
|
+
"Replay and dangling-cleanup both failed"
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
if (replayError) {
|
|
1282
|
+
throw replayError;
|
|
1283
|
+
}
|
|
1284
|
+
if (danglingError) {
|
|
1285
|
+
throw danglingError;
|
|
1286
|
+
}
|
|
1287
|
+
return state;
|
|
1199
1288
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
const cwd = options.cwd ?? process.cwd();
|
|
1203
|
-
const fileOps = options.fileOps ?? nodeFileOps;
|
|
1204
|
-
if (!await isGitHubRepositoryAsync({ cwd })) {
|
|
1205
|
-
throw new SetupGithubError(
|
|
1206
|
-
"github_repository_not_found",
|
|
1207
|
-
"Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
|
|
1208
|
-
400
|
|
1209
|
-
);
|
|
1210
|
-
}
|
|
1211
|
-
let gitRepoRoot;
|
|
1212
|
-
try {
|
|
1213
|
-
gitRepoRoot = await getGitRepoRootAsync({ cwd });
|
|
1214
|
-
} catch (error) {
|
|
1215
|
-
debugLogger2.debug("Failed to get git repo root:", error);
|
|
1216
|
-
throw new SetupGithubError(
|
|
1217
|
-
"github_repository_not_found",
|
|
1218
|
-
"Unable to determine the GitHub repository. /setup-github must be run from a git repository.",
|
|
1219
|
-
400
|
|
1220
|
-
);
|
|
1289
|
+
getPendingToolCalls() {
|
|
1290
|
+
return Array.from(this.pendingReplayToolCalls.values());
|
|
1221
1291
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
"
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1292
|
+
/**
|
|
1293
|
+
* Replays a single chat record.
|
|
1294
|
+
*/
|
|
1295
|
+
async replayRecord(record) {
|
|
1296
|
+
this.setActiveRecordId(record.uuid, record.timestamp);
|
|
1297
|
+
try {
|
|
1298
|
+
switch (record.type) {
|
|
1299
|
+
case "user":
|
|
1300
|
+
if (record.subtype === "notification" || record.subtype === "cron") {
|
|
1301
|
+
const displayText = record.systemPayload?.displayText;
|
|
1302
|
+
if (displayText) {
|
|
1303
|
+
await this.messageEmitter.emitUserMessage(
|
|
1304
|
+
displayText,
|
|
1305
|
+
record.timestamp,
|
|
1306
|
+
record.subtype === "cron" ? { source: "cron" } : void 0
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
if (record.subtype === "mid_turn_user_message") {
|
|
1312
|
+
const displayText = record.systemPayload?.displayText;
|
|
1313
|
+
if (displayText) {
|
|
1314
|
+
await this.messageEmitter.emitUserMessage(
|
|
1315
|
+
displayText,
|
|
1316
|
+
record.timestamp
|
|
1317
|
+
);
|
|
1318
|
+
} else if (record.message) {
|
|
1319
|
+
await this.replayContent(
|
|
1320
|
+
record.message,
|
|
1321
|
+
"user",
|
|
1322
|
+
record.timestamp,
|
|
1323
|
+
record.uuid
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
if (record.message) {
|
|
1329
|
+
await this.replayContent(
|
|
1330
|
+
record.message,
|
|
1331
|
+
"user",
|
|
1332
|
+
record.timestamp,
|
|
1333
|
+
record.uuid
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
break;
|
|
1337
|
+
case "assistant":
|
|
1338
|
+
if (record.message) {
|
|
1339
|
+
await this.replayContent(
|
|
1340
|
+
record.message,
|
|
1341
|
+
"assistant",
|
|
1342
|
+
record.timestamp,
|
|
1343
|
+
record.uuid
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
if (record.usageMetadata) {
|
|
1347
|
+
await this.replayUsageMetadata(record.usageMetadata);
|
|
1348
|
+
}
|
|
1349
|
+
break;
|
|
1350
|
+
case "tool_result":
|
|
1351
|
+
await this.replayToolResult(record);
|
|
1352
|
+
break;
|
|
1353
|
+
case "system":
|
|
1354
|
+
if (record.subtype === "slash_command") {
|
|
1355
|
+
await this.replaySlashCommandResult(record);
|
|
1356
|
+
}
|
|
1357
|
+
break;
|
|
1358
|
+
default:
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1361
|
+
} finally {
|
|
1362
|
+
this.setActiveRecordId(null);
|
|
1233
1363
|
}
|
|
1234
1364
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
throw new SetupGithubError(
|
|
1248
|
-
"github_release_lookup_failed",
|
|
1249
|
-
"Unable to determine the latest qwen-code-action release on GitHub.",
|
|
1250
|
-
502
|
|
1365
|
+
/**
|
|
1366
|
+
* Emits a visible notice marking a break in the persisted history chain: an
|
|
1367
|
+
* earlier segment was physically lost (storage interruption) and could not be
|
|
1368
|
+
* recovered, so the surviving turns below must not be read as contiguous with
|
|
1369
|
+
* whatever came before the gap. Uses the agent message channel — the same one
|
|
1370
|
+
* used for other system notices (see MessageEmitter.emitStopHookLoop) — so no
|
|
1371
|
+
* new session-update kind is needed.
|
|
1372
|
+
*/
|
|
1373
|
+
async emitHistoryGapNotice(gap, timestamp) {
|
|
1374
|
+
await this.messageEmitter.emitAgentMessage(
|
|
1375
|
+
formatHistoryGapNotice(gap),
|
|
1376
|
+
timestamp
|
|
1251
1377
|
);
|
|
1252
1378
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Replays content from a message (user or assistant).
|
|
1381
|
+
* Handles text parts, thought parts, and function calls.
|
|
1382
|
+
*
|
|
1383
|
+
* @param content - The content to replay
|
|
1384
|
+
* @param role - The role (user or assistant)
|
|
1385
|
+
* @param timestamp - Optional server-side timestamp from the JSONL record
|
|
1386
|
+
*/
|
|
1387
|
+
async replayContent(content, role, timestamp, recordId) {
|
|
1388
|
+
for (const part of content.parts ?? []) {
|
|
1389
|
+
if ("text" in part && part.text) {
|
|
1390
|
+
const isThought = part.thought ?? false;
|
|
1391
|
+
await this.messageEmitter.emitMessage(
|
|
1392
|
+
part.text,
|
|
1393
|
+
role,
|
|
1394
|
+
isThought,
|
|
1395
|
+
timestamp
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
if ("functionCall" in part && part.functionCall) {
|
|
1399
|
+
const functionName = part.functionCall.name ?? "";
|
|
1400
|
+
const sourceCallId = part.functionCall.id;
|
|
1401
|
+
const callId = sourceCallId ?? `${functionName}-${Date.now()}`;
|
|
1402
|
+
const emitted = await this.toolCallEmitter.emitStart({
|
|
1403
|
+
toolName: functionName,
|
|
1404
|
+
callId,
|
|
1405
|
+
args: part.functionCall.args,
|
|
1406
|
+
status: "in_progress",
|
|
1407
|
+
timestamp
|
|
1408
|
+
});
|
|
1409
|
+
if (emitted && role === "assistant" && recordId && sourceCallId) {
|
|
1410
|
+
this.pendingReplayToolCalls.set(callId, {
|
|
1411
|
+
callId,
|
|
1412
|
+
toolName: functionName,
|
|
1413
|
+
timestamp,
|
|
1414
|
+
recordId
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1275
1419
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1420
|
+
/**
|
|
1421
|
+
* Replays usage metadata.
|
|
1422
|
+
* @param usageMetadata - The usage metadata to replay
|
|
1423
|
+
*/
|
|
1424
|
+
async replayUsageMetadata(usageMetadata) {
|
|
1425
|
+
await this.messageEmitter.emitUsageMetadata(usageMetadata);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Replays a tool result record.
|
|
1429
|
+
*/
|
|
1430
|
+
async replayToolResult(record) {
|
|
1431
|
+
if (!record.message?.parts) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
const result = record.toolCallResult;
|
|
1435
|
+
const callId = getToolResultCallId(record);
|
|
1436
|
+
this.pendingReplayToolCalls.delete(callId);
|
|
1437
|
+
const toolName = this.extractToolNameFromRecord(record);
|
|
1438
|
+
await this.toolCallEmitter.emitResult({
|
|
1439
|
+
toolName,
|
|
1440
|
+
callId,
|
|
1441
|
+
success: !result?.error,
|
|
1442
|
+
message: record.message.parts,
|
|
1443
|
+
resultDisplay: result?.resultDisplay,
|
|
1444
|
+
artifacts: result?.artifacts,
|
|
1445
|
+
// For TodoWriteTool fallback, try to extract args from the record
|
|
1446
|
+
// Note: args aren't stored in tool_result records by default
|
|
1447
|
+
args: void 0,
|
|
1448
|
+
timestamp: record.timestamp
|
|
1449
|
+
});
|
|
1450
|
+
const { resultDisplay } = result ?? {};
|
|
1451
|
+
if (!!resultDisplay && typeof resultDisplay === "object" && "type" in resultDisplay && resultDisplay.type === "task_execution") {
|
|
1452
|
+
await this.emitTaskUsageFromResultDisplay(
|
|
1453
|
+
resultDisplay
|
|
1283
1454
|
);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
async failDanglingToolCalls() {
|
|
1458
|
+
let firstError;
|
|
1459
|
+
for (const pending of this.pendingReplayToolCalls.values()) {
|
|
1460
|
+
this.setActiveRecordId(pending.recordId, pending.timestamp);
|
|
1284
1461
|
try {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
path: relativePath,
|
|
1293
|
-
status: "written",
|
|
1294
|
-
sizeBytes: write.sizeBytes
|
|
1462
|
+
await this.toolCallEmitter.emitResult({
|
|
1463
|
+
toolName: pending.toolName,
|
|
1464
|
+
callId: pending.callId,
|
|
1465
|
+
success: false,
|
|
1466
|
+
message: [],
|
|
1467
|
+
error: new Error(MISSING_TOOL_RESULT_MESSAGE),
|
|
1468
|
+
timestamp: pending.timestamp
|
|
1295
1469
|
});
|
|
1296
1470
|
} catch (error) {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
path: relativePath,
|
|
1301
|
-
status: "failed",
|
|
1302
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1303
|
-
});
|
|
1304
|
-
throw new SetupGithubError(
|
|
1305
|
-
"github_workflow_write_failed",
|
|
1306
|
-
`Unable to write ${relativePath}.`,
|
|
1307
|
-
500,
|
|
1308
|
-
result
|
|
1309
|
-
);
|
|
1471
|
+
firstError ??= error;
|
|
1472
|
+
} finally {
|
|
1473
|
+
this.setActiveRecordId(null);
|
|
1310
1474
|
}
|
|
1311
1475
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
"github_workflow_write_failed",
|
|
1316
|
-
"Unable to create .github/workflows.",
|
|
1317
|
-
500,
|
|
1318
|
-
result
|
|
1319
|
-
);
|
|
1476
|
+
if (firstError) {
|
|
1477
|
+
throw firstError;
|
|
1478
|
+
}
|
|
1320
1479
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
async
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
".gitignore"
|
|
1329
|
-
);
|
|
1330
|
-
if (existingContent === void 0) {
|
|
1331
|
-
const content = GITIGNORE_ENTRIES.join("\n") + "\n";
|
|
1332
|
-
await fileOps.writeTextFile(gitRepoRoot, ".gitignore", content);
|
|
1333
|
-
return {
|
|
1334
|
-
path: ".gitignore",
|
|
1335
|
-
status: "created",
|
|
1336
|
-
added: [...GITIGNORE_ENTRIES]
|
|
1337
|
-
};
|
|
1480
|
+
/**
|
|
1481
|
+
* Emits token usage from a AgentResultDisplay execution summary, if present.
|
|
1482
|
+
*/
|
|
1483
|
+
async emitTaskUsageFromResultDisplay(resultDisplay) {
|
|
1484
|
+
const summary = resultDisplay.executionSummary;
|
|
1485
|
+
if (!summary) {
|
|
1486
|
+
return;
|
|
1338
1487
|
}
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
if (missingEntries.length === 0) {
|
|
1343
|
-
return { path: ".gitignore", status: "unchanged" };
|
|
1488
|
+
const usageMetadata = {};
|
|
1489
|
+
if (Number.isFinite(summary.inputTokens)) {
|
|
1490
|
+
usageMetadata.promptTokenCount = summary.inputTokens;
|
|
1344
1491
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
__name(updateGitignore, "updateGitignore");
|
|
1362
|
-
async function downloadWorkflows(options) {
|
|
1363
|
-
const internalAbort = new AbortController();
|
|
1364
|
-
try {
|
|
1365
|
-
const dispatcher = options.proxy ? new import_undici2.ProxyAgent(options.proxy) : void 0;
|
|
1366
|
-
return await Promise.all(
|
|
1367
|
-
GITHUB_WORKFLOW_PATHS.map(async (workflow) => {
|
|
1368
|
-
const endpoint = `https://raw.githubusercontent.com/QwenLM/qwen-code-action/refs/tags/${options.releaseTag}/examples/workflows/${workflow}`;
|
|
1369
|
-
const response = await options.fetchImpl(endpoint, {
|
|
1370
|
-
method: "GET",
|
|
1371
|
-
dispatcher,
|
|
1372
|
-
signal: AbortSignal.any([
|
|
1373
|
-
AbortSignal.timeout(3e4),
|
|
1374
|
-
internalAbort.signal,
|
|
1375
|
-
...options.abortSignal ? [options.abortSignal] : []
|
|
1376
|
-
])
|
|
1377
|
-
});
|
|
1378
|
-
if (!response.ok) {
|
|
1379
|
-
throw new Error(
|
|
1380
|
-
`Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`
|
|
1381
|
-
);
|
|
1382
|
-
}
|
|
1383
|
-
return {
|
|
1384
|
-
sourcePath: workflow,
|
|
1385
|
-
content: await readResponseTextWithLimit(response, workflow)
|
|
1386
|
-
};
|
|
1387
|
-
})
|
|
1388
|
-
);
|
|
1389
|
-
} catch (error) {
|
|
1390
|
-
internalAbort.abort();
|
|
1391
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1392
|
-
debugLogger2.debug("Failed to download qwen-code-action workflows:", error);
|
|
1393
|
-
throw new SetupGithubError(
|
|
1394
|
-
"github_workflow_download_failed",
|
|
1395
|
-
`Unable to download qwen-code-action workflows from GitHub. ${message}`,
|
|
1396
|
-
502
|
|
1397
|
-
);
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
__name(downloadWorkflows, "downloadWorkflows");
|
|
1401
|
-
async function readResponseTextWithLimit(response, sourcePath) {
|
|
1402
|
-
const contentLength = response.headers.get("content-length");
|
|
1403
|
-
if (contentLength !== null) {
|
|
1404
|
-
const parsedLength = Number(contentLength);
|
|
1405
|
-
if (Number.isFinite(parsedLength) && parsedLength > MAX_WORKFLOW_DOWNLOAD_BYTES) {
|
|
1406
|
-
throw new Error(
|
|
1407
|
-
`${sourcePath} exceeds download limit of ${MAX_WORKFLOW_DOWNLOAD_BYTES} bytes`
|
|
1408
|
-
);
|
|
1492
|
+
if (Number.isFinite(summary.outputTokens)) {
|
|
1493
|
+
usageMetadata.candidatesTokenCount = summary.outputTokens;
|
|
1494
|
+
}
|
|
1495
|
+
if (Number.isFinite(summary.thoughtTokens)) {
|
|
1496
|
+
usageMetadata.thoughtsTokenCount = summary.thoughtTokens;
|
|
1497
|
+
}
|
|
1498
|
+
if (Number.isFinite(summary.cachedTokens)) {
|
|
1499
|
+
usageMetadata.cachedContentTokenCount = summary.cachedTokens;
|
|
1500
|
+
}
|
|
1501
|
+
if (Number.isFinite(summary.totalTokens)) {
|
|
1502
|
+
usageMetadata.totalTokenCount = summary.totalTokens;
|
|
1503
|
+
}
|
|
1504
|
+
if (Object.keys(usageMetadata).length > 0) {
|
|
1505
|
+
await this.messageEmitter.emitUsageMetadata(usageMetadata);
|
|
1409
1506
|
}
|
|
1410
1507
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1508
|
+
/**
|
|
1509
|
+
* Replays a slash_command system record by re-emitting its output as an
|
|
1510
|
+
* agent message chunk. This allows Zed to reconstruct the correct turn
|
|
1511
|
+
* structure (user → agent) on session resume without polluting model context.
|
|
1512
|
+
*/
|
|
1513
|
+
async replaySlashCommandResult(record) {
|
|
1514
|
+
const payload = record.systemPayload;
|
|
1515
|
+
if (payload?.phase !== "result" || !payload.outputHistoryItems?.length) {
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
for (const item of payload.outputHistoryItems) {
|
|
1519
|
+
const text = typeof item["text"] === "string" ? item["text"] : "";
|
|
1520
|
+
if (text) {
|
|
1521
|
+
await this.messageEmitter.emitSlashCommandOutput(
|
|
1522
|
+
text.replace(/\n/g, " \n"),
|
|
1523
|
+
record.timestamp
|
|
1426
1524
|
);
|
|
1427
1525
|
}
|
|
1428
|
-
chunks.push(value);
|
|
1429
1526
|
}
|
|
1430
|
-
} finally {
|
|
1431
|
-
reader.releaseLock();
|
|
1432
|
-
}
|
|
1433
|
-
const body = new Uint8Array(totalBytes);
|
|
1434
|
-
let offset = 0;
|
|
1435
|
-
for (const chunk of chunks) {
|
|
1436
|
-
body.set(chunk, offset);
|
|
1437
|
-
offset += chunk.byteLength;
|
|
1438
1527
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1528
|
+
/**
|
|
1529
|
+
* Extracts tool name from a chat record's function response.
|
|
1530
|
+
*/
|
|
1531
|
+
extractToolNameFromRecord(record) {
|
|
1532
|
+
if (record.message?.parts) {
|
|
1533
|
+
for (const part of record.message.parts) {
|
|
1534
|
+
if ("functionResponse" in part && part.functionResponse?.name) {
|
|
1535
|
+
return part.functionResponse.name;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
return "";
|
|
1448
1540
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
} catch {
|
|
1455
|
-
return path.resolve(input);
|
|
1541
|
+
setActiveRecordId(recordId, timestamp) {
|
|
1542
|
+
const context = this.ctx;
|
|
1543
|
+
if (typeof context.setActiveRecordId === "function") {
|
|
1544
|
+
context.setActiveRecordId(recordId, timestamp);
|
|
1545
|
+
}
|
|
1456
1546
|
}
|
|
1457
|
-
}
|
|
1458
|
-
__name(realpathOrResolve, "realpathOrResolve");
|
|
1547
|
+
};
|
|
1459
1548
|
|
|
1460
1549
|
// packages/cli/src/ui/utils/export/collect.ts
|
|
1461
1550
|
init_esbuild_shims();
|
|
@@ -1646,7 +1735,7 @@ async function extractMetadata(conversation, config) {
|
|
|
1646
1735
|
const gitBranch = firstRecord?.gitBranch;
|
|
1647
1736
|
let gitRepo;
|
|
1648
1737
|
if (cwd) {
|
|
1649
|
-
const { getGitRepoName } = await import("./src-
|
|
1738
|
+
const { getGitRepoName } = await import("./src-7FITDSVC.js");
|
|
1650
1739
|
gitRepo = getGitRepoName(cwd);
|
|
1651
1740
|
}
|
|
1652
1741
|
let model;
|
|
@@ -1961,7 +2050,19 @@ function buildToolCallMessageFromResult(record, config) {
|
|
|
1961
2050
|
const rawInput = normalizeRawInput(
|
|
1962
2051
|
functionCallArgs ?? toolCallResult?.args
|
|
1963
2052
|
);
|
|
1964
|
-
const
|
|
2053
|
+
const resultContent = extractDiffContent(toolCallResult?.resultDisplay) ?? transformPartsToToolCallContent(record.message?.parts ?? []);
|
|
2054
|
+
const content = isVisionBridgeNoticeDisplay(toolCallResult?.resultDisplay) ? [
|
|
2055
|
+
{
|
|
2056
|
+
type: "content",
|
|
2057
|
+
content: {
|
|
2058
|
+
type: "text",
|
|
2059
|
+
text: sanitizeTerminalText(
|
|
2060
|
+
formatVisionBridgeNoticeDisplay(toolCallResult.resultDisplay)
|
|
2061
|
+
)
|
|
2062
|
+
}
|
|
2063
|
+
},
|
|
2064
|
+
...resultContent
|
|
2065
|
+
] : resultContent;
|
|
1965
2066
|
return {
|
|
1966
2067
|
uuid: record.uuid,
|
|
1967
2068
|
parentUuid: record.parentUuid,
|
|
@@ -2491,7 +2592,7 @@ export {
|
|
|
2491
2592
|
};
|
|
2492
2593
|
/**
|
|
2493
2594
|
* @license
|
|
2494
|
-
* Copyright 2025
|
|
2595
|
+
* Copyright 2025 Google LLC
|
|
2495
2596
|
* SPDX-License-Identifier: Apache-2.0
|
|
2496
2597
|
*/
|
|
2497
2598
|
/**
|
|
@@ -2501,7 +2602,7 @@ export {
|
|
|
2501
2602
|
*/
|
|
2502
2603
|
/**
|
|
2503
2604
|
* @license
|
|
2504
|
-
* Copyright 2025
|
|
2605
|
+
* Copyright 2025 Qwen
|
|
2505
2606
|
* SPDX-License-Identifier: Apache-2.0
|
|
2506
2607
|
*/
|
|
2507
2608
|
/**
|